From a5c6a3af3458a57376694bcecbc714597f5f0cd9 Mon Sep 17 00:00:00 2001 From: David Huynh Date: Mon, 18 Oct 2010 01:07:35 +0000 Subject: [PATCH] Support ESC key to dismiss menus and dialogs (which required jquery eventstack plugin). Updated binding names in project.vt so that the bound HTML elements are distinguished from the JS objects that manage them (e.g., summarBarDiv vs summaryBar). git-svn-id: http://google-refine.googlecode.com/svn/trunk@1591 7d457c2a-affb-35e4-300a-418c747d4874 --- .../webapp/modules/core/MOD-INF/controller.js | 1 + main/webapp/modules/core/about.html | 3 + .../core/externals/jquery.eventstack-0.3.js | 94 +++++++++++++++++++ main/webapp/modules/core/project.vt | 18 ++-- main/webapp/modules/core/scripts/project.js | 30 +++--- .../modules/core/scripts/util/dialog.js | 18 ++++ main/webapp/modules/core/scripts/util/menu.js | 17 ++++ 7 files changed, 157 insertions(+), 24 deletions(-) create mode 100644 main/webapp/modules/core/externals/jquery.eventstack-0.3.js diff --git a/main/webapp/modules/core/MOD-INF/controller.js b/main/webapp/modules/core/MOD-INF/controller.js index d2436495e..6fb92889d 100644 --- a/main/webapp/modules/core/MOD-INF/controller.js +++ b/main/webapp/modules/core/MOD-INF/controller.js @@ -164,6 +164,7 @@ function init() { [ "externals/jquery-1.4.2.min.js", "externals/jquery.cookie.js", + "externals/jquery.eventstack-0.3.js", "externals/suggest/suggest-1.2.1.min.js", "externals/jquery-ui/jquery-ui-1.8.custom.min.js", "externals/imgareaselect/jquery.imgareaselect.js", diff --git a/main/webapp/modules/core/about.html b/main/webapp/modules/core/about.html index 0c9e01f5f..1cf324a38 100644 --- a/main/webapp/modules/core/about.html +++ b/main/webapp/modules/core/about.html @@ -125,6 +125,9 @@ licenses/jquery.LICENSE.txt licenses/jquery_ui.LICENSE.txt jquery_ui + +licenses/jquery.eventstack.LICENSE.txt + jquery eventstack licenses/datejs.LICENSE.txt datejs diff --git a/main/webapp/modules/core/externals/jquery.eventstack-0.3.js b/main/webapp/modules/core/externals/jquery.eventstack-0.3.js new file mode 100644 index 000000000..a13298be4 --- /dev/null +++ b/main/webapp/modules/core/externals/jquery.eventstack-0.3.js @@ -0,0 +1,94 @@ +/** + * Copyright (c) 2008, Ben XO + * + * Dual licensed under the MIT (MIT-LICENSE.txt) + * and GPL (GPL-LICENSE.txt) licenses. + * + * + * This is a jQuery plugin that allows events to be handled in reverse order of + * binding - add events to the head of the queue rather than the end. + * + * Particularly useful if you apply your "do"s in a modular order and wish to + * apply your "undo"s in reverse order. + * + * It adds the following two methods: + * + * reverse(event): reverses the order that functions attached to are + * applied to this element. + * + * stack( event, data, fn ): just like bind(), except adds to the front of the + * event queue instead of the end. + * + * Also, every event method (.click(), .focus(), .resize(), .submit(), etc - + * 21 methods in all) can take an extra parameter "reverse" that controls if + * the event is added to the front or end of the event queue. For example: + * + * $("body").click(function() { alert("1"); }); + * $("body").click(function() { alert("2"); }); + * $("body").click(function() { alert("3"); }, true); + * + * ... will show "3", "1" then "2" when the document is clicked. + * + * @version 0.3 + */ + +jQuery.fn.extend({ + + // reverse the order of events bound to an element + reverse: function( event ) { + var events = this.data("events"); + if ( events != undefined && events[event] != undefined) { + // can't reverse what's not there + var reverseEvent = new Array; + for (var e in events[event]) { + reverseEvent.unshift(events[event][e]); + } + events[event] = reverseEvent; + } + return this; + }, + + // add an event to the front of an event queue rather than the back + // we do this by reversing the queue, adding, then reversing again + stack: function( event, data, fn ) { + return this + .reverse( event ) + .bind( event, data, fn ) + .reverse( event ) + ; + }, + + hover: function( fnOver, fnOut, reverse ) { + if(reverse) { + return this + .stack('mouseenter', fnOver) + .stack('mouseleave', fnOut) + ; + } else { + return this + .bind('mouseenter', fnOver) + .bind('mouseleave', fnOut) + ; + } + } +}); + +// every event handler - blur(), focus(), click() etc now has a 2nd param which +// if true will add the passed function to the beginning of the event list +// instead of the end +jQuery.each( ("blur,focus,load,resize,scroll,unload,click,dblclick," + + "mousedown,mouseup,mousemove,mouseover,mouseout,change,select," + + "submit,keydown,keypress,keyup,error").split(","), function(i, name){ + + // Handle event binding + jQuery.fn[name] = function(fn, reverse){ + if(fn) { + return reverse ? + this.stack(name, fn) : + this.bind(name, fn) + ; + } else { + return this.trigger(name); + } + }; +}); \ No newline at end of file diff --git a/main/webapp/modules/core/project.vt b/main/webapp/modules/core/project.vt index faa02fc20..4c72ab70c 100644 --- a/main/webapp/modules/core/project.vt +++ b/main/webapp/modules/core/project.vt @@ -22,28 +22,28 @@
Starting up...
-
+ -
-
-
+
+
+
-
+
Extensions:
-
+
-
+
diff --git a/main/webapp/modules/core/scripts/project.js b/main/webapp/modules/core/scripts/project.js index 8d46f6236..594d3b99c 100644 --- a/main/webapp/modules/core/scripts/project.js +++ b/main/webapp/modules/core/scripts/project.js @@ -19,34 +19,34 @@ function resize() { var top = $("#header").outerHeight(); var height = $(window).height() - top; - var leftPanelPaddings = ui.leftPanel.outerHeight(true) - ui.leftPanel.height(); - ui.leftPanel + var leftPanelPaddings = ui.leftPanelDiv.outerHeight(true) - ui.leftPanelDiv.height(); + ui.leftPanelDiv .css("top", top + "px") .css("left", "0px") .css("height", (height - leftPanelPaddings) + "px") .css("width", leftPanelWidth + "px"); var leftPanelTabsPaddings = ui.leftPanelTabs.outerHeight(true) - ui.leftPanelTabs.height(); - ui.leftPanelTabs.height(ui.leftPanel.height() - leftPanelTabsPaddings); + ui.leftPanelTabs.height(ui.leftPanelDiv.height() - leftPanelTabsPaddings); - var rightPanelVPaddings = ui.rightPanel.outerHeight(true) - ui.rightPanel.height(); - var rightPanelHPaddings = ui.rightPanel.outerWidth(true) - ui.rightPanel.width(); - ui.rightPanel + var rightPanelVPaddings = ui.rightPanelDiv.outerHeight(true) - ui.rightPanelDiv.height(); + var rightPanelHPaddings = ui.rightPanelDiv.outerWidth(true) - ui.rightPanelDiv.width(); + ui.rightPanelDiv .css("top", top + "px") .css("left", leftPanelWidth + "px") .css("height", (height - rightPanelVPaddings) + "px") .css("width", (width - leftPanelWidth - rightPanelHPaddings) + "px"); - ui.viewPanel.height((height - ui.toolPanel.outerHeight() - rightPanelVPaddings) + "px"); + ui.viewPanelDiv.height((height - ui.toolPanelDiv.outerHeight() - rightPanelVPaddings) + "px"); var processPanelWidth = 400; - ui.processPanel + ui.processPanelDiv .css("width", processPanelWidth + "px") .css("left", Math.floor((width - processPanelWidth) / 2) + "px"); } function resizeTabs() { - var totalHeight = ui.leftPanel.height(); + var totalHeight = ui.leftPanelDiv.height(); var headerHeight = ui.leftPanelTabs.find(".ui-tabs-nav").outerHeight(true); var visibleTabPanels = ui.leftPanelTabs.find(".ui-tabs-panel:not(.ui-tabs-hide)"); @@ -81,18 +81,18 @@ function initializeUI(uiState) { ui = DOM.bind($("#body")); - ui.extensionBar = new ExtensionBar(ui.extensionBar); // construct the menu first so we can resize everything else + ui.extensionBar = new ExtensionBar(ui.extensionBarDiv); // construct the menu first so we can resize everything else ui.exporterManager = new ExporterManager($("#export-button")); ui.leftPanelTabs.tabs({ selected: 0 }); resize(); resizeTabs(); - ui.summaryBar = new SummaryBar(ui.summaryBar); - ui.browsingEngine = new BrowsingEngine(ui.facetPanel, uiState.facets || []); - ui.processPanel = new ProcessPanel(ui.processPanel); - ui.historyPanel = new HistoryPanel(ui.historyPanel, ui.historyTabHeader); - ui.dataTableView = new DataTableView(ui.viewPanel); + ui.summaryBar = new SummaryBar(ui.summaryBarDiv); + ui.browsingEngine = new BrowsingEngine(ui.facetPanelDiv, uiState.facets || []); + ui.processPanel = new ProcessPanel(ui.processPanelDiv); + ui.historyPanel = new HistoryPanel(ui.historyPanelDiv, ui.historyTabHeader); + ui.dataTableView = new DataTableView(ui.viewPanelDiv); ui.leftPanelTabs.bind('tabsshow', function(event, tabs) { if (tabs.index === 0) { diff --git a/main/webapp/modules/core/scripts/util/dialog.js b/main/webapp/modules/core/scripts/util/dialog.js index 1f10a14a8..711408b2e 100644 --- a/main/webapp/modules/core/scripts/util/dialog.js +++ b/main/webapp/modules/core/scripts/util/dialog.js @@ -27,6 +27,21 @@ DialogSystem.showDialog = function(elmt, onCancel) { DialogSystem._layers.push(layer); var level = DialogSystem._layers.length; + + layer.keyHandler = function(evt) { + if (evt.keyCode == 27 && !evt.shiftKey && !evt.metaKey && !evt.altKey && !evt.ctrlKey && + evt.target.tagName.toLowerCase() != "input" && + evt.target.tagName.toLowerCase() != "textarea") { + + DialogSystem.dismissUntil(level - 1); + evt.stopImmediatePropagation(); + evt.stopPropagation(); + evt.preventDefault(); + return false; + } + }; + $(document).stack("keydown", layer.keyHandler); + return level; }; @@ -37,6 +52,9 @@ DialogSystem.dismissAll = function() { DialogSystem.dismissUntil = function(level) { for (var i = DialogSystem._layers.length - 1; i >= level; i--) { var layer = DialogSystem._layers[i]; + + $(document).unbind("keydown", layer.keyHandler); + layer.overlay.remove(); layer.container.remove(); layer.container.unbind(); diff --git a/main/webapp/modules/core/scripts/util/menu.js b/main/webapp/modules/core/scripts/util/menu.js index 540f73d04..c41404758 100644 --- a/main/webapp/modules/core/scripts/util/menu.js +++ b/main/webapp/modules/core/scripts/util/menu.js @@ -17,10 +17,24 @@ MenuSystem.showMenu = function(elmt, onDismiss) { elmt: elmt, onDismiss: onDismiss }; + MenuSystem._layers.push(layer); var level = MenuSystem._layers.length; + layer.keyHandler = function(evt) { + if (evt.keyCode == 27 && !evt.shiftKey && !evt.metaKey && !evt.altKey && !evt.ctrlKey && + evt.target.tagName.toLowerCase() != "input" && + evt.target.tagName.toLowerCase() != "textarea") { + MenuSystem.dismissUntil(level - 1); + evt.stopImmediatePropagation(); + evt.stopPropagation(); + evt.preventDefault(); + return false; + } + }; + $(document).stack("keydown", layer.keyHandler); + return level; }; @@ -35,6 +49,9 @@ MenuSystem.dismissAll = function() { MenuSystem.dismissUntil = function(level) { for (var i = MenuSystem._layers.length - 1; i >= level; i--) { var layer = MenuSystem._layers[i]; + + $(document).unbind("keydown", layer.keyHandler); + layer.elmt.remove(); layer.elmt.unbind(); layer.onDismiss();