Răsfoiți Sursa

[notebook] Improved add snippet wheel

The wheel now shows the last 4 used snippet and a '...' alternative is added to the wheel that will open a modal for the remaining snippets. Clicking the middle '+' will open the last used snippet.
Johan Åhlén 10 ani în urmă
părinte
comite
1b30217

+ 32 - 28
desktop/core/src/desktop/static/desktop/js/ko.hue-bindings.js

@@ -190,45 +190,48 @@ ko.bindingHandlers.numericTextInput = {
 
 ko.bindingHandlers.radialMenu = {
   init: function(element, valueAccessor) {
+    var $element = $(element);
+    var allAlternatives = $("<div>").addClass('all-alternatives').hide().appendTo($element);
+    $element.data('hide-timeout', -1);
+  },
+
+  update: function(element, valueAccessor) {
     var $element = $(element);
     var options = valueAccessor();
 
     var alternatives = options.alternatives;
-    var selected = options.selected; // Will be set before onSelect is called
-    var mainAlt = options.mainAlternative; // Alternative for clicking center
     var onSelect = options.onSelect || $.noop;
     var minRadius = options.minRadius || 70;
     var alternativeCss = options.alternativeCss;
     var alternativeSize = options.alternativeSize || 65;
 
-    var selectAttribute = options.selectAttribute;
     var textRenderer = options.textRenderer || function(item) {
         return item[selectAttribute]();
       };
 
-    var allAlternatives = $("<div>").hide();
+    var allAlternatives = $element.find('.all-alternatives');
 
-    var hideTimeout = -1;
     var hideAlternatives = function () {
-      clearTimeout(hideTimeout);
-      hideTimeout = setTimeout(function () {
+      clearTimeout($element.data('hide-timeout'));
+      $element.data('hide-timeout', setTimeout(function () {
         allAlternatives.fadeOut();
-      }, 600);
+      }, 600));
     };
 
-    var select = function (selectedValue) {
-      selected(selectedValue);
-      onSelect(selectedValue);
-      clearTimeout(hideTimeout);
+    var select = function (alternative) {
+      onSelect(alternative);
+      clearTimeout($element.data('hide-timeout'));
       allAlternatives.fadeOut();
     };
 
-    if (alternatives().length > 1) {
+    allAlternatives.empty();
+
+    if (alternatives().length > 0) {
       window.setTimeout(function() {
         var circumference = alternatives().length * alternativeSize;
         var radius = Math.max(minRadius, circumference / Math.PI / 2);
         var radIncrements = 2 * Math.PI / alternatives().length;
-        var currentRad = alternatives().length == 2 ? 2 * Math.PI : -0.5 * Math.PI;
+        var currentRad = -0.5 * Math.PI;
         var iconRadius = $element.find("i").width() / 2;
 
         $.each(alternatives(), function (index, alternative) {
@@ -237,32 +240,33 @@ ko.bindingHandlers.radialMenu = {
             .css("left", radius * Math.cos(currentRad) + iconRadius)
             .css("top", radius * Math.sin(currentRad) + iconRadius)
             .on("click", function () {
-              select(alternative[selectAttribute]());
+              select(alternative);
             })
             .on("mouseenter", function () {
-              clearTimeout(hideTimeout);
+              clearTimeout($element.data('hide-timeout'));
             })
             .on("mouseleave", hideAlternatives)
             .appendTo(allAlternatives);
           $("<div>")
             .text(textRenderer(alternative))
             .appendTo(outerDiv);
-
           currentRad += radIncrements;
         });
-        $element.append(allAlternatives);
       }, 500);
     }
 
-    $element.find("i")
-      .on("click", function() {
-        select(mainAlt());
-      })
-      .on("mouseenter", function() {
-        clearTimeout(hideTimeout);
-        allAlternatives.fadeIn();
-      })
-      .on("mouseleave", hideAlternatives);
+    if (! $element.data('radial-initialized')) {
+      $element.find("i")
+        .on("click", function() {
+          select();
+        })
+        .on("mouseenter", function() {
+          clearTimeout($element.data('hide-timeout'));
+          allAlternatives.fadeIn();
+        })
+        .on("mouseleave", hideAlternatives);
+      $element.data('radial-initialized', true);
+    }
   }
 };
 
@@ -1715,7 +1719,7 @@ ko.bindingHandlers.aceEditor = {
       editor.setOptions({fontSize: "14px"})
     }
     editor.on("focus", function () {
-      huePubSub.publish("hue.ace.activeMode", ko.utils.unwrapObservable(options.mode));
+      huePubSub.publish("hue.ace.activeMode", ko.unwrap(options.mode));
     });
 
     if (ko.isObservable(options.errors)) {

+ 89 - 0
desktop/core/src/desktop/templates/ko_components.mako

@@ -901,4 +901,93 @@ from desktop.views import _ko
       });
     }());
   </script>
+</%def>
+
+<%def name="addSnippetMenu()">
+  <script type="text/html" id="add-snippet-menu-template">
+    <div class="add-snippet-button pointer" style="position:relative; width:65px; text-align: center;" data-bind="radialMenu: {
+        alternatives: snippetsInWheel,
+        textRenderer: function(attribute) { return attribute.name() },
+        onSelect: addNewSnippet,
+        alternativeCss: 'add-snippet-alt'
+      }">
+      <i class="add-last-used-snippet fa fa-plus-circle fa-5x" title="${ _('Add a new snippet') }"></i>
+    </div>
+
+    <div id="addSnippetModal" class="modal hide fade">
+      <div class="modal-header">
+        <a href="#" class="close" data-dismiss="modal">&times;</a>
+        <h3>${ _('Add Snippet') }</h3>
+      </div>
+      <div class="modal-body" style="min-height: 100px">
+        <ul class="snippet-list-alts" data-bind="foreach: availableSnippets">
+          <li data-bind="click: function() { $parent.addNewSnippet($data) }">
+            <div style="width: 30px; display:inline-block;">
+            <!-- ko if: $root.getSnippetViewSettings(type()).snippetImage -->
+            <img class="snippet-icon" data-bind="attr: { 'src': $root.getSnippetViewSettings(type()).snippetImage }">
+            <!-- /ko -->
+            <!-- ko if: $root.getSnippetViewSettings(type()).snippetIcon -->
+            <i style="margin-left: 6px" class="fa snippet-icon" data-bind="css: $root.getSnippetViewSettings(type()).snippetIcon"></i>
+            <!-- /ko -->
+            </div>
+            <span data-bind="text: name"></span>
+          </li>
+        </ul>
+      </div>
+      <div class="modal-footer">
+        <button class="btn btn-primary disable-feedback" data-dismiss="modal">${_('Close')}</button>
+      </div>
+    </div>
+  </script>
+
+
+  <script type="text/javascript" charset="utf-8">
+    (function() {
+
+      var SHOW_MODAL_SNIPPET_ALT = {
+        type: function() { return "SHOW_MODAL" },
+        name: function() { return "..." }
+      };
+
+      function AddSnippetMenuViewModel (params) {
+        var self = this;
+        self.notebook = params.notebook;
+        self.availableSnippets = params.availableSnippets;
+
+        self.snippetHistory = ko.observableArray([].concat(self.availableSnippets.slice(0,4)));
+
+        self.snippetsInWheel = ko.computed(function () {
+          var result = self.snippetHistory().concat(SHOW_MODAL_SNIPPET_ALT);
+          return result;
+        });
+
+        self.addNewSnippet = function (alternative) {
+          $("#addSnippetModal").modal('hide');
+          if (alternative && alternative.type() === SHOW_MODAL_SNIPPET_ALT.type()) {
+            $("#addSnippetModal").modal('show');
+            return;
+          }
+          if (! alternative && self.snippetHistory().length > 0) {
+            self.notebook.newSnippet(self.snippetHistory()[0].type());
+            return;
+          }
+
+          var currentIndex = self.snippetHistory().indexOf(alternative);
+          if (currentIndex > -1) {
+            self.snippetHistory().splice(currentIndex, 1);
+          } else if (self.snippetHistory().length == 4) {
+            self.snippetHistory.pop();
+          }
+          self.snippetHistory.unshift(alternative);
+
+          self.notebook.newSnippet(alternative.type())
+        };
+      }
+
+      ko.components.register('add-snippet-menu', {
+        viewModel: AddSnippetMenuViewModel,
+        template: { element: 'add-snippet-menu-template' }
+      });
+    }());
+  </script>
 </%def>

+ 22 - 3
desktop/libs/notebook/src/notebook/static/notebook/css/notebook.css

@@ -146,7 +146,7 @@ body {
   padding: 20px;
 }
 
-.add-last-used-snippet {
+.add-snippet-button > i {
   color: #CCC;
   cursor: pointer;
 }
@@ -159,6 +159,7 @@ body {
   height: 50px;
   width: 50px;
   border-radius: 25px;
+  border: 1px solid;
 }
 
 .add-snippet-alt > div {
@@ -171,7 +172,25 @@ body {
   font-size: 11px;
 }
 
-.add-last-used-snippet,
+.snippet-list-alts {
+  margin: 0;
+  padding: 0;
+  list-style: none;
+}
+
+.snippet-list-alts > li {
+  padding: 5px 0 5px 10px;
+  cursor: pointer;
+  color: #464646;
+  margin-bottom: 2px;
+}
+
+.snippet-list-alts > li:hover {
+  padding: 5px 0 5px 10px;
+  background-color: #f0f0f0;
+}
+
+.add-snippet-button > i,
 .add-snippet-alt {
   -webkit-transition: color 0.3s ease, -webkit-transform 0.3s;
   -ms-transition: color 0.3s ease, -ms-transform 0.3s;
@@ -181,7 +200,7 @@ body {
 .add-snippet-alt:hover {
   color: #FFF;
 }
-.add-last-used-snippet:hover,
+.add-snippet-button > i:hover,
 .add-snippet-alt:hover {
   -webkit-transform: scale(1.3, 1.3);
   -ms-transform: scale(1.3, 1.3);

+ 4 - 1
desktop/libs/notebook/src/notebook/static/notebook/js/notebook.ko.js

@@ -767,7 +767,10 @@ var Notebook = function (vm, notebook) {
     })
   };
 
-  self.newSnippet = function () {
+  self.newSnippet = function (type) {
+    if (type) {
+      self.selectedSnippet(type);
+    }
     self.addSnippet({
       type: self.selectedSnippet(),
       result: {}

+ 8 - 4
desktop/libs/notebook/src/notebook/templates/notebook.mako

@@ -40,10 +40,13 @@ ${ editorComponents.includes() }
     <!-- ko if: $root.availableSnippets().length > 0 -->
     <h1 class="empty" data-bind="visible: snippets().length == 0">${ _('Add a snippet to start your new notebook') }</h1>
 
-    <div class="add-snippet">
-      <div class="add-snippet-button pointer" style="position:relative; width:65px; text-align: center;" data-bind="radialMenu: { alternatives: $root.availableSnippets, selectAttribute: 'type', textRenderer: function(attribute) { return attribute.name() }, selected: selectedSnippet, mainAlternative: selectedSnippet, onSelect: newSnippet, alternativeCss: 'add-snippet-alt' }">
-        <i class="add-last-used-snippet fa fa-plus-circle fa-5x" title="${ _('Add a new snippet') }"></i>
-      </div>
+    <div class="add-snippet" data-bind="component: {
+      name: 'add-snippet-menu',
+      params: {
+        notebook: $data,
+        availableSnippets: $root.availableSnippets
+      }
+    }">
     </div>
     <!-- /ko -->
   </%def>
@@ -52,6 +55,7 @@ ${ editorComponents.includes() }
 ${ koComponents.csvListInput() }
 ${ koComponents.jvmMemoryInput() }
 ${ koComponents.assistPanel() }
+${ koComponents.addSnippetMenu() }
 
 ${ editorComponents.commonJS() }