Selaa lähdekoodia

HUE-62. Allow HtmlTable context menu for multiple rows

* moved ccs-form_submit linker up to global level
* added support for disabling/enabling a context menu
* added support for nested context menus
* added methods to register/unregister keyboards on JFrame from a behavior filter
* added plugin to manage HtmlTable keyboard instances properly
* added new global linker for submitting forms with an anchor tag (moved up from Beeswax)
Aaron Newton 15 vuotta sitten
vanhempi
commit
68185c020d

+ 26 - 26
apps/beeswax/src/beeswax/templates/choose_delimiter.mako

@@ -29,10 +29,10 @@ ${wrappers.head('Choose a Delimiter')}
     <div class="bw-choose-delimiter">
         <div class="ccs-bc-section">
           <form action ="${action}" method="POST">
-	    <div class="ccs-hidden">
-	      ${util.render_form(file_form)}
-	      ${comps.field(delim_form['file_type'])}
-	    </div>
+            <div class="ccs-hidden">
+              ${util.render_form(file_form)}
+              ${comps.field(delim_form['file_type'])}
+            </div>
             <a name="step2"></a>
             <dt>Step 2: Choose A Delimiter</dt>
             <dd>
@@ -43,45 +43,45 @@ ${wrappers.head('Choose a Delimiter')}
                       <p class="delimiter_confirmation">Beeswax has determined that this file is delimited by ${delim_readable}.  Is this correct?</p>
                       <label>
                         Yes
-			## TODO(marcus)  The YES button does nothing
+                        ## TODO(marcus)  The YES button does nothing
                         <input type="submit" name="submit_delim" value="Select this Delimiter" class="ccs-hidden"/>
                       </label>
                       <label>
                         No
-			## TODO(marcus)  The NO + preview jump out of jframe
+                        ## TODO(marcus)  The NO + preview jump out of jframe
                         <input type="button" name="No" class="ccs-hidden"/>
                       </label>
                     </div>
                   % endif
                   <div class="bw-select_delim" class="ccs-hidden">
-		    ${comps.field(delim_form["delimiter"], render_default=True, help=r'Enter the column delimiter.  Must be a single character.  Use syntax like "\001" or "\t" for special characters.', klass="ccs-select-with-other")}
+                    ${comps.field(delim_form["delimiter"], render_default=True, help=r'Enter the column delimiter.  Must be a single character.  Use syntax like "\001" or "\t" for special characters.', klass="ccs-select-with-other")}
 
-		    <input class="ccs-hidden" type="submit" value="Preview" name="submit_preview"/>
-		    <input class="ccs-hidden" type="submit" value="Select this Delimiter" name="submit_delim"/>
+                    <input class="ccs-hidden" type="submit" value="Preview" name="submit_preview"/>
+                    <input class="ccs-hidden" type="submit" value="Select this Delimiter" name="submit_delim"/>
                   </div>
                   <div class="delimiter_preview_holder">
                     <table class="delimiter_preview">
-		      <thead>
-			<tr>
-			  % for i in range(n_cols):
-			    <th>col_${i+1}</th>
-			  % endfor
-			</tr>
-		      </thead>
-		      <tbody>
-			% for row in fields_list:
-			  <tr>
-			    % for val in row:
-			    <td>${val}</td>
-			    % endfor
-			  </tr>
-			% endfor
-		      </tbody>
+                      <thead>
+                        <tr>
+                          % for i in range(n_cols):
+                            <th>col_${i+1}</th>
+                          % endfor
+                        </tr>
+                      </thead>
+                      <tbody>
+                        % for row in fields_list:
+                          <tr>
+                            % for val in row:
+                            <td>${val}</td>
+                            % endfor
+                          </tr>
+                        % endfor
+                      </tbody>
                     </table>
                   </div>
                 </dt>
               </dl>
-	      <a class="ccs-form_submit ccs-visible ccs-multipart-next" data-extraData="{'submit_delim': 'Step 3: Define Your Columns'}">
+              <a class="ccs-submit_form ccs-visible ccs-multipart-next" data-extra-data="{'submit_delim': 'Step 3: Define Your Columns'}">
               Step 3: Define Your Columns&raquo;
               </a>
               <input type="submit" name="submit_delim" value="Step 3: Define Your Columns" class="ccs-hidden"/>

+ 2 - 2
apps/beeswax/src/beeswax/templates/choose_file.mako

@@ -63,10 +63,10 @@ ${wrappers.head('Choose a File')}
                   )}
                 </div>
                 ## TODO(marcus): Button style?
-                <a class="ccs-multipart-next ccs-form_submit ccs-visible" style="display:none" data-extraData="{'submit_file' : 'Step 2: Choose Your Delimiter'}">
+                <a class="ccs-multipart-next ccs-submit_form ccs-visible" style="display:none" data-extra-data="{'submit_file' : 'Step 2: Choose Your Delimiter'}">
                   Step 2: Choose Your Delimiter&raquo;
                 </a>
-                  <input type="submit" name="submit_file" value="Step 2: Choose Your Delimiter" class="ccs-hidden ccs-form_submit ccs-multipart-next ccs-visible"/>
+                  <input type="submit" name="submit_file" value="Step 2: Choose Your Delimiter" class="ccs-hidden ccs-submit_form ccs-multipart-next ccs-visible"/>
               </dl>
             </form>
           </dd>

+ 31 - 31
apps/beeswax/src/beeswax/templates/define_columns.mako

@@ -29,15 +29,15 @@ ${wrappers.head('Define Columns')}
   <div class="bw-define-columns">
     <form action="${action}" method="POST">
       <div class="ccs-hidden">
-	${util.render_form(file_form)}
-	${util.render_form(delim_form)}
-	${str(column_formset.management_form) | n}
+        ${util.render_form(file_form)}
+        ${util.render_form(delim_form)}
+        ${str(column_formset.management_form) | n}
       </div>
       <div class="ccs-bc-section">
       <dt> Step 3: Define Your Columns </dt>
       <%
-	n_rows = len(fields_list)
-	if n_rows > 2: n_rows = 2
+        n_rows = len(fields_list)
+        if n_rows > 2: n_rows = 2
       %>
       <dd>
           Beeswax has attempted to determine the types of your columns.  Please check them as you name the columns.
@@ -46,44 +46,44 @@ ${wrappers.head('Define Columns')}
           <dt> </dt>
           <dd>
             <table class="row_headers ccs-visible" style="display:none">
-	      % for i in range(n_rows):
-		<tr><td> Row ${i + 1} </td></tr>
-	      % endfor
+              % for i in range(n_rows):
+                <tr><td> Row ${i + 1} </td></tr>
+              % endfor
               <tr><td>&nbsp;</td></tr>
               <tr><td class="input_row_header"> Column Name </td></tr>
               <tr><td class="input_row_header"> Type </td></tr>
             </table>
             <div class="table_holder">
-	      <table class="data_table">
-		% for i, row in enumerate(fields_list[:n_rows]):
-		  <tr>
-		    <td class="ccs-hidden"> Row ${i + 1} </td>
-		    % for val in row:
-		      <td>${val}</td>
-		    % endfor
-		  </tr>
-		% endfor
+              <table class="data_table">
+                % for i, row in enumerate(fields_list[:n_rows]):
+                  <tr>
+                    <td class="ccs-hidden"> Row ${i + 1} </td>
+                    % for val in row:
+                      <td>${val}</td>
+                    % endfor
+                  </tr>
+                % endfor
                 <tr><td colspan="${n_cols}">&nbsp;</td></tr>
                 <tr>
-		  % for form in column_formset.forms:
-		    <td>
-		      ${comps.field(form["column_name"],
-			render_default=False,
-			help="Column name",
-		      )}
-		      ${comps.field(form["column_type"],
-			render_default=True,
-			help="Type for this column",
-		      )}
-		      ${str(form["_exists"]) | n}
-		    </td>
-		  %endfor
+                  % for form in column_formset.forms:
+                    <td>
+                      ${comps.field(form["column_name"],
+                        render_default=False,
+                        help="Column name",
+                      )}
+                      ${comps.field(form["column_type"],
+                        render_default=True,
+                        help="Type for this column",
+                      )}
+                      ${str(form["_exists"]) | n}
+                    </td>
+                  %endfor
                 </tr>
               </table>
             </div>
           </dd>
           </dl>
-          <a class="ccs-form_submit ccs-visible ccs-multipart-next" data-extraData="{'submit_create': 'Finish Creating Table'}" style="display:none">
+          <a class="ccs-submit_form ccs-visible ccs-multipart-next" data-extra-data="{'submit_create': 'Finish Creating Table'}" style="display:none">
           Finish Creating Table
           </a>
           <input type="submit" name="submit_create" value="Finish Creating Table" class="ccs-hidden"/>

+ 0 - 7
apps/beeswax/static/js/Source/Beeswax/CCS.Beeswax.js

@@ -85,13 +85,6 @@ ART.Sheet.define('splitview.bw-editor', {
 					sections.each(function(section) {
 						section.setStyle('display', show.contains(section) ? 'block' : 'none');
 					});
-				},
-				'.ccs-form_submit': function(event, el) {
-				/*
-					submit the form that the element is in.
-					el.getParent('form').formUpdate();
-				*/
-					el.getParent('form').retrieve('form.request').setOptions({extraData: el.getJSONData('extraData')}).send();
 				}
 			});
 			this.jframe.addFilters({

+ 2 - 2
apps/jframegallery/src/jframegallery/templates/context-menu.html

@@ -25,8 +25,8 @@ limitations under the License.
 			I show a menu if you right click anywhere in me. Or you can click <a class="show-options">this link</a> to show it.
 			<ul class="context-menu ccs-hidden">
 				<li class="cm-one">Item 1</li>
-				<li class="cm-two">Item 1</li>
-				<li class="cm-three">Item 1</li>
+				<li class="cm-two">Item 2</li>
+				<li class="cm-three">Item 3</li>
 			</ul>
 		</div>
 	</body>

+ 126 - 0
apps/jframegallery/src/jframegallery/templates/html-table.multi-select.menu.html

@@ -0,0 +1,126 @@
+{% comment %}
+Licensed to Cloudera, Inc. under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  Cloudera, Inc. licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+{% endcomment %}
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+	<head>
+		<title>HtmlTable Multi-Select Menu</title>
+	</head>
+	<body>
+		<div class="ccs-shared">
+			
+			<p>
+				Right click a row in the table below to get a menu. Select more than one row (hold shift) and right click and get a different menu.
+			</p>
+		
+		<table data-filters="HtmlTable, ContextMenu" class="multiselect selectable sortable" cellpadding="0" cellspacing="0"
+		data-context-menu-actions="[{'events':['contextmenu'], 'menu':'ul.table-context-menu'}]">
+			<ul class="table-context-menu context-menu ccs-hidden">
+				<li class="cm-one">multi-select option 1</li>
+				<li class="cm-two">multi-select option 2</li>
+				<li class="cm-three">multi-select option 3</li>
+			</ul>
+			<thead>
+				<tr>
+					<th>
+								ID
+					</th>
+					<th>
+								TimeZone
+					</th>
+					<th>
+								Name
+					</th>
+					<th>
+								GEO Latitude
+					</th>
+					<th>
+								GEO Longitude
+					</th>
+				</tr>
+			</thead>
+			<tbody>
+				<tr data-filters="ContextMenu" data-context-menu-actions="[{'events':['contextmenu','click:relay(a.show-options)'],'menu':'ul.context-menu'}]">
+					<ul class="context-menu ccs-hidden">
+						<li class="cm-one">Item 1</li>
+						<li class="cm-two">Item 2</li>
+						<li class="cm-three">Item 3</li>
+					</ul>
+					<td>
+						22
+					</td>
+					<td>
+						New York City
+					</td>
+					<td>
+						America/New_York
+					</td>
+					<td>
+						40.7255
+					</td>
+					<td>
+						-73.9983
+					</td>
+				</tr>
+				<tr data-filters="ContextMenu" data-context-menu-actions="[{'events':['contextmenu','click:relay(a.show-options)'],'menu':'ul.context-menu'}]">
+					<ul class="context-menu ccs-hidden">
+						<li class="cm-one">Item 1</li>
+						<li class="cm-two">Item 2</li>
+						<li class="cm-three">Item 3</li>
+					</ul>
+					<td>
+						23
+					</td>
+					<td>
+						San Francisco
+					</td>
+					<td>
+						America/Los_Angeles
+					</td>
+					<td>
+						37.7587
+					</td>
+					<td>
+						-122.433
+					</td>
+				</tr>
+				<tr data-filters="ContextMenu" data-context-menu-actions="[{'events':['contextmenu','click:relay(a.show-options)'],'menu':'ul.context-menu'}]">
+					<ul class="context-menu ccs-hidden">
+						<li class="cm-one">Item 1</li>
+						<li class="cm-two">Item 2</li>
+						<li class="cm-three">Item 3</li>
+					</ul>
+					<td>
+						24
+					</td>
+					<td>
+						Boston
+					</td>
+					<td>
+						America/New_York
+					</td>
+					<td>
+						42.3583
+					</td>
+					<td>
+						-71.0603
+					</td>
+				</tr>
+			</tbody>
+		</table>
+	</body>
+</html>

+ 57 - 0
apps/jframegallery/src/jframegallery/templates/submit.link.html

@@ -0,0 +1,57 @@
+{% comment %}
+Licensed to Cloudera, Inc. under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  Cloudera, Inc. licenses this file
+to you under the Apache License, Version 2.0 (the
+"License"); you may not use this file except in compliance
+with the License.  You may obtain a copy of the License at
+
+		http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+{% endcomment %}
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
+<html>
+	<head>
+		<title>Submit Links</title>
+	</head>
+	<body>
+
+		<p>Click either submit button to update the box below. The box should have an ajax spinner and then update with the content in the button.</p>
+
+		<form action="/jframegallery/submit.link.html" method="post" style="margin: 6px 0px 0px;">
+			<input type="submit" name="button" value="fetch html (button 1)"/>
+			<input type="submit" name="button" value="fetch html (button 2)"/>
+			<a class="ccs-submit_form" data-extra-data="{'link':'fetch html (link 1)'}">fetch html (link 1)</a>
+			<a class="ccs-submit_form" data-extra-data="{'link':'fetch html (link 2)'}">fetch html (link 2)</a>
+		</form>
+
+		<div style="position: relative; margin-top: 10px">
+			<div id="update" style="padding: 10px; width: 200px; border: 1px solid black; height: 100px; overflow:hidden;">
+				{% if post_vars %}
+					<div class="jframe_padded">
+						You submitted the following values:
+						<ul>
+							{% for post_var, val in post_vars %}
+							 <li>{{post_var}}: {{val}}</li>
+							{% endfor %}
+						</ul>
+					</div>
+				{% else %}
+					this box should get new text when you click the input above.
+				{% endif %}
+			</div>
+		</div>
+
+		<script src="/depender/build?require=Widgets/Behavior.FormRequest,More/Spinner"></script>
+		<script>
+		new Behavior().apply(document.body);
+		</script>
+
+	</body>
+</html>

+ 2 - 0
desktop/core/static/js/Source/BehaviorFilters/Behavior.ContextMenu.js

@@ -33,6 +33,7 @@ var JframeContextMenu = new Class({
 		this.applyDelegates = this.options.applyDelegates;
 	},
 	show: function(x, y){
+		if (this.disabled || !this.activeMenu) return;
 		//when the menu is shown, put the place holder after the menu
 		this._placeHolder.inject(this.activeMenu, 'after');
 		//move the menu into the container
@@ -42,6 +43,7 @@ var JframeContextMenu = new Class({
 		this.parent(x, y);
 	},
 	hide: function(){
+		if (this.disabled || !this.activeMenu) return;
 		//when we hide the menu, put the menu back where it was and pop the placeholder out of the DOM
 		this.activeMenu.inject(this._placeHolder, 'after');
 		this._placeHolder.dispose();

+ 6 - 6
desktop/core/static/js/Source/BehaviorFilters/Behavior.FilterInput.js

@@ -33,13 +33,13 @@ Behavior.addGlobalFilters({
 	FilterInput: function(element, methods){
 		var container = methods.getContentElement();
 		//this method will find all the elements and check them for the value
+		var selector = element.get('data', 'filter-elements');
+		if (!selector) {
+			dbug.warn('warning, there was no selector defined for data-filter-elements for this element: ', element);
+			return;
+		}
+		var filterParents = element.get('data', 'filter-parents');
 		var filter = function (){
-			var selector = element.get('data', 'filter-elements');
-			var filterParents = element.get('data', 'filter-parents');
-			if (!selector) {
-				dbug.warn('warning, there was no selector defined for data-filter-elements for this element: ', element);
-				return;
-			}
 			var elements = container.getElements(selector);
 			if (!elements.length) {
 				dbug.warn('warning, this filter element %o has data-filter-elements selector defined as %s but this selector matches no elements.', element, selector);

+ 32 - 0
desktop/core/static/js/Source/BehaviorFilters/Behavior.HtmlTableKeyboard.js

@@ -0,0 +1,32 @@
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+/*
+---
+description: Makes form validator instances scroll the jframe to the errors.
+provides: [Behavior.HtmlTableKeyboard]
+requires: [Widgets/Behavior.HtmlTable]
+script: Behavior.HtmlTableKeyboard.js
+...
+*/
+
+Behavior.addGlobalPlugin('HtmlTable', 'HtmlTableJFrame', function(element, methods){
+
+	var table = element.retrieve('HtmlTable');
+	if (table.keyboard) {
+		methods.registerKeyboard(table.keyboard);
+		this.markForCleanup(element, function(){
+			methods.unregisterKeyboard(table.keyboard);
+		});
+	}
+
+});

+ 65 - 0
desktop/core/static/js/Source/BehaviorFilters/Behavior.HtmlTableMultiSelectMenu.js

@@ -0,0 +1,65 @@
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+/*
+---
+description: Adds support for HtmlTable context menus for multiple selected rows.
+provides: [Behavior.HtmlTableMultiSelectMenu]
+requires: [Widgets/Behavior.HtmlTable, /Behavior.ContextMenu]
+script: Behavior.HtmlTableMultiSelectMenu.js
+...
+*/
+Behavior.addGlobalPlugin('HtmlTable', 'HtmlTableMutiSelect', function(element, methods){
+	var table = element.retrieve('HtmlTable');
+	var previousSelected;
+	//check if the table has a context menu for bulk edits
+	//and we can multi-select things
+	if (table.options.allowMultiSelect && element.hasDataFilter('ContextMenu')) {
+		//wait for a short period to get the table's context menu; we have no guarantee
+		//that its been created before this filter runs
+		var menu;
+		(function(){
+			menu = element.retrieve('ContextMenu');
+			if (menu) menu.disable();
+		}).delay(10);
+		//when the user selects a row
+		table.addEvent('rowFocus', function(row, selectedRows){
+			//if there is no context menu on the table, then exit
+			if (!menu) return;
+			var action;
+			//if there were a previously selected group of menus, re-enable them.
+			if (previousSelected) {
+				previousSelected.each(function(menu){
+					menu.enable();
+				});
+				previousSelected.empty();
+			}
+			//if the user has selected more than one row
+			if (selectedRows.length > 1) {
+				//enable the table's menu
+				menu.enable();
+				//loop through the selected rows and disable their menus
+				//this allows the right click event to travel past the table row level and up to the table
+				//so the bulk action menu is displayed
+				previousSelected = selectedRows.map(function(tr){
+					var menu = tr.retrieve('ContextMenu');
+					if (menu) menu.disable();
+					return menu;
+				}).clean();
+			} else {
+				//otherwise, if there aren't multiple rows selected, disable the table's menu
+				menu.disable();
+			}
+		});
+	}
+
+});

+ 31 - 14
desktop/core/static/js/Source/CCS/CCS.ContextMenu.js

@@ -48,8 +48,12 @@ script: CCS.ContextMenu.js
 	document.addEvents({
 		mousedown: function(e) {
 			//if there is a menu visible, hide it on any click
-			var active = $(CCS.ContextMenu.active);
-			if (active && e.target != active && !active.hasChild(e.target)) CCS.ContextMenu.active.hide();
+			var menu = CCS.ContextMenu.active;
+			var active = $(menu);
+			if (active && e.target != active && !active.hasChild(e.target)) {
+				active.hide();
+				menu.fireEvent('hide', active);
+			}
 		}.bind(this),
 		keyup: function(e) {
 			//or if the user hits escape
@@ -64,7 +68,10 @@ script: CCS.ContextMenu.js
 		},
 		initialize: function(delegate, options){
 			this.setOptions(options);
-			this.delegate = $(delegate);
+			this.delegate = $(delegate).store('ContextMenu', this);
+			this._eventStopper = function(){
+				if (this.disabled) return false;
+			};
 			this.attach();
 		},
 		detachers: [],
@@ -81,9 +88,9 @@ script: CCS.ContextMenu.js
 						//if there is no menu, but there was data, we want to kill right-click support
 						//on this element; we assume that the right-click behavior is still intended,
 						//but there's simply no menu
-						this.delegate.addEvent('contextmenu', eventStopper);
+						this.delegate.addEvent('contextmenu', this._eventStopper);
 						this.detachers.push(function(){
-							this.delegate.removeEvent('contextmenu', eventStopper);
+							this.delegate.removeEvent('contextmenu', this._eventStopper);
 						}.bind(this));
 						return;
 					}
@@ -94,17 +101,19 @@ script: CCS.ContextMenu.js
 						click: this.hide.bind(this)
 					});
 					this.detachers.push(function(){
-						menu.removeEvent('contextmenu', eventStopper);
-					});
+						menu.removeEvent('contextmenu', this._eventStopper);
+					}.bind(this));
 					//for each event defined in the data, delegate that event to the container
 					//contextmenu, click:relay(selector), etc
 					data.events.each(function(event) {
 						events[event] = function(e){
-							e.preventDefault();
-							//let's only show one menu like this at a time
-							this.activeMenu = menu;
-							//put the menu on the mouse
-							this.show(e.page.x, e.page.y);
+							if (!this.disabled) {
+								e.preventDefault();
+								//let's only show one menu like this at a time
+								this.activeMenu = menu;
+								//put the menu on the mouse
+								this.show(e.page.x, e.page.y);
+							}
 						}.bind(this);
 					}, this);
 					this.delegate.addEvents(events);
@@ -120,14 +129,21 @@ script: CCS.ContextMenu.js
 				fn();
 			});
 		},
+		disable: function(){
+			this.hide();
+			this.disabled = true;
+		},
+		enable: function(){
+			this.disabled = false;
+		},
 		toElement: function(){
 			return this.activeMenu;
 		},
 		//shows the menu at the given x/y position
 		show: function(x, y){
+			if (this.disabled) return;
 			//if there is a menu visible, hide it on any click
 			if (CCS.ContextMenu.active && CCS.ContextMenu.active != this) CCS.ContextMenu.active.hide();
-			
 			if (this.activeMenu) {
 				this.activeMenu.show();
 				this.position(x, y);
@@ -157,11 +173,12 @@ script: CCS.ContextMenu.js
 		},
 		//hides the active menu
 		hide: function(){
+			if (this.disabled) return;
 			var menu = this.activeMenu;
 			if (menu) menu.hide();
 			this.activeMenu = null;
 			if (CCS.ContextMenu.active == this) CCS.ContextMenu.active = null;
-			this.fireEvent('hide', menu);
+			if (menu) this.fireEvent('hide', menu);
 		}
 	});
 

+ 24 - 23
desktop/core/static/js/Source/CCS/CCS.JBrowser.js

@@ -21,39 +21,40 @@ requires:
  - /CCS.JFrame
  - Widgets/ART.Browser
  - Widgets/ART.SolidWindow
+ - /CCS.JFrame.Alert
+ - /CCS.JFrame.ArtButtons
  - /CCS.JFrame.AutoRefresh
+ - /CCS.JFrame.CheckAllOrNone
+ - /CCS.JFrame.Chooser
  - /CCS.JFrame.Collapsible
- - /CCS.JFrame.DoubleClickDelegate
- - /CCS.JFrame.HtmlTable
- - /CCS.JFrame.OverText
- - /CCS.JFrame.SubmitOnChange
+ - /CCS.JFrame.ConfirmAndPost
  - /CCS.JFrame.ContextMenu
+ - /CCS.JFrame.DataGroupToggle
+ - /CCS.JFrame.DoubleClickDelegate
+ - /CCS.JFrame.FakeRefresh
+ - /CCS.JFrame.FilterInput
  - /CCS.JFrame.FormRequest
- - /CCS.JFrame.NoOverflow
- - /CCS.JFrame.SplitView
- - /CCS.JFrame.Tabs
+ - /CCS.JFrame.FormValidator
  - /CCS.JFrame.FitText
- - /CCS.JFrame.ConfirmAndPost
+ - /CCS.JFrame.HtmlTable
+ - /CCS.JFrame.Input
+ - /CCS.JFrame.Nav
+ - /CCS.JFrame.NoOverflow
+ - /CCS.JFrame.OverText
+ - /CCS.JFrame.PartialRefresh
+ - /CCS.JFrame.Prompt
  - /CCS.JFrame.PromptAndPost
  - /CCS.JFrame.Refresh
+ - /CCS.JFrame.SelectWithOther
+ - /CCS.JFrame.SideBySideSelect
  - /CCS.JFrame.SizeTo
- - /CCS.JFrame.FilterInput
- - /CCS.JFrame.FakeRefresh
+ - /CCS.JFrame.SplitView
+ - /CCS.JFrame.SubmitLink
+ - /CCS.JFrame.SubmitOnChange
+ - /CCS.JFrame.Tabs
  - /CCS.JFrame.Target
- - /CCS.JFrame.Chooser
- - /CCS.JFrame.Alert
- - /CCS.JFrame.Prompt
- - /CCS.JFrame.PartialRefresh
- - /CCS.JFrame.ArtButtons
- - /CCS.JFrame.SideBySideSelect
- - /CCS.JFrame.CheckAllOrNone
- - /CCS.JFrame.FormValidator
- - /CCS.JFrame.DataGroupToggle
- - /CCS.JFrame.ToggleHistory
- - /CCS.JFrame.Nav
  - /CCS.JFrame.Tips
- - /CCS.JFrame.SelectWithOther
- - /CCS.JFrame.Input
+ - /CCS.JFrame.ToggleHistory
 script: CCS.JBrowser.js
 
 ...

+ 9 - 0
desktop/core/static/js/Source/CCS/CCS.JFrame.js

@@ -33,6 +33,7 @@ requires:
  - Widgets/Behavior
  - Widgets/Behavior.ArtButton
  - Widgets/Behavior.ArtInput
+ - Widgets/Behavior.FormRequest
  - Widgets/Behavior.FormValidator
  - Widgets/Behavior.HtmlTable
  - Widgets/Behavior.OverText
@@ -40,6 +41,8 @@ requires:
  - /Behavior.ContextMenu
  - /Behavior.FilterInput
  - /Behavior.FitText
+ - /Behavior.HtmlTableKeyboard
+ - /Behavior.HtmlTableMultiSelectMenu
  - /Behavior.MultiChecks
  - /Behavior.SideBySideSelect
  - /Behavior.SizeTo
@@ -133,6 +136,12 @@ CCS.JFrame = new Class({
 						this._requestSuccessHandler(request, text);
 					}.bind(this)
 				});
+			}.bind(this),
+			registerKeyboard: function(keyboard){
+				this.keyboard.manage(keyboard);
+			}.bind(this),
+			unregisterKeyboard: function(keyboard){
+				this.keyboard.drop(keyboard);
 			}.bind(this)
 		});
 		this.addEvent('resize', this.behavior.resize.bind(this.behavior));

+ 35 - 0
desktop/core/static/js/Source/JFrameLinkers/CCS.JFrame.SubmitLink.js

@@ -0,0 +1,35 @@
+// Licensed to Cloudera, Inc. under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  Cloudera, Inc. licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+/*
+---
+description: When the user clicks a link with the class '.ccs-submit_form' submit the parent form.
+provides: [CCS.JFrame.SubmitLink]
+requires: [/CCS.JFrame]
+script: CCS.JFrame.SubmitLink.js
+
+...
+*/
+
+CCS.JFrame.addGlobalLinkers({
+	/*
+		submit the form that the element is in.
+	*/
+	'.ccs-submit_form': function(event, el) {
+		el.getParent('form').retrieve('form.request').setOptions({extraData: el.getJSONData('extra-data')}).send();
+	}
+
+});

+ 7 - 4
desktop/core/static/js/package.yml

@@ -38,14 +38,15 @@ sources: [
   Source/UI/StickyWin.Drawer.js,
   Source/UI/StickyWin.UI.Solid.js,
   Source/UI/ThumbTack.js,
-  Source/JFrameLinkers/CCS.JFrame.Target.js,
   Source/JFrameLinkers/CCS.JFrame.CheckAllOrNone.js,
+  Source/JFrameLinkers/CCS.JFrame.Chooser.js,
+  Source/JFrameLinkers/CCS.JFrame.ConfirmAndPost.js,
+  Source/JFrameLinkers/CCS.JFrame.FakeRefresh.js,
   Source/JFrameLinkers/CCS.JFrame.Nav.js,
   Source/JFrameLinkers/CCS.JFrame.PromptAndPost.js,
-  Source/JFrameLinkers/CCS.JFrame.ConfirmAndPost.js,
   Source/JFrameLinkers/CCS.JFrame.Refresh.js,
-  Source/JFrameLinkers/CCS.JFrame.FakeRefresh.js,
-  Source/JFrameLinkers/CCS.JFrame.Chooser.js,
+  Source/JFrameLinkers/CCS.JFrame.SubmitLink.js,
+  Source/JFrameLinkers/CCS.JFrame.Target.js,
   Source/Native/String.CCS.js,
   Source/Native/Element.Data.js,
   Source/StaticThirdParty/DynamicTextarea.js,
@@ -54,6 +55,8 @@ sources: [
   Source/BehaviorFilters/Behavior.ContextMenu.js,
   Source/BehaviorFilters/Behavior.FilterInput.js,
   Source/BehaviorFilters/Behavior.FitText.js,
+  Source/BehaviorFilters/Behavior.HtmlTableMultiSelectMenu.js,
+  Source/BehaviorFilters/Behavior.HtmlTableKeyboard.js,
   Source/BehaviorFilters/Behavior.MultiChecks.js,
   Source/BehaviorFilters/Behavior.SideBySideSelect.js,
   Source/BehaviorFilters/Behavior.SizeTo.js,

+ 1 - 1
ext/thirdparty/js/art-widgets.hash

@@ -1 +1 @@
-4d07560e1defc325ef10b92d968d6472d87db133
+a55bab170a37fb0f855a8d291460ce7a07dc92f3

+ 1 - 1
ext/thirdparty/js/mootools-more.hash

@@ -1 +1 @@
-4074ee73688f1e70ce22176d83d2a2fb8af983e6
+a89b413b51aaaf425514c8ec7e77596a787cbede