diff --git a/attachments/pages/index.html b/attachments/pages/index.html
index e4755c06..df30df64 100644
--- a/attachments/pages/index.html
+++ b/attachments/pages/index.html
@@ -9,8 +9,10 @@
+
+
diff --git a/attachments/script/jquery.hotkeys.js b/attachments/script/jquery.hotkeys.js
new file mode 100644
index 00000000..fbd71c71
--- /dev/null
+++ b/attachments/script/jquery.hotkeys.js
@@ -0,0 +1,99 @@
+/*
+ * jQuery Hotkeys Plugin
+ * Copyright 2010, John Resig
+ * Dual licensed under the MIT or GPL Version 2 licenses.
+ *
+ * Based upon the plugin by Tzury Bar Yochay:
+ * http://github.com/tzuryby/hotkeys
+ *
+ * Original idea by:
+ * Binny V A, http://www.openjs.com/scripts/events/keyboard_shortcuts/
+*/
+
+(function(jQuery){
+
+ jQuery.hotkeys = {
+ version: "0.8",
+
+ specialKeys: {
+ 8: "backspace", 9: "tab", 13: "return", 16: "shift", 17: "ctrl", 18: "alt", 19: "pause",
+ 20: "capslock", 27: "esc", 32: "space", 33: "pageup", 34: "pagedown", 35: "end", 36: "home",
+ 37: "left", 38: "up", 39: "right", 40: "down", 45: "insert", 46: "del",
+ 96: "0", 97: "1", 98: "2", 99: "3", 100: "4", 101: "5", 102: "6", 103: "7",
+ 104: "8", 105: "9", 106: "*", 107: "+", 109: "-", 110: ".", 111 : "/",
+ 112: "f1", 113: "f2", 114: "f3", 115: "f4", 116: "f5", 117: "f6", 118: "f7", 119: "f8",
+ 120: "f9", 121: "f10", 122: "f11", 123: "f12", 144: "numlock", 145: "scroll", 191: "/", 224: "meta"
+ },
+
+ shiftNums: {
+ "`": "~", "1": "!", "2": "@", "3": "#", "4": "$", "5": "%", "6": "^", "7": "&",
+ "8": "*", "9": "(", "0": ")", "-": "_", "=": "+", ";": ": ", "'": "\"", ",": "<",
+ ".": ">", "/": "?", "\\": "|"
+ }
+ };
+
+ function keyHandler( handleObj ) {
+ // Only care when a possible input has been specified
+ if ( typeof handleObj.data !== "string" ) {
+ return;
+ }
+
+ var origHandler = handleObj.handler,
+ keys = handleObj.data.toLowerCase().split(" ");
+
+ handleObj.handler = function( event ) {
+ // Don't fire in text-accepting inputs that we didn't directly bind to
+ if ( this !== event.target && (/textarea|select/i.test( event.target.nodeName ) ||
+ event.target.type === "text") ) {
+ return;
+ }
+
+ // Keypress represents characters, not special keys
+ var special = event.type !== "keypress" && jQuery.hotkeys.specialKeys[ event.which ],
+ character = String.fromCharCode( event.which ).toLowerCase(),
+ key, modif = "", possible = {};
+
+ // check combinations (alt|ctrl|shift+anything)
+ if ( event.altKey && special !== "alt" ) {
+ modif += "alt+";
+ }
+
+ if ( event.ctrlKey && special !== "ctrl" ) {
+ modif += "ctrl+";
+ }
+
+ // TODO: Need to make sure this works consistently across platforms
+ if ( event.metaKey && !event.ctrlKey && special !== "meta" ) {
+ modif += "meta+";
+ }
+
+ if ( event.shiftKey && special !== "shift" ) {
+ modif += "shift+";
+ }
+
+ if ( special ) {
+ possible[ modif + special ] = true;
+
+ } else {
+ possible[ modif + character ] = true;
+ possible[ modif + jQuery.hotkeys.shiftNums[ character ] ] = true;
+
+ // "$" can be triggered as "Shift+4" or "Shift+$" or just "$"
+ if ( modif === "shift+" ) {
+ possible[ jQuery.hotkeys.shiftNums[ character ] ] = true;
+ }
+ }
+
+ for ( var i = 0, l = keys.length; i < l; i++ ) {
+ if ( possible[ keys[i] ] ) {
+ return origHandler.apply( this, arguments );
+ }
+ }
+ };
+ }
+
+ jQuery.each([ "keydown", "keyup", "keypress" ], function() {
+ jQuery.event.special[ this ] = { add: keyHandler };
+ });
+
+})( jQuery );
\ No newline at end of file
diff --git a/attachments/script/microevent.js b/attachments/script/microevent.js
new file mode 100644
index 00000000..3e74d026
--- /dev/null
+++ b/attachments/script/microevent.js
@@ -0,0 +1,50 @@
+/**
+ * MicroEvent - to make any js object an event emitter (server or browser)
+ *
+ * - pure javascript - server compatible, browser compatible
+ * - dont rely on the browser doms
+ * - super simple - you get it immediatly, no mistery, no magic involved
+ *
+ * - create a MicroEventDebug with goodies to debug
+ * - make it safer to use
+*/
+
+var MicroEvent = function(){}
+MicroEvent.prototype = {
+ on : function(event, fct){
+ this._events = this._events || {};
+ this._events[event] = this._events[event] || [];
+ this._events[event].push(fct);
+ },
+ clear : function(event, fct){
+ this._events = this._events || {};
+ if( event in this._events === false ) return;
+ this._events[event].splice(this._events[event].indexOf(fct), 1);
+ },
+ trigger : function(event /* , args... */){
+ this._events = this._events || {};
+ if( event in this._events === false ) return;
+ for(var i = 0; i < this._events[event].length; i++){
+ this._events[event][i].apply(this, Array.prototype.slice.call(arguments, 1))
+ }
+ }
+};
+
+/**
+ * mixin will delegate all MicroEvent.js function in the destination object
+ *
+ * - require('MicroEvent').mixin(Foobar) will make Foobar able to use MicroEvent
+ *
+ * @param {Object} the object which will support MicroEvent
+*/
+MicroEvent.mixin = function(destObject){
+ var props = ['on', 'clear', 'trigger'];
+ for(var i = 0; i < props.length; i ++){
+ destObject.prototype[props[i]] = MicroEvent.prototype[props[i]];
+ }
+}
+
+// export in common js
+if( typeof module !== "undefined" && ('exports' in module)){
+ module.exports = MicroEvent
+}
\ No newline at end of file
diff --git a/attachments/script/removalist.js b/attachments/script/removalist.js
index 6b313161..cb11bad8 100644
--- a/attachments/script/removalist.js
+++ b/attachments/script/removalist.js
@@ -118,6 +118,9 @@ var removalist = function() {
}
function bootstrap() {
+ util.registerEmitter();
+ util.listenFor(["esc"]);
+
couch.request({url: app.baseURL + "api"}).then(function( dbInfo ) {
app.dbInfo = dbInfo;
diff --git a/attachments/script/site.js b/attachments/script/site.js
index ffdbd74c..e55d4f78 100644
--- a/attachments/script/site.js
+++ b/attachments/script/site.js
@@ -83,14 +83,18 @@ app.after = {
exportActions: removalist.handleMenuClick,
columnActions: removalist.handleMenuClick,
signIn: function() {
+
+ util.observeExit($('.dialog-content'), function() {
+ util.hide('dialog');
+ })
+
$('.dialog-content #username-input').focus();
+
$('.dialog-content').find('#sign-in-form').submit(function(e) {
$('.dialog-content .okButton').click();
return false;
})
- $('.dialog-content .cancelButton').click(function(e) {
- util.hide('dialog');
- })
+
$('.dialog-content .okButton').click(function(e) {
util.hide('dialog');
util.notify("Signing you in...", {persist: true, loader: true});
@@ -106,11 +110,14 @@ app.after = {
if (error.statusText === "error") util.notify(JSON.parse(error.responseText).reason);
})
})
+
},
bulkEdit: function() {
- $('.dialog-content .cancelButton').click(function(e) {
+
+ util.observeExit($('.dialog-content'), function() {
util.hide('dialog');
})
+
$('.dialog-content .okButton').click(function(e) {
var funcText = $('.expression-preview-code').val();
util.hide('dialog');
diff --git a/attachments/script/util.js b/attachments/script/util.js
index b3dc9be4..2407be5d 100644
--- a/attachments/script/util.js
+++ b/attachments/script/util.js
@@ -24,6 +24,32 @@ var util = function() {
return exists;
}
+ function registerEmitter() {
+ var Emitter = function(obj) {
+ this.emit = function(obj, channel) {
+ if (!channel) var channel = 'data';
+ this.trigger(channel, obj);
+ };
+ };
+ MicroEvent.mixin(Emitter);
+ app.emitter = new Emitter();
+ }
+
+ function listenFor(keys) {
+ _.each(keys, function(key) {
+ $(document).bind('keydown', key, function() { app.emitter.emit(key, key) });
+ })
+ }
+
+ function observeExit(elem, callback) {
+ var cancelButton = elem.find('.cancelButton');
+ app.emitter.on('esc', function() {
+ cancelButton.click();
+ app.emitter.clear('esc');
+ });
+ cancelButton.click(callback);
+ }
+
function show( thing ) {
$('.' + thing ).show();
$('.' + thing + '-overlay').show();
@@ -148,11 +174,14 @@ var util = function() {
return {
inURL: inURL,
+ registerEmitter: registerEmitter,
+ listenFor: listenFor,
show: show,
hide: hide,
position: position,
render: render,
notify: notify,
+ observeExit: observeExit,
formatMetadata:formatMetadata,
getBaseURL:getBaseURL,
resetForm: resetForm,