From 4da60774f30982800400881a05ce71a356dae6c7 Mon Sep 17 00:00:00 2001 From: Coleman Watts Date: Wed, 12 May 2021 14:19:03 -0400 Subject: [PATCH] Afform - improve drag-n-drop UI Fixes a number of issues with drag-n-drop on the Afform GUI palette & canvas. Forces panels to take up full vertical space so palette never scrolls offscreen. Compresses tabs above palette to save space. --- ext/afform/admin/ang/afGuiEditor.css | 75 ++++++++++++++++--- ext/afform/admin/ang/afGuiEditor.js | 4 +- .../ang/afGuiEditor/afGuiEditor.component.js | 54 ++++++++++++- .../ang/afGuiEditor/afGuiEditorCanvas.html | 2 + .../ang/afGuiEditor/afGuiEditorPalette.html | 25 ++++--- .../admin/ang/afGuiEditor/afGuiEntity.html | 12 +-- .../admin/ang/afGuiEditor/afGuiSearch.html | 12 +-- .../elements/afGuiContainer.component.js | 2 + 8 files changed, 149 insertions(+), 37 deletions(-) diff --git a/ext/afform/admin/ang/afGuiEditor.css b/ext/afform/admin/ang/afGuiEditor.css index 3667005a12..5025b6e280 100644 --- a/ext/afform/admin/ang/afGuiEditor.css +++ b/ext/afform/admin/ang/afGuiEditor.css @@ -1,14 +1,11 @@ #afGuiEditor #afGuiEditor-palette { margin-right: 5px; + height: 100%; } #afGuiEditor #afGuiEditor-canvas { margin-left: 5px; -} - -#afGuiEditor .panel-body { - padding: 5px 12px; - position: relative; + height: 100%; } #afGuiEditor fieldset legend { @@ -26,13 +23,39 @@ margin-bottom: 10px; } -#afGuiEditor #afGuiEditor-palette-tabs li { +#afGuiEditor .panel { + height: 100%; +} +#afGuiEditor .panel-heading { + height: 44px; + padding: 10px; +} +#afGuiEditor .panel-heading ul.nav-tabs { + border-bottom: 0 none; +} +#afGuiEditor .panel-heading ul.nav-tabs li { top: 1px; } - -#afGuiEditor #afGuiEditor-palette-tabs li > a { - padding: 10px 15px; +#afGuiEditor .panel-heading ul.nav-tabs li.fluid-width-tab { + white-space: nowrap; + overflow: hidden; +} +#afGuiEditor .panel-heading ul.nav-tabs li.active { + max-width: 50%; +} +#afGuiEditor .panel-heading ul.nav-tabs li > a { + padding: 5px 3px 5px 8px; + height: 33px; font-size: 12px; + margin: 0; +} + +#afGuiEditor .panel-body { + padding: 5px 12px; + position: relative; + height: calc(100% - 44px); + overflow-y: scroll; + overflow-x: hidden; } #afGuiEditor .af-gui-columns { @@ -49,7 +72,7 @@ } #afGuiEditor .crm-editable-enabled, -#afGuiEditor-palette-tabs > li > a > span { +#afGuiEditor .panel-heading ul.nav-tabs li > a > span { display: inline-block; padding: 0 4px !important; border: 2px solid transparent !important; @@ -112,7 +135,7 @@ left: 0; padding-left: 15px; } -#afGuiEditor:not(.af-gui-dragging) #afGuiEditor-canvas:hover .af-gui-bar { +#afGuiEditor:not(.af-gui-dragging *) #afGuiEditor-canvas:hover .af-gui-bar { opacity: 1; transition: opacity .2s; } @@ -122,6 +145,16 @@ transition: opacity .1s; } +/* Disable menu while dragging */ +body.af-gui-dragging #civicrm-menu { + pointer-events: none; +} +/* Disable scrollbars while dragging */ +body.af-gui-dragging { + overflow-x: hidden; + overflow-y: hidden; +} + #afGuiEditor .af-gui-bar .btn.active { background-color: #b3b3b3; } @@ -143,6 +176,8 @@ padding: 22px 3px 3px; min-height: 40px; display: block; + margin-bottom: 10px; + margin-top: 10px; } #afGuiEditor af-gui-markup, @@ -160,10 +195,12 @@ #afGuiEditor .af-gui-container-type-fieldset { box-shadow: 0 0 5px #bbbbbb; + margin-top: 20px; + margin-bottom: 20px; } #afGuiEditor .af-gui-container:hover, -#afGuiEditor.af-gui-dragging .af-gui-container { +.af-gui-dragging #afGuiEditor .af-gui-container { border: 2px dashed #757575; } #afGuiEditor .af-gui-container.af-gui-dragtarget { @@ -217,6 +254,20 @@ margin-top: 10px; } +#afGuiEditor .ui-sortable-helper { + height: 20px !important; + opacity: .5; + overflow: visible; +} +#afGuiEditor .ui-sortable-helper > * { + background-color: #d5d5d5; +} +#afGuiEditor .ui-sortable-helper .af-gui-palette-item { + height: 30px; + width: 300px; + border: 2px dashed #0071bd; +} + #afGuiEditor .af-gui-entity-palette-select-list { max-height: 400px; overflow-y: auto; diff --git a/ext/afform/admin/ang/afGuiEditor.js b/ext/afform/admin/ang/afGuiEditor.js index 406906a5c1..6fde62204a 100644 --- a/ext/afform/admin/ang/afGuiEditor.js +++ b/ext/afform/admin/ang/afGuiEditor.js @@ -190,10 +190,10 @@ $(this).removeClass('af-gui-dragtarget'); }) .on('sortstart', '#afGuiEditor', function() { - $('#afGuiEditor').addClass('af-gui-dragging'); + $('body').addClass('af-gui-dragging'); }) .on('sortstop', function() { - $('.af-gui-dragging').removeClass('af-gui-dragging'); + $('body').removeClass('af-gui-dragging'); $('.af-gui-dragtarget').removeClass('af-gui-dragtarget'); }); }); diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js index acbf3e23db..cf5e27e00b 100644 --- a/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js +++ b/ext/afform/admin/ang/afGuiEditor/afGuiEditor.component.js @@ -26,13 +26,24 @@ $scope.saving = false; $scope.selectedEntityName = null; this.meta = afGui.meta; - var editor = this; + var editor = this, + sortableOptions = {}; this.$onInit = function() { // Load the current form plus blocks & fields afGui.resetMeta(); afGui.addMeta(this.data); initializeForm(); + + $timeout(fixEditorHeight); + $timeout(editor.adjustTabWidths); + $(window) + .on('resize.afGuiEditor', fixEditorHeight) + .on('resize.afGuiEditor', editor.adjustTabWidths); + }; + + this.$onDestroy = function() { + $(window).off('.afGuiEditor'); }; // Initialize the current form @@ -141,6 +152,7 @@ if (selectTab) { editor.selectEntity(type + num); } + $timeout(editor.adjustTabWidths); } if (meta.fields) { @@ -165,6 +177,7 @@ this.selectEntity = function(entityName) { $scope.selectedEntityName = entityName; + $timeout(editor.adjustTabWidths); }; this.getEntity = function(entityName) { @@ -228,6 +241,24 @@ return options; } + // Options for ui-sortable in field palette + this.getSortableOptions = function(entityName) { + if (!sortableOptions[entityName + '']) { + sortableOptions[entityName + ''] = { + helper: 'clone', + appendTo: '#afGuiEditor-canvas-body > af-gui-container', + containment: '#afGuiEditor-canvas-body', + update: editor.onDrop, + items: '> div:not(.disabled)', + connectWith: '#afGuiEditor-canvas ' + (entityName ? '[data-entity="' + entityName + '"] > ' : '') + '[ui-sortable]', + placeholder: 'af-gui-dropzone', + tolerance: 'pointer', + scrollSpeed: 8 + }; + } + return sortableOptions[entityName + '']; + }; + // Validates that a drag-n-drop action is allowed this.onDrop = function(event, ui) { var sort = ui.item.sortable; @@ -274,6 +305,27 @@ }); } }); + + // Force editor panels to a fixed height, to avoid palette scrolling offscreen + function fixEditorHeight() { + var height = $(window).height() - $('#afGuiEditor').offset().top; + $('#afGuiEditor').height(Math.floor(height)); + } + + // Compress tabs on small screens + this.adjustTabWidths = function() { + $('#afGuiEditor .panel-heading ul.nav-tabs li.active').css('max-width', ''); + $('#afGuiEditor .panel-heading ul.nav-tabs').each(function() { + var remainingSpace = Math.floor($(this).width()) - 1, + inactiveTabs = $(this).children('li.fluid-width-tab').not('.active'); + $(this).children('.active,:not(.fluid-width-tab)').each(function() { + remainingSpace -= $(this).width(); + }); + if (inactiveTabs.length) { + inactiveTabs.css('max-width', Math.floor(remainingSpace / inactiveTabs.length) + 'px'); + } + }); + }; } }); diff --git a/ext/afform/admin/ang/afGuiEditor/afGuiEditorCanvas.html b/ext/afform/admin/ang/afGuiEditor/afGuiEditorCanvas.html index df975f1058..0b767376da 100644 --- a/ext/afform/admin/ang/afGuiEditor/afGuiEditorCanvas.html +++ b/ext/afform/admin/ang/afGuiEditor/afGuiEditorCanvas.html @@ -21,11 +21,13 @@