فهرست منبع

[notebook] Add code visibility toggle to snippets

This change makes it possible to show and hide the code or properties area for a snippet. Before this change the run and stop buttons were placed on top of the code editor and in order to still allow execution when the code is hidden the button has been moved down below the editor.

The visibility state is saved with the notebook.
Johan Ahlen 10 سال پیش
والد
کامیت
a21cbf2

+ 8 - 11
apps/spark/src/spark/static/spark/css/spark.css

@@ -202,6 +202,14 @@
   outline: none;
 }
 
+.snippet-actions {
+    display: none;
+}
+
+.snippet-container:hover .snippet-actions {
+    display: inline-block;
+}
+
 .text-snippet h2 {
   padding-left: 0 !important;
 }
@@ -268,17 +276,6 @@ h1.empty {
   background-color: #F0F0F0;
 }
 
-.editor:hover .run-button {
-    display: inherit;
-}
-
-.snippet-body:hover .run-button {
-    display: inline-block;
-}
-
-.run-button {
-    display: none;
-}
 .chart-icon {
   width: 15px;
   text-align: center;

+ 12 - 0
apps/spark/src/spark/static/spark/js/spark.ko.js

@@ -247,6 +247,18 @@ var Snippet = function (vm, notebook, snippet) {
     $(document).trigger("toggleLeftPanel", self);
   };
 
+  self.codeVisible = ko.observable(typeof snippet.codeVisible != "undefined" && snippet.codeVisible != null ? snippet.codeVisible : true);
+
+  // We need to refresh codemirror the first time it's shown if it's initially hidden otherwise it'll be blank
+  if (!self.codeVisible()) {
+    var subscription = self.codeVisible.subscribe(function(newVal) {
+      if (newVal) {
+        $(document).trigger("refreshCodeMirror", self);
+        subscription.dispose();
+      }
+    });
+  }
+
   self.expand = function () {
     self.size(self.size() + 1);
     $("#snippet_" + self.id()).trigger("resize");

+ 46 - 20
apps/spark/src/spark/templates/editor.mako

@@ -355,7 +355,7 @@ ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
 
 
 <script type="text/html" id="snippet">
-  <div class="row-fluid">
+  <div class="snippet-container row-fluid">
     <div data-bind="css: klass, attr: {'id': 'snippet_' + id()}">
 
       <h2 class="card-heading simple" data-bind="visible: $root.isEditing() || (! $root.isEditing() && type() != 'text')">
@@ -382,15 +382,16 @@ ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
         </div>
 
         <span data-bind="editable: name, editableOptions: {enabled: $root.isEditing(), placement: 'right'}"></span>
-        <div class="inline pull-right">
-          <a href="javascript:void(0)" data-bind="visible: $root.isEditing, click: function(){ remove($parent, $data); window.setTimeout(redrawFixedHeaders, 100);}"><i class="fa fa-times"></i></a>
+        <div class="snippet-actions inline pull-right">
+          <a href="javascript:void(0)" data-bind="click: function(){ codeVisible(! codeVisible()) }"><i class="fa" data-bind="css: {'fa-compress' : codeVisible, 'fa-expand' : ! codeVisible() }"></i></a>
+          <a href="javascript:void(0)" data-bind="click: function(){ remove($parent, $data); window.setTimeout(redrawFixedHeaders, 100);}"><i class="fa fa-times"></i></a>
         </div>
       </h2>
 
       <!-- ko if: ['text', 'jar', 'py'].indexOf(type()) == -1  -->
       <div class="snippet-body">
         <div class="row-fluid">
-          <div data-bind="css: editorKlass">
+          <div data-bind="css: editorKlass, verticalSlide: codeVisible">
             <div data-bind="foreach: variables">
               <div>
                 <span data-bind="text: name"></span>
@@ -399,22 +400,22 @@ ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
             </div>
             <textarea data-bind="value: statement_raw, codemirror: { 'id': id(), 'viewportMargin': Infinity, 'lineNumbers': true, 'indentUnit': 0, 'matchBrackets': true, 'mode': editorMode(), 'enter': execute }">
             </textarea>
-            <a data-bind="visible: status() == 'loading'" class="btn btn-disabled spark-btn codeMirror-overlaybtn" title="${ _('Creating session') }">
-              <i class="fa fa-spinner fa-spin"></i>
-            </a>
-            <a title="${ _('CTRL + ENTER') }" data-bind="click: execute, visible: status() != 'running' && status() != 'loading'" class="run-button btn btn-primary disable-feedback spark-btn codeMirror-overlaybtn pointer">
-              <i class="fa fa-play"></i>
-            </a>
-            <a title="${ _('Cancel') }" data-bind="click: cancel, visible: status() == 'running'" class="btn btn-danger disable-feedback spark-btn codeMirror-overlaybtn pointer">
-              <i class="fa fa-stop"></i>
-            </a>
-            <div class="progress progress-striped active" data-bind="css: { 'progress-warning': progress() > 0 && progress() < 100, 'progress-success': progress() == 100, 'progress-danger': progress() == 0 && result.errors().length > 0}" style="height: 1px; background-color: #FFF;">
-              <div class="bar" data-bind="style: {'width': (result.errors().length > 0 ? 100 : progress()) + '%'}"></div>
-            </div>
+          </div>
+          <div class="progress progress-striped active" data-bind="css: { 'progress-warning': progress() > 0 && progress() < 100, 'progress-success': progress() == 100, 'progress-danger': progress() == 0 && result.errors().length > 0}" style="height: 1px; background-color: #FFF; width: 100%">
+            <div class="bar" data-bind="style: {'width': (result.errors().length > 0 ? 100 : progress()) + '%'}"></div>
           </div>
         </div>
 
-        <div style="padding-top: 10px;">
+        <div style="padding-top: 10px; height: 29px;">
+          <a data-bind="visible: status() == 'loading'" class="btn btn-disabled spark-btn" title="${ _('Creating session') }">
+            <i class="fa fa-spinner fa-spin"></i>
+          </a>
+          <a title="${ _('CTRL + ENTER') }" data-bind="click: execute, visible: status() != 'running' && status() != 'loading'" class="snippet-actions run-button btn btn-primary disable-feedback spark-btn pointer">
+            <i class="fa fa-play"></i>
+          </a>
+          <a title="${ _('Cancel') }" data-bind="click: cancel, visible: status() == 'running'" class="btn btn-danger disable-feedback spark-btn pointer">
+            <i class="fa fa-stop"></i>
+          </a>
           <button data-bind="visible: result.type() == 'table' && result.hasSomeResults(), click: function() { $data.showGrid(true); }, css: {'active': $data.showGrid}" href="javascript:void(0)" class="btn" title="${ _('Grid') }">
             <i class="fa fa-th"></i>
           </button>
@@ -499,7 +500,7 @@ ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
         </div>
 
         <!-- ko if: result.hasSomeResults() && result.type() != 'table' -->
-          <div class="row-fluid" style="max-height: 400px; margin-top: 50px">
+          <div class="row-fluid" style="max-height: 400px; margin: 10px 0;">
             <pre data-bind="text: result.data()[0][1]">
             </pre>
           </div>
@@ -643,8 +644,8 @@ ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
       <!-- /ko -->
 
       <!-- ko if: type() == 'jar' || type() == 'py'-->
-        <div class="snippet-body" style="padding: 10px">
-          <table class="airy">
+        <div class="snippet-body">
+          <table class="airy" data-bind="verticalSlide: codeVisible">
             <tr data-bind="visible: type() =='jar'">
               <td>${_('Path')}</td>
               <td><input type="text" class="input-xxlarge filechooser-input" data-bind="value: properties.app_jar, valueUpdate:'afterkeydown', filechooser: properties.app_jar" placeholder="${ _('Path to application jar, e.g. hdfs://localhost:8020/user/hue/oozie-examples.jar') }"/></td>
@@ -813,6 +814,23 @@ ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
     }
   }
 
+  ko.bindingHandlers.verticalSlide = {
+    init: function(element, valueAccessor) {
+      if (ko.utils.unwrapObservable(valueAccessor())) {
+        $(element).show();
+      } else {
+        $(element).hide();
+      }
+    },
+    update: function(element, valueAccessor) {
+      if (ko.utils.unwrapObservable(valueAccessor())) {
+        $(element).slideDown('fast');
+      } else {
+        $(element).slideUp('fast');
+      }
+    }
+  };
+
   ko.bindingHandlers.codemirror = {
     init: function (element, valueAccessor, allBindingsAccessor, snippet) {
 
@@ -1824,6 +1842,14 @@ ${ commonheader(_('Query'), app_name, user, "68px") | n,unicode }
       }, 100);
     });
 
+    $(document).on("refreshCodeMirror", function (e, snippet) {
+      window.setTimeout(function () {
+        $("#snippet_" + snippet.id()).find(".CodeMirror").each(function() {
+          $(this)[0].CodeMirror.refresh();
+        });
+      }, 100);
+    });
+
     $(document).on("puma", function (e, snippet) {
       forceChartDraws();
     });