浏览代码

HUE-4993 [assist] Use ko bindings for the query builder context menu

This also adds a submenu binding for the hue context menu.
Johan Ahlen 9 年之前
父节点
当前提交
30e5b0e72b

+ 15 - 1
desktop/core/src/desktop/static/desktop/css/hue3.css

@@ -2514,6 +2514,7 @@ body {
 
 
 .hue-inner-drop-down > li > a:hover,
 .hue-inner-drop-down > li > a:hover,
 .hue-inner-drop-down > li.active,
 .hue-inner-drop-down > li.active,
+.hue-context-menu > li.active,
 .hue-context-menu > li > a:not(.disabled):hover {
 .hue-context-menu > li > a:not(.disabled):hover {
   background-color: #DBE8F1;
   background-color: #DBE8F1;
 }
 }
@@ -2531,7 +2532,7 @@ body {
   vertical-align: middle;
   vertical-align: middle;
 }
 }
 
 
-.hue-context-menu > li > a > i {
+.hue-context-menu > li > a > i:not(.sub-icon) {
   position: absolute;
   position: absolute;
   top: 6px;
   top: 6px;
   left: 13px;
   left: 13px;
@@ -2544,6 +2545,19 @@ body {
   vertical-align: middle;
   vertical-align: middle;
 }
 }
 
 
+.hue-context-menu > li > a > .sub-icon {
+  position: absolute;
+  top: 6px;
+  left: auto;
+  right: 13px;
+  line-height: 22px;
+  height: 24px;
+
+  color: #555;
+  font-size: 12px;
+  vertical-align: middle;
+}
+
 .hue-context-menu > .divider {
 .hue-context-menu > .divider {
   height: 1px;
   height: 1px;
   margin: 9px 0;
   margin: 9px 0;

+ 40 - 0
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -605,6 +605,46 @@
     }
     }
   };
   };
 
 
+
+  ko.bindingHandlers.contextSubMenu = {
+    init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
+      var menuSelector = valueAccessor();
+      var $element = $(element);
+
+      var $menu = $element.find(menuSelector);
+      var $parentMenu = $element.parent('.hue-context-menu');
+      var open = false;
+
+      var closeSubMenu = function () {
+        open = false;
+        $menu.hide();
+        $element.removeClass('active');
+      };
+
+      var hideTimeout = -1;
+      $element.add($menu).on('mouseenter', function () {
+        $element.addClass('active');
+        if (!open) {
+          huePubSub.publish('hue.sub.menu.close');
+        }
+        open = true;
+        window.clearTimeout(hideTimeout);
+        var menuHeight = $menu.outerHeight();
+        $menu.css('top', ($element.position().top + $parentMenu.position().top + menuHeight > $(window).height()) ? $(window).height() - menuHeight - 8 : $element.position().top + $parentMenu.position().top);
+        $menu.css('left', $element.offset().left + $element.outerWidth(true));
+        $menu.css('opacity', 0);
+        $menu.show();
+        $menu.css('opacity', 1);
+        huePubSub.subscribeOnce('hue.sub.menu.close', closeSubMenu);
+      });
+
+      $element.add($menu).on('mouseleave', function () {
+        window.clearTimeout(hideTimeout);
+        hideTimeout = window.setTimeout(closeSubMenu, 300);
+      });
+    }
+  };
+
   ko.bindingHandlers.templateContextMenu = {
   ko.bindingHandlers.templateContextMenu = {
     init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
     init: function (element, valueAccessor, allBindings, viewModel, bindingContext) {
       var options = valueAccessor();
       var options = valueAccessor();

+ 45 - 0
desktop/core/src/desktop/templates/assist.mako

@@ -459,6 +459,51 @@ from metadata.conf import has_navigator
 
 
   <script type="text/html" id="sql-context-items">
   <script type="text/html" id="sql-context-items">
     <li><a href="javascript:void(0);" data-bind="click: dblClick"><i class="fa fa-fw fa-pencil"></i> ${ _('Insert...') }</a></li>
     <li><a href="javascript:void(0);" data-bind="click: dblClick"><i class="fa fa-fw fa-pencil"></i> ${ _('Insert...') }</a></li>
+    <!-- ko if: definition.isColumn -->
+    <li class="divider"></li>
+    <!-- ko template: { name: 'query-builder-context-items' } --><!-- /ko -->
+    <!-- /ko -->
+  </script>
+
+  <script type="text/html" id="query-builder-context-items">
+    <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
+      <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Project') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
+      <ul class="hue-context-menu hue-context-sub-menu">
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Select', 'Project', '{0}', false, false); }">${ _('Select') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Select distinct', 'Project', '{0}', false, false); }">${ _('Select distinct') }</a></li>
+      </ul>
+    </li>
+
+    <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
+      <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Aggregate') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
+      <ul class="hue-context-menu hue-context-sub-menu">
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Count', 'Aggregate', 'COUNT({0}.{1}) as count_{1}', false, false); }">${ _('Count') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Count distinct', 'Aggregate', 'COUNT(DISTINCT {0}.{1}) as distinct_count_{1}', false, false); }">${ _('Count distinct') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Sum', 'Aggregate', 'SUM({0}.{1}) as sum_{1}', false, false); }">${ _('Sum') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Minimum', 'Aggregate', 'MIN({0}.{1}) as min_{1}', false, false); }">${ _('Minimum') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Maximum', 'Aggregate', 'MAX({0}.{1}) as max_{1}', false, false); }">${ _('Maximum') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Average', 'Aggregate', 'AVG({0}.{1}) as avg_{1}', false, false); }">${ _('Average') }</a></li>
+      </ul>
+    </li>
+
+    <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
+      <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Filter') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
+      <ul class="hue-context-menu hue-context-sub-menu">
+        <li><a href="javascript:void(0);" data-bind="click: function () { var isNotNullRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Is not null'); if (isNotNullRule.length) { isNotNullRule.attr('rule', 'Is null'); isNotNullRule.find('.rule').text('Is null'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Is null', 'Filter', '{0}.{1} = null', false, false); } }">${ _('Is null') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { var isNullRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Is null'); if (isNullRule.length) { isNullRule.attr('rule', 'Is not null'); isNullRule.find('.rule').text('Is not null'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Is not null', 'Filter', '{0}.{1} != null', false, false); } }">${ _('Is not null') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Equal to', 'Filter', '{0}.{1} = {2}', true, true); }">${ _('Equal to') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Not equal to', 'Filter', '{0}.{1} != {2}', true, true); }">${ _('Not equal to') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Greater than', 'Filter', '{0}.{1} > {2}', true, false) }">${ _('Greater than') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { QueryBuilder.addRule(databaseName, tableName, columnName, 'Less than', 'Filter', '{0}.{1} < {2}', true, false); }">${ _('Less than') }</a></li>
+      </ul>
+    </li>
+    <li data-bind="contextSubMenu: '.hue-context-sub-menu'">
+      <a href="javascript:void(0);"><i class="fa fa-fw fa-magic"></i> ${ _('Order') }<i class="sub-icon fa fa-fw fa-chevron-right"></i></a>
+      <ul class="hue-context-menu hue-context-sub-menu">
+        <li><a href="javascript:void(0);" data-bind="click: function () { var descendingRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Descending'); if (descendingRule.length) { descendingRule.attr('rule', 'Ascending'); descendingRule.find('.rule').text('Ascending'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Ascending', 'Order', '{0}.{1} ASC', false, false); } }">${ _('Ascending') }</a></li>
+        <li><a href="javascript:void(0);" data-bind="click: function () { var ascendingRule = QueryBuilder.getRule(databaseName, tableName, columnName, 'Ascending'); if (ascendingRule.length) { ascendingRule.attr('rule', 'Descending'); ascendingRule.find('.rule').text('Descending'); } else { QueryBuilder.addRule(databaseName, tableName, columnName, 'Descending', 'Order', '{0}.{1} DESC', false, false); } }">${ _('Descending') }</a></li>
+      </ul>
+    </li>
   </script>
   </script>
 
 
   <script type="text/html" id="assist-table-entry">
   <script type="text/html" id="assist-table-entry">