GUI Add controls for text color, block border & block background color
authorColeman Watts <coleman@civicrm.org>
Tue, 19 Nov 2019 13:42:51 +0000 (08:42 -0500)
committerCiviCRM <info@civicrm.org>
Wed, 16 Sep 2020 02:13:20 +0000 (19:13 -0700)
ext/afform/gui/afform_gui.php
ext/afform/gui/ang/afGuiEditor.css
ext/afform/gui/ang/afGuiEditor.js
ext/afform/gui/ang/afGuiEditor/block-menu.html
ext/afform/gui/ang/afGuiEditor/block.html
ext/afform/gui/ang/afGuiEditor/button-menu.html
ext/afform/gui/ang/afGuiEditor/text-menu.html
ext/afform/gui/ang/afGuiEditor/text.html

index 19a71aa48ad31deae8b3c0aba27da1e1eecc6963..e55d0815e23a3977e72ebee7438ff7d12b474317 100644 (file)
@@ -213,6 +213,15 @@ function afform_gui_civicrm_buildAsset($asset, $params, &$mimeType, &$content) {
     $data['inputType'][$matches[1]] = $matches[1];
   }
 
+  $data['styles'] = [
+    'default' => ts('Default'),
+    'primary' => ts('Primary'),
+    'success' => ts('Success'),
+    'info' => ts('Info'),
+    'warning' => ts('Warning'),
+    'danger' => ts('Danger'),
+  ];
+
   $mimeType = 'text/javascript';
   $content = "CRM.afformAdminData=" . json_encode($data, JSON_UNESCAPED_SLASHES) . ';';
 }
index 2c215c37cf2f2a83466c79dd27bb0eb8d8f7aa64..ae9d26e0b7bf6a753af640560732807c45a3ebac 100644 (file)
   padding-right: 5px;
 }
 
+#afGuiEditor li .af-gui-field-select-in-dropdown input[type=color] {
+  width: 30px;
+  padding: 2px 4px;
+}
+
 /* For editing field placeholder text */
 #afGuiEditor .af-gui-field-input input[type=text].form-control {
   color: #9a9a9a;
 }
 #afGuiEditor .af-gui-field-input-type-radio label.radio input[type=radio] {
   margin: 0;
-
 }
 
 #afGuiEditor .af-gui-text-h1 {
   font-style: italic;
 }
 
-
 #afGuiEditor.af-gui-editing-options {
   pointer-events: none;
   cursor: default;
index b6fb02bd7b9c92328298cf96a480bfb875271a67..e8e18cd928cd51e480b05ca81b53a6cbc7d24847 100644 (file)
         $scope.editor = editor;
       },
       controller: function($scope) {
-        $scope.block = this;
+        var block = $scope.block = this;
         var ts = $scope.ts = CRM.ts();
         this.node = $scope.node;
 
           if (val !== 'af-layout-rows') {
             classes.push(val);
           }
-          $scope.block.modifyClasses($scope.node, _.keys($scope.layouts), classes);
+          block.modifyClasses($scope.node, _.keys($scope.layouts), classes);
         };
 
+        $scope.getSetBorderWidth = function(width) {
+          return getSetBorderProp(0, arguments.length ? width : null);
+        };
+
+        $scope.getSetBorderStyle = function(style) {
+          return getSetBorderProp(1, arguments.length ? style : null);
+        };
+
+        $scope.getSetBorderColor = function(color) {
+          return getSetBorderProp(2, arguments.length ? color : null);
+        };
+
+        $scope.getSetBackgroundColor = function(color) {
+          if (!arguments.length) {
+            return block.getStyles($scope.node)['background-color'] || '#ffffff';
+          }
+          block.setStyle($scope.node, 'background-color', color);
+        };
+        
+        function getSetBorderProp(idx, val) {
+          var border = getBorder() || ['1px', '', '#000000'];
+          if (val === null) {
+            return border[idx];
+          }
+          border[idx] = val;
+          block.setStyle($scope.node, 'border', val ? border.join(' ') : null);
+        }
+
+        this.getStyles = function(node) {
+          return !node || !node.style ? {} : _.transform(node.style.split(';'), function(styles, style) {
+            var keyVal = _.map(style.split(':'), _.trim);
+            if (keyVal.length > 1 && keyVal[1].length) {
+              styles[keyVal[0]] = keyVal[1];
+            }
+          }, {});
+        };
+
+        this.setStyle = function(node, name, val) {
+          var styles = block.getStyles(node);
+          styles[name] = val;
+          if (!val) {
+            delete styles[name];
+          }
+          if (_.isEmpty(styles)) {
+            delete node.style;
+          } else {
+            node.style = _.transform(styles, function(combined, val, name) {
+              combined.push(name + ': ' + val);
+            }, []).join('; ');
+          }
+        };
+
+        function getBorder() {
+          var border = _.map((block.getStyles($scope.node).border || '').split(' '), _.trim);
+          return border.length > 2 ? border : null;
+        }
+
       }
     };
   });
         $scope.setAlign = function(val) {
           $scope.block.modifyClasses($scope.node, _.keys($scope.alignments), val === 'text-left' ? null : val);
         };
+
+        $scope.styles = _.transform(CRM.afformAdminData.styles, function(styles, val, key) {
+          styles['text-' + key] = val;
+        });
+
+        // Getter/setter for ng-model
+        $scope.getSetStyle = function(val) {
+          if (arguments.length) {
+            return $scope.block.modifyClasses($scope.node, _.keys($scope.styles), val === 'text-default' ? null : val);
+          }
+          return _.intersection(splitClass($scope.node['class']), _.keys($scope.styles))[0] || 'text-default';
+        };
+
       }
     };
   });
         //   "modelListCtrl.submit()": ts('Submit Form')
         // };
 
-        $scope.styles = {
-          'btn-default': ts('Default'),
-          'btn-primary': ts('Primary'),
-          'btn-success': ts('Success'),
-          'btn-info': ts('Info'),
-          'btn-warning': ts('Warning'),
-          'btn-danger': ts('Danger')
-        };
+        $scope.styles = _.transform(CRM.afformAdminData.styles, function(styles, val, key) {
+          styles['btn-' + key] = val;
+        });
 
         // Getter/setter for ng-model
         $scope.getSetStyle = function(val) {
index f42066e6dbea6779f029825ff0376e1a0484f269..4a01d9ee924913da19e46f883fa502129134bd65 100644 (file)
@@ -2,4 +2,33 @@
 <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>
+  <div class="af-gui-field-select-in-dropdown form-inline" ng-click="$event.stopPropagation()">
+    <select class="form-control" ng-model="getSetBorderStyle" ng-model-options="{getterSetter: true}">
+      <option value="">{{ ts('No border') }}</option>
+      <option value="solid">{{ ts('Solid') }}</option>
+      <option value="dotted">{{ ts('Dotted') }}</option>
+      <option value="dashed">{{ ts('Dashed') }}</option>
+      <option value="double">{{ ts('Double') }}</option>
+      <option value="groove">{{ ts('Groove') }}</option>
+      <option value="ridge">{{ ts('Ridge') }}</option>
+      <option value="inset">{{ ts('Inset') }}</option>
+      <option value="outset">{{ ts('Outset') }}</option>
+    </select>
+    <select class="form-control" ng-if="block.getStyles(node).border" ng-model="getSetBorderWidth" ng-model-options="{getterSetter: true}">
+      <option ng-repeat="num in ['1px', '2px', '3px', '4px', '5px', '6px', '7px', '8px', '9px']" value="{{ num }}">{{ num }}</option>
+    </select>
+    <input type="color" class="form-control" ng-if="block.getStyles(node).border" ng-model="getSetBorderColor" ng-model-options="{getterSetter: true}"/>
+  </div>
+</li>
+<li>
+  <div class="af-gui-field-select-in-dropdown form-inline" ng-click="$event.stopPropagation()">
+    <label>{{ ts('Background:') }}</label>
+    <input type="color" class="form-control" ng-model="getSetBackgroundColor" ng-model-options="{getterSetter: true}"/>
+    <a href class="" ng-click="getSetBackgroundColor(null)" ng-if="block.getStyles(node)['background-color']">
+      <i class="crm-i fa-times"></i>
+    </a>
+  </div>
+</li>
+<li role="separator" class="divider"></li>
 <li><a href ng-click="block.removeBlock(node)"><span class="text-danger">{{ ts('Delete this block') }}</span></a></li>
index 8fc03edcc4cb2354ca661b328372113af7a0fba3..1c7df59e4f999acfabdfb5f86707aafa1e334ed5 100644 (file)
@@ -35,8 +35,8 @@
 <div ui-sortable="{handle: '.af-gui-bar', update: onDrop, connectWith: '[ui-sortable]', cancel: 'input,textarea,button,select,option,a'}" ng-model="node['#children']" class="af-gui-layout {{ getLayout() }}">
   <div ng-repeat="item in node['#children']" >
     <div ng-switch="block.getNodeType(item)">
-      <div ng-switch-when="fieldset" af-gui-block="item" class="af-gui-block af-gui-fieldset af-gui-block-type-{{ item['#tag'] }}" ng-class="{'af-entity-selected': isSelectedFieldset(item['af-fieldset'])}" entity-name="item['af-fieldset']" data-entity="{{ item['af-fieldset'] }}" />
-      <div ng-switch-when="block" af-gui-block="item" class="af-gui-block af-gui-block-type-{{ item['#tag'] }}" entity-name="entityName" />
+      <div ng-switch-when="fieldset" af-gui-block="item" style="{{ item.style }}" class="af-gui-block af-gui-fieldset af-gui-block-type-{{ item['#tag'] }}" ng-class="{'af-entity-selected': isSelectedFieldset(item['af-fieldset'])}" entity-name="item['af-fieldset']" data-entity="{{ item['af-fieldset'] }}" />
+      <div ng-switch-when="block" af-gui-block="item" style="{{ item.style }}" class="af-gui-block af-gui-block-type-{{ item['#tag'] }}" entity-name="entityName" />
       <div ng-switch-when="field" af-gui-field="item" entity-name="entityName" />
       <div ng-switch-when="text" af-gui-text="item" class="af-gui-element af-gui-text" />
       <div ng-switch-when="button" af-gui-button="item" class="af-gui-element af-gui-button" />
index ab67fb5ccd3a57bd50934566907c9f488cbcfc74..9a55847f18d0d6aa60ccf5fe1832c989fac17ef9 100644 (file)
@@ -1,7 +1,7 @@
 <li>
   <div ng-click="$event.stopPropagation()" class="af-gui-field-select-in-dropdown form-inline" >
-    <label>{{ ts('Style:') }}</label>
-    <select class="form-control {{ getSetStyle().replace('btn', 'text') }}" ng-model="getSetStyle" ng-model-options="{getterSetter: true}" title="{{ ts('Button style') }}">
+    <label>{{ ts('Color:') }}</label>
+    <select class="form-control {{ getSetStyle().replace('btn', 'text') }}" ng-model="getSetStyle" ng-model-options="{getterSetter: true}" title="{{ ts('Button color scheme') }}">
       <option ng-repeat="(style, label) in styles" class="{{ style.replace('btn', 'bg') }}" value="{{ style }}">{{ label }}</option>
     </select>
   </div>
index 8fed55388d3ec3e111256af6d0e50d084295e8b6..7b4ab0ff81e415ec41b30091d16fb6ba55d98786 100644 (file)
     </div>
   </div>
 </li>
+<li>
+  <div ng-click="$event.stopPropagation()" class="af-gui-field-select-in-dropdown form-inline" >
+    <label>{{ ts('Color:') }}</label>
+    <select class="form-control {{ getSetStyle().replace('btn', 'text') }}" ng-model="getSetStyle" ng-model-options="{getterSetter: true}" title="{{ ts('Button color scheme') }}">
+      <option ng-repeat="(style, label) in styles" class="{{ style.replace('text', 'bg') }}" value="{{ style }}">{{ label }}</option>
+    </select>
+  </div>
+</li>
 <li role="separator" class="divider"></li>
 <li>
   <a href ng-click="block.removeBlock(node)"><span class="text-danger">{{ ts('Delete this text') }}</span></a>
index a5a6261fc62129504384eb04f1be949bc909c8e8..f7b182532bbd30164cd4e854061ded6a7c32fc3c 100644 (file)
@@ -8,6 +8,6 @@
     </div>
   </div>
 </div>
-<p class="af-gui-node-title {{ getAlign() + ' af-gui-text-' + node['#tag'] }}" >
+<p class="af-gui-node-title {{ node['class'] + ' af-gui-text-' + node['#tag'] }}" >
   <span af-gui-editable ng-model="node['#children'][0]['#text']">{{ node['#children'][0]['#text'] }}</span>
 </p>