GUI: Add/remove block buttons
authorColeman Watts <coleman@civicrm.org>
Fri, 8 Nov 2019 18:04:21 +0000 (13:04 -0500)
committerCiviCRM <info@civicrm.org>
Wed, 16 Sep 2020 02:13:20 +0000 (19:13 -0700)
ext/afform/gui/ang/afGuiEditor.css
ext/afform/gui/ang/afGuiEditor.js
ext/afform/gui/ang/afGuiEditor/block.html
ext/afform/gui/ang/afGuiEditor/button.html
ext/afform/gui/ang/afGuiEditor/text.html

index c1ceee8f184f24020530950f906d494b52309daa..08944397a16b9b8650d20e553145c0a000347188 100644 (file)
   margin-left: 5px;
 }
 
+#afGuiEditor-canvas .panel-body {
+  padding-top: 5px;
+}
+
 #afGuiEditor #afGuiEditor-palette-tabs li {
   top: 1px;
 }
 }
 
 #afGuiEditor .af-gui-bar {
+  height: 22px;
+  width: 100%;
+  opacity: 0;
+  transition: opacity 1s 2s;
+  position:relative;
+}
+#afGuiEditor [ui-sortable] .af-gui-bar {
   cursor: move;
   background-color: #efefef;
-  height: 22px;
   position: absolute;
   top: 0;
   left: 0;
-  width: 100%;
   padding-left: 15px;
-  opacity: 0;
-  transition: opacity 1s 2s;
 }
 #afGuiEditor-canvas:hover .af-gui-bar {
   opacity: 1;
   background-color: #efefef;
 }
 /* grip handle */
-#afGuiEditor .af-gui-bar:before,
+#afGuiEditor [ui-sortable] .af-gui-bar:before,
 #afGuiEditor .af-gui-field-select-list > div:not(.disabled):hover:before {
   background-size: cover;
   background: url("data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI1IiBoZWlnaHQ9IjUiPgo8cmVjdCB3aWR0aD0iMSIgaGVpZ2h0PSIxIiBmaWxsPSIjODg4Ij48L3JlY3Q+Cjwvc3ZnPg==");
   left: 4px;
   top: 5px;
 }
-
+#afGuiEditor #afGuiEditor-canvas .af-gui-add-canvas-button {
+  border: 2px dashed #0071bd;
+  color: #0071bd;
+  padding-top: 2px;
+  padding-bottom: 2px;
+}
 #afGuiEditor .af-gui-add-block-button span {
   display: inline-block;
-  width: 16px;
-  height: 16px;
-  border: 2px dashed grey;
+  width: 18px;
+  height: 18px;
+  border: 2px dashed #0071bd;
+  color: #0071bd;
 }
 #afGuiEditor .af-gui-add-block-button span i {
   position: relative;
index 95b7b26b8f80eb0b4bb40ef2c61f1e65a4049d8e..eb9009c811e51c02abedaf171991298dd36b69ed 100644 (file)
       restrict: 'A',
       templateUrl: '~/afGuiEditor/entity.html',
       scope: {
-        entity: '=afGuiEntity',
+        entity: '=afGuiEntity'
       },
       require: '^^afGuiEditor',
       link: function ($scope, element, attrs, editor) {
           return null;
         };
 
-        $scope.addBlock = function(type) {
-          var newBlock = {
-            '#tag': type === 'text' ? 'p' : 'div',
-            'class': 'af-' + type,
-            '#children': type == 'block' ? [] : [{'#text': ts('Enter text')}]
-          };
-          if (type === 'button') {
-            newBlock['#tag'] = 'button';
-            newBlock['class'] += ' btn btn-primary';
-            newBlock['crm-icon'] = 'fa-check';
-            newBlock['ng-click'] = "modelListCtrl.submit()";
-          }
+        $scope.addBlock = function(type, props) {
+          var classes = type.split('.');
+          var newBlock = _.defaults({
+            '#tag': classes.shift(),
+            'class': classes.join(' '),
+            '#children': classes[0] === 'af-block' ? [] : [{'#text': ts('Enter text')}]
+          }, props);
           $scope.node['#children'].push(newBlock);
         };
 
+        this.removeBlock = function(node) {
+          removeRecursive($scope.editor.scope.layout['#children'], {$$hashKey: node.$$hashKey});
+        };
+
         $scope.isSelectedFieldset = function(entityName) {
           return entityName === $scope.editor.getSelectedEntity();
         };
index 28d96ff68c6a3048ba925bc305a5e72816ce6b1b..00fad45b9bd24524da668e74aed6b7c0929dc1e6 100644 (file)
@@ -1,4 +1,4 @@
-<div class="af-gui-bar" ng-if="node['#tag'] != 'af-form'" ng-click="selectEntity()" >
+<div class="af-gui-bar" ng-if="node['#tag'] !== 'af-form'" ng-click="selectEntity()" >
   <span ng-if="block.getNodeType(node) == 'fieldset'">{{ editor.getEntity(entityName).label }}</span>
   <span>{{ node['#tag'] }}</span>
   <div class="form-inline pull-right">
@@ -7,16 +7,33 @@
         <i class="af-gui-layout-icon {{ opt }}" ></i>
       </button>
     </div>
-    <select ng-model="node['#tag']">
+    <select ng-model="node['#tag']" title="{{ ts('Block type') }}">
       <option ng-repeat="(opt, label) in tags" value="{{ opt }}">{{ label }}</option>
     </select>
     <button type="button" class="btn btn-default btn-xs dropdown-toggle af-gui-add-block-button" data-toggle="dropdown" title="{{ ts('Add block') }}">
       <span><i class="crm-i fa-plus"></i></span>
     </button>
     <ul class="dropdown-menu">
-      <li><a href ng-click="addBlock('block')">{{ ts('Add block/fieldset') }}</a></li>
-      <li><a href ng-click="addBlock('text')">{{ ts('Add text box') }}</a></li>
-      <li><a href ng-click="addBlock('button')">{{ ts('Add button') }}</a></li>
+      <li><a href ng-click="addBlock('div.af-block')">{{ ts('Add block') }}</a></li>
+      <li><a href ng-click="addBlock('p.af-text')">{{ ts('Add text box') }}</a></li>
+      <li><a href ng-click="addBlock('button.af-button.btn-primary', {'crm-icon': 'fa-check', 'ng-click': 'modelListCtrl.submit()'})">{{ ts('Add button') }}</a></li>
+      <li><a href ng-click="block.removeBlock(node)"><span class="text-danger">{{ ts('Delete this block') }}</span></a></li>
+    </ul>
+  </div>
+</div>
+<div class="af-gui-bar" ng-if="node['#tag'] === 'af-form'" >
+  <div class="form-inline pull-right">
+    <button type="button" class="btn  btn-default btn-sm dropdown-toggle af-gui-add-canvas-button" data-toggle="dropdown" title="{{ ts('Add block') }}">
+      <span>Add <i class="crm-i fa-plus"></i></span>
+    </button>
+    <ul class="dropdown-menu">
+      <li><a href ng-click="addBlock('div.af-block')">{{ ts('Add block') }}</a></li>
+      <li><a href ng-click="addBlock('p.af-text')">{{ ts('Add text box') }}</a></li>
+      <li><a href ng-click="addBlock('button.af-button.btn-primary', {'crm-icon': 'fa-check', 'ng-click': 'modelListCtrl.submit()'})">{{ ts('Add button') }}</a></li>
+      <li role="separator" class="divider"></li>
+      <li ng-repeat="entity in editor.scope.entities">
+        <a href ng-click="addBlock('fieldset.af-block', {'af-fieldset': entity.name})">{{ ts('Fieldset for %1', {1: entity.label}) }}</a>
+      </li>
     </ul>
   </div>
 </div>
index 996205a13bcfb7323be2b13fbe8533f31120fc16..60d8a0a8c2de082f5521faa282ff29ea806ac905 100644 (file)
@@ -1,15 +1,25 @@
 <div class="af-gui-bar">
   {{ node['#tag'] }}
   <div class="form-inline pull-right">
-    <button type="button" class="btn btn-xs dropdown-toggle {{ getStyle() }}-outline" data-toggle="dropdown" title="{{ ts('Style') }}">
-      <span>{{ styles[getStyle()] }}</span>
-      <i class="crm-i fa-caret-down"></i>
-    </button>
-    <ul class="dropdown-menu">
-      <li ng-repeat="(style, label) in styles" class="{{ style.replace('btn', 'bg') }}">
-        <a href ng-click="setStyle(style)">{{ label }}</a>
-      </li>
-    </ul>
+    <div class="btn-group pull-right">
+      <button type="button" class="btn btn-default btn-xs dropdown-toggle af-gui-add-block-button" data-toggle="dropdown" title="{{ ts('Configure') }}">
+        <span><i class="crm-i fa-gear"></i></span>
+      </button>
+      <ul class="dropdown-menu">
+        <li><a href ng-click="block.removeBlock(node)"><span class="text-danger">{{ ts('Delete this button') }}</span></a></li>
+      </ul>
+    </div>
+    <div class="btn-group pull-right">
+      <button type="button" class="btn btn-xs dropdown-toggle {{ getStyle() }}-outline" data-toggle="dropdown" title="{{ ts('Style') }}">
+        <span>{{ styles[getStyle()] }}</span>
+        <i class="crm-i fa-caret-down"></i>
+      </button>
+      <ul class="dropdown-menu">
+        <li ng-repeat="(style, label) in styles" class="{{ style.replace('btn', 'bg') }}">
+          <a href ng-click="setStyle(style)">{{ label }}</a>
+        </li>
+      </ul>
+    </div>
   </div>
 </div>
 <button type="button" class="btn {{ getStyle() }}">
index 85b6889a15d0269c89b8f22fe283cf102cae38f0..f770446d8fe7861b79939d89c80e2077bdd0aa25 100644 (file)
@@ -1,12 +1,22 @@
 <div class="af-gui-bar">
   {{ node['#tag'] }}
-  <select class="pull-right" ng-model="node['#tag']">
-    <option ng-repeat="(opt, label) in tags" value="{{ opt }}">{{ label }}</option>
-  </select>
-  <div class="btn-group btn-group-xs pull-right" role="group">
-    <button type="button" class="btn btn-default" ng-class="{active: opt === getAlign()}" ng-repeat="(opt, label) in alignments" ng-click="setAlign(opt)" title="{{ label }}">
-      <i class="crm-i fa-{{ opt.replace('text', 'align') }}" ></i>
-    </button>
+  <div class="form-inline pull-right">
+    <div class="btn-group pull-right">
+      <button type="button" class="btn btn-default btn-xs dropdown-toggle af-gui-add-block-button" data-toggle="dropdown" title="{{ ts('Configure') }}">
+        <span><i class="crm-i fa-gear"></i></span>
+      </button>
+      <ul class="dropdown-menu">
+        <li><a href ng-click="block.removeBlock(node)"><span class="text-danger">{{ ts('Delete this text') }}</span></a></li>
+      </ul>
+    </div>
+    <select class="pull-right" ng-model="node['#tag']" title="{{ ts('Text style') }}">
+      <option ng-repeat="(opt, label) in tags" value="{{ opt }}">{{ label }}</option>
+    </select>
+    <div class="btn-group btn-group-xs pull-right" role="group">
+      <button type="button" class="btn btn-default" ng-class="{active: opt === getAlign()}" ng-repeat="(opt, label) in alignments" ng-click="setAlign(opt)" title="{{ label }}">
+        <i class="crm-i fa-{{ opt.replace('text', 'align') }}" ></i>
+      </button>
+    </div>
   </div>
 </div>
 <p af-gui-editable ng-model="node['#children'][0]['#text']" class="{{ getAlign() + ' af-gui-text-' + node['#tag'] }}" >