Products.CMFPlone/5.0.x-jqtree-contextmenu: Add JS Shortcut for keyboard shortcut support.

Oshane Bailey <jenkins-z4DKO/[email protected]>
Newsgroups gmane.comp.web.zope.plone.cvs
Message-ID <[email protected]>
Repository: Products.CMFPlone
Branch: refs/heads/5.0.x-jqtree-contextmenu
Date: 2017-07-11T01:32:05-05:00
Author: Oshane Bailey (b4oshany) <[email protected]>
Commit: https://github.com/plone/Products.CMFPlone/commit/3922d0e9de7165359710e81f27099ff602c74889

Add JS Shortcut for keyboard shortcut support.

Files changed:
A Products/CMFPlone/static/components/js-shortcuts/LICENSE
A Products/CMFPlone/static/components/js-shortcuts/README.md
A Products/CMFPlone/static/components/js-shortcuts/js-shortcuts-angular.js
A Products/CMFPlone/static/components/js-shortcuts/js-shortcuts.js
M CHANGES.rst
M Products/CMFPlone/profiles/dependencies/registry.xml
M Products/CMFPlone/static/bower.json

diff --git a/CHANGES.rst b/CHANGES.rst
index 8e7fabc7a..7b7e61db5 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -15,7 +15,9 @@ Breaking changes:
 
 New features:
 
-- Create an upgrade step to 5020 from 5019.
+- Add js-shortcuts package for keyboard shortcuts
+  [b4oshany]
+- Update package version to 5020 from 5019.
   [b4oshany]
 - Add more ignores to static/.gitignore.
   [thet]
diff --git a/Products/CMFPlone/profiles/dependencies/registry.xml b/Products/CMFPlone/profiles/dependencies/registry.xml
index e05bdca7f..5720ce2fb 100644
--- a/Products/CMFPlone/profiles/dependencies/registry.xml
+++ b/Products/CMFPlone/profiles/dependencies/registry.xml
@@ -324,6 +324,12 @@
       <value key="deps">jqtree</value>
   </records>
 
+  <records prefix="plone.resources/js-shortcuts"
+            interface='Products.CMFPlone.interfaces.IResourceRegistry'>
+      <value key="js">++plone++static/components/js-shortcuts/js-shortcuts.js</value>
+      <value key="deps">jquery</value>
+  </records>
+
   <records prefix="plone.resources/jquery.form"
             interface='Products.CMFPlone.interfaces.IResourceRegistry'>
       <value key="js">++plone++static/components/jquery-form/jquery.form.js</value>
diff --git a/Products/CMFPlone/static/bower.json b/Products/CMFPlone/static/bower.json
index 6a152b52f..98a8726e1 100644
--- a/Products/CMFPlone/static/bower.json
+++ b/Products/CMFPlone/static/bower.json
@@ -28,7 +28,8 @@
     "requirejs": "",
     "less": "2.1.2",
     "r.js": "2.1.15",
-    "cs-jqtree-contextmenu": "^0.1.0"
+    "cs-jqtree-contextmenu": "^0.1.0",
+    "js-shortcuts": "^1.0.1"
   },
   "resolutions": {
     "jquery": "1.11.3",
diff --git a/Products/CMFPlone/static/components/js-shortcuts/LICENSE b/Products/CMFPlone/static/components/js-shortcuts/LICENSE
new file mode 100644
index 000000000..a44eb83a0
--- /dev/null
+++ b/Products/CMFPlone/static/components/js-shortcuts/LICENSE
@@ -0,0 +1,28 @@
+Copyright (c) 2015, Saneem
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+  list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+  this list of conditions and the following disclaimer in the documentation
+  and/or other materials provided with the distribution.
+
+* Neither the name of js-shortcuts nor the names of its
+  contributors may be used to endorse or promote products derived from
+  this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
diff --git a/Products/CMFPlone/static/components/js-shortcuts/README.md b/Products/CMFPlone/static/components/js-shortcuts/README.md
new file mode 100644
index 000000000..534330311
--- /dev/null
+++ b/Products/CMFPlone/static/components/js-shortcuts/README.md
@@ -0,0 +1,49 @@
+# js-shortcuts
+
+Easily add combination key-press event listeners in JavaScript. Useful for adding keyboard shortcuts to web applications.
+
+Here's the [original version](http://www.openjs.com/scripts/events/keyboard_shortcuts/). I'm putting this up on GitHub to make loading this overusing Bower a bit easier.
+
+## Usage
+
+Basic Version
+
+    shortcut.add("Ctrl+B", function () {
+      window.alert("Make it Bold!");
+    });
+
+AngularJS
+
+    app.controller('yourCtrl', function(jsShortcuts) {
+    
+      jsShortcuts.add("Ctrl+B", function () {
+        window.alert("Make it Bold!");
+      });  
+      
+    });
+
+More information available on the [original doc](http://www.openjs.com/scripts/events/keyboard_shortcuts/) page.
+
+## Installation
+
+### Bower
+Install via bower:
+
+    bower install js-shortcuts --save 
+
+and require the script:
+
+    <script src="bower_components/js-shortcuts/js-shortcuts.js"></script>
+
+### Angular
+Install via bower as above. Use the AngularJS version of the script.
+
+    <script src="bower_components/js-shortcuts/js-shortcuts-angular.js"></script>
+
+Add the module `js-shortcuts` as a dependency to your app
+
+    var app = angular.module('yourAwesomeApp', ['js-shortcuts']);
+
+
+## License
+BSD License
diff --git a/Products/CMFPlone/static/components/js-shortcuts/js-shortcuts-angular.js b/Products/CMFPlone/static/components/js-shortcuts/js-shortcuts-angular.js
new file mode 100644
index 000000000..7c4b80705
--- /dev/null
+++ b/Products/CMFPlone/static/components/js-shortcuts/js-shortcuts-angular.js
@@ -0,0 +1,300 @@
+/**
+ @license 
+ Adapted for Angular by Saneem
+ Original version by Binny V A
+ License: MIT
+ */
+(function () {
+  'use strict';
+
+  angular.module('js-shortcuts', []).provider('jsShortcuts', function () {
+
+    this.$get = function () {
+      var all_shortcuts = {};
+
+      return {
+        add: function (shortcut_combination, callback, opt) {
+          //Provide a set of default options
+          var default_options = {
+            'type': 'keydown',
+            'propagate': false,
+            'disable_in_input': false,
+            'target': document,
+            'keycode': false
+          };
+
+          if (!opt) {
+            opt = default_options;
+          } else {
+            for (var dfo in default_options) {
+              if (typeof opt[dfo] === 'undefined') {
+                opt[dfo] = default_options[dfo];
+              }
+            }
+          }
+
+          var ele = opt.target;
+          if (typeof opt.target === 'string') {
+            ele = document.getElementById(opt.target);
+          }
+
+          shortcut_combination = shortcut_combination.toLowerCase();
+
+          //The function to be called at keypress
+          var func = function (e) {
+            var code;
+            e = e || window.event;
+
+            if (opt.disable_in_input) { //Don't enable shortcut keys in Input, Textarea fields
+              var element;
+              if (e.target) {
+                element = e.target;
+              } else if (e.srcElement) {
+                element = e.srcElement;
+              }
+              if (element.nodeType === 3) {
+                element = element.parentNode;
+              }
+
+              if (element.tagName === 'INPUT' || element.tagName === 'TEXTAREA') {
+                return;
+              }
+            }
+
+            //Find Which key is pressed
+            if (e.keyCode) {
+              code = e.keyCode;
+            } else if (e.which) {
+              code = e.which;
+            }
+
+            var character = String.fromCharCode(code).toLowerCase();
+
+            if (code === 188) {
+              character = ","; //If the user presses , when the type is onkeydown
+            }
+            if (code === 190) {
+              character = "."; //If the user presses , when the type is onkeydown
+            }
+
+            var keys = shortcut_combination.split("+");
+            //Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
+            var kp = 0;
+
+            //Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
+            var shift_nums = {
+              "`": "~",
+              "1": "!",
+              "2": "@",
+              "3": "#",
+              "4": "$",
+              "5": "%",
+              "6": "^",
+              "7": "&",
+              "8": "*",
+              "9": "(",
+              "0": ")",
+              "-": "_",
+              "=": "+",
+              ";": ":",
+              "'": "\"",
+              ",": "<",
+              ".": ">",
+              "/": "?",
+              "\\": "|"
+            };
+
+            //Special Keys - and their codes
+            var special_keys = {
+              'esc': 27,
+              'escape': 27,
+              'tab': 9,
+              'space': 32,
+              'return': 13,
+              'enter': 13,
+              'backspace': 8,
+
+              'scrolllock': 145,
+              'scroll_lock': 145,
+              'scroll': 145,
+              'capslock': 20,
+              'caps_lock': 20,
+              'caps': 20,
+              'numlock': 144,
+              'num_lock': 144,
+              'num': 144,
+
+              'pause': 19,
+              'break': 19,
+
+              'insert': 45,
+              'home': 36,
+              'delete': 46,
+              'end': 35,
+
+              'pageup': 33,
+              'page_up': 33,
+              'pu': 33,
+
+              'pagedown': 34,
+              'page_down': 34,
+              'pd': 34,
+
+              'left': 37,
+              'up': 38,
+              'right': 39,
+              'down': 40,
+
+              'f1': 112,
+              'f2': 113,
+              'f3': 114,
+              'f4': 115,
+              'f5': 116,
+              'f6': 117,
+              'f7': 118,
+              'f8': 119,
+              'f9': 120,
+              'f10': 121,
+              'f11': 122,
+              'f12': 123
+            };
+
+            var modifiers = {
+              shift: {
+                wanted: false,
+                pressed: false
+              },
+              ctrl: {
+                wanted: false,
+                pressed: false
+              },
+              alt: {
+                wanted: false,
+                pressed: false
+              },
+              meta: {
+                wanted: false,
+                pressed: false
+              } //Meta is Mac specific
+            };
+
+            if (e.ctrlKey) {
+              modifiers.ctrl.pressed = true;
+            }
+            if (e.shiftKey) {
+              modifiers.shift.pressed = true;
+            }
+            if (e.altKey) {
+              modifiers.alt.pressed = true;
+            }
+            if (e.metaKey) {
+              modifiers.meta.pressed = true;
+            }
+
+            var k;
+
+            for (var i = 0; k = keys[i], i < keys.length; i++) {
+              //Modifiers
+              if (k === 'ctrl' || k === 'control') {
+                kp++;
+                modifiers.ctrl.wanted = true;
+
+              } else if (k === 'shift') {
+                kp++;
+                modifiers.shift.wanted = true;
+
+              } else if (k === 'alt') {
+                kp++;
+                modifiers.alt.wanted = true;
+              } else if (k === 'meta') {
+                kp++;
+                modifiers.meta.wanted = true;
+              } else if (k.length > 1) { //If it is a special key
+                if (special_keys[k] === code) {
+                  kp++;
+                }
+
+              } else if (opt.keycode) {
+                if (opt.keycode === code) {
+                  kp++;
+                }
+
+              } else { //The special keys did not match
+                if (character === k) {
+                  kp++;
+                } else {
+                  if (shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
+                    character = shift_nums[character];
+                    if (character === k) {
+                      kp++;
+                    }
+                  }
+                }
+              }
+            }
+
+            if (kp === keys.length &&
+              modifiers.ctrl.pressed === modifiers.ctrl.wanted &&
+              modifiers.shift.pressed === modifiers.shift.wanted &&
+              modifiers.alt.pressed === modifiers.alt.wanted &&
+              modifiers.meta.pressed === modifiers.meta.wanted) {
+              callback(e);
+
+              if (!opt.propagate) { //Stop the event
+                //e.cancelBubble is supported by IE - this will kill the bubbling process.
+                e.cancelBubble = true;
+                e.returnValue = false;
+
+                //e.stopPropagation works in Firefox.
+                if (e.stopPropagation) {
+                  e.stopPropagation();
+                  e.preventDefault();
+                }
+                return false;
+              }
+            }
+          };
+
+          all_shortcuts[shortcut_combination] = {
+            'callback': func,
+            'target': ele,
+            'event': opt.type
+          };
+          //Attach the function with the event
+          if (ele.addEventListener) {
+            ele.addEventListener(opt.type, func, false);
+          } else if (ele.attachEvent) {
+            ele.attachEvent('on' + opt.type, func);
+          } else {
+            ele['on' + opt.type] = func;
+          }
+        },
+
+        remove: function (shortcut_combination) {
+          shortcut_combination = shortcut_combination.toLowerCase();
+          var binding = all_shortcuts[shortcut_combination];
+          delete(all_shortcuts[shortcut_combination]);
+          if (!binding) {
+            return;
+          }
+          var type = binding.event;
+          var ele = binding.target;
+          var callback = binding.callback;
+
+          if (ele.detachEvent) {
+            ele.detachEvent('on' + type, callback);
+          } else if (ele.removeEventListener) {
+            ele.removeEventListener(type, callback, false);
+          } else {
+            ele['on' + type] = false;
+          }
+        }
+
+
+      };
+    };
+
+  });
+
+
+}).call(this);
\ No newline at end of file
diff --git a/Products/CMFPlone/static/components/js-shortcuts/js-shortcuts.js b/Products/CMFPlone/static/components/js-shortcuts/js-shortcuts.js
new file mode 100644
index 000000000..38742f897
--- /dev/null
+++ b/Products/CMFPlone/static/components/js-shortcuts/js-shortcuts.js
@@ -0,0 +1,223 @@
+/**
+ * http://www.openjs.com/scripts/events/keyboard_shortcuts/
+ * Version : 2.01.B
+ * By Binny V A
+ * License : BSD
+ */
+shortcut = {
+	'all_shortcuts':{},//All the shortcuts are stored in this array
+	'add': function(shortcut_combination,callback,opt) {
+		//Provide a set of default options
+		var default_options = {
+			'type':'keydown',
+			'propagate':false,
+			'disable_in_input':false,
+			'target':document,
+			'keycode':false
+		}
+		if(!opt) opt = default_options;
+		else {
+			for(var dfo in default_options) {
+				if(typeof opt[dfo] == 'undefined') opt[dfo] = default_options[dfo];
+			}
+		}
+
+		var ele = opt.target;
+		if(typeof opt.target == 'string') ele = document.getElementById(opt.target);
+		var ths = this;
+		shortcut_combination = shortcut_combination.toLowerCase();
+
+		//The function to be called at keypress
+		var func = function(e) {
+			e = e || window.event;
+			
+			if(opt['disable_in_input']) { //Don't enable shortcut keys in Input, Textarea fields
+				var element;
+				if(e.target) element=e.target;
+				else if(e.srcElement) element=e.srcElement;
+				if(element.nodeType==3) element=element.parentNode;
+
+				if(element.tagName == 'INPUT' || element.tagName == 'TEXTAREA') return;
+			}
+	
+			//Find Which key is pressed
+			if (e.keyCode) code = e.keyCode;
+			else if (e.which) code = e.which;
+			var character = String.fromCharCode(code).toLowerCase();
+			
+			if(code == 188) character=","; //If the user presses , when the type is onkeydown
+			if(code == 190) character="."; //If the user presses , when the type is onkeydown
+
+			var keys = shortcut_combination.split("+");
+			//Key Pressed - counts the number of valid keypresses - if it is same as the number of keys, the shortcut function is invoked
+			var kp = 0;
+			
+			//Work around for stupid Shift key bug created by using lowercase - as a result the shift+num combination was broken
+			var shift_nums = {
+				"`":"~",
+				"1":"!",
+				"2":"@",
+				"3":"#",
+				"4":"$",
+				"5":"%",
+				"6":"^",
+				"7":"&",
+				"8":"*",
+				"9":"(",
+				"0":")",
+				"-":"_",
+				"=":"+",
+				";":":",
+				"'":"\"",
+				",":"<",
+				".":">",
+				"/":"?",
+				"\\":"|"
+			}
+			//Special Keys - and their codes
+			var special_keys = {
+				'esc':27,
+				'escape':27,
+				'tab':9,
+				'space':32,
+				'return':13,
+				'enter':13,
+				'backspace':8,
+	
+				'scrolllock':145,
+				'scroll_lock':145,
+				'scroll':145,
+				'capslock':20,
+				'caps_lock':20,
+				'caps':20,
+				'numlock':144,
+				'num_lock':144,
+				'num':144,
+				
+				'pause':19,
+				'break':19,
+				
+				'insert':45,
+				'home':36,
+				'delete':46,
+				'end':35,
+				
+				'pageup':33,
+				'page_up':33,
+				'pu':33,
+	
+				'pagedown':34,
+				'page_down':34,
+				'pd':34,
+	
+				'left':37,
+				'up':38,
+				'right':39,
+				'down':40,
+	
+				'f1':112,
+				'f2':113,
+				'f3':114,
+				'f4':115,
+				'f5':116,
+				'f6':117,
+				'f7':118,
+				'f8':119,
+				'f9':120,
+				'f10':121,
+				'f11':122,
+				'f12':123
+			}
+	
+			var modifiers = { 
+				shift: { wanted:false, pressed:false},
+				ctrl : { wanted:false, pressed:false},
+				alt  : { wanted:false, pressed:false},
+				meta : { wanted:false, pressed:false}	//Meta is Mac specific
+			};
+                        
+			if(e.ctrlKey)	modifiers.ctrl.pressed = true;
+			if(e.shiftKey)	modifiers.shift.pressed = true;
+			if(e.altKey)	modifiers.alt.pressed = true;
+			if(e.metaKey)   modifiers.meta.pressed = true;
+                        
+			for(var i=0; k=keys[i],i<keys.length; i++) {
+				//Modifiers
+				if(k == 'ctrl' || k == 'control') {
+					kp++;
+					modifiers.ctrl.wanted = true;
+
+				} else if(k == 'shift') {
+					kp++;
+					modifiers.shift.wanted = true;
+
+				} else if(k == 'alt') {
+					kp++;
+					modifiers.alt.wanted = true;
+				} else if(k == 'meta') {
+					kp++;
+					modifiers.meta.wanted = true;
+				} else if(k.length > 1) { //If it is a special key
+					if(special_keys[k] == code) kp++;
+					
+				} else if(opt['keycode']) {
+					if(opt['keycode'] == code) kp++;
+
+				} else { //The special keys did not match
+					if(character == k) kp++;
+					else {
+						if(shift_nums[character] && e.shiftKey) { //Stupid Shift key bug created by using lowercase
+							character = shift_nums[character]; 
+							if(character == k) kp++;
+						}
+					}
+				}
+			}
+			
+			if(kp == keys.length && 
+						modifiers.ctrl.pressed == modifiers.ctrl.wanted &&
+						modifiers.shift.pressed == modifiers.shift.wanted &&
+						modifiers.alt.pressed == modifiers.alt.wanted &&
+						modifiers.meta.pressed == modifiers.meta.wanted) {
+				callback(e);
+	
+				if(!opt['propagate']) { //Stop the event
+					//e.cancelBubble is supported by IE - this will kill the bubbling process.
+					e.cancelBubble = true;
+					e.returnValue = false;
+	
+					//e.stopPropagation works in Firefox.
+					if (e.stopPropagation) {
+						e.stopPropagation();
+						e.preventDefault();
+					}
+					return false;
+				}
+			}
+		}
+		this.all_shortcuts[shortcut_combination] = {
+			'callback':func, 
+			'target':ele, 
+			'event': opt['type']
+		};
+		//Attach the function with the event
+		if(ele.addEventListener) ele.addEventListener(opt['type'], func, false);
+		else if(ele.attachEvent) ele.attachEvent('on'+opt['type'], func);
+		else ele['on'+opt['type']] = func;
+	},
+
+	//Remove the shortcut - just specify the shortcut and I will remove the binding
+	'remove':function(shortcut_combination) {
+		shortcut_combination = shortcut_combination.toLowerCase();
+		var binding = this.all_shortcuts[shortcut_combination];
+		delete(this.all_shortcuts[shortcut_combination])
+		if(!binding) return;
+		var type = binding['event'];
+		var ele = binding['target'];
+		var callback = binding['callback'];
+
+		if(ele.detachEvent) ele.detachEvent('on'+type, callback);
+		else if(ele.removeEventListener) ele.removeEventListener(type, callback, false);
+		else ele['on'+type] = false;
+	}
+}



------------------------------------------------------------------------------
Check out the vibrant tech community on one of the world's most
engaging tech sites, Slashdot.org! http://sdm.link/slashdot
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.