From 76572f5bd6bf7c63e1fe4742919d0e8371255c65 Mon Sep 17 00:00:00 2001 From: Elaine Tan Date: Tue, 17 Apr 2012 16:37:42 +0800 Subject: [PATCH] [IDEMPIERE-184] Zk6: Port KeyListener component to Zk6 --- .../WEB-INF/src/metainfo/zk/lang-addon.xml | 11 + .../adempiere/webui/panel/ADWindowPanel.java | 35 +--- .../org/zkforge/keylistener/Keylistener.java | 195 ++++++++++++++++++ .../src/org/zkforge/keylistener/Version.java | 11 + .../WEB-INF/src/web/js/zkforge/KeyListener.js | 128 ++++++++++++ .../src/web/js/zkforge/mold/key-listener.js | 3 + .../WEB-INF/src/web/js/zkforge/zk.wpd | 3 + org.adempiere.ui.zk/WEB-INF/zk.xml | 2 +- org.zkoss.zk.library/.classpath | 73 ++++--- org.zkoss.zk.library/META-INF/MANIFEST.MF | 3 - 10 files changed, 399 insertions(+), 65 deletions(-) create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Keylistener.java create mode 100644 org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Version.java create mode 100644 org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/KeyListener.js create mode 100644 org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/mold/key-listener.js create mode 100644 org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/zk.wpd diff --git a/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml b/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml index 4619a69ce6..d1c89d0c29 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml +++ b/org.adempiere.ui.zk/WEB-INF/src/metainfo/zk/lang-addon.xml @@ -21,10 +21,21 @@ Copyright (C) 2007 Ashley G Ramdass (ADempiere WebUI). org.adempiere.webui.AdempiereWebUI 3.5 + + + keylistener + org.zkforge.keylistener.Keylistener + zkforge.KeyListener + + default + mold/key-listener.js + + + diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java index 690baf87a0..6de955f142 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/ADWindowPanel.java @@ -40,7 +40,7 @@ import org.compiere.model.MQuery; import org.compiere.util.CLogger; import org.compiere.util.Env; import org.compiere.util.Msg; -//import org.zkforge.keylistener.Keylistener; +import org.zkforge.keylistener.Keylistener; import org.zkoss.zk.ui.Component; import org.zkoss.zk.ui.HtmlBasedComponent; import org.zkoss.zk.ui.event.Event; @@ -52,8 +52,8 @@ import org.zkoss.zul.Center; import org.zkoss.zul.East; import org.zkoss.zul.North; import org.zkoss.zul.South; -import org.zkoss.zul.West; import org.zkoss.zul.Tab; +import org.zkoss.zul.West; /** * @@ -78,7 +78,7 @@ public class ADWindowPanel extends AbstractADWindowPanel private East east; -// private Keylistener keyListener; + private Keylistener keyListener; public ADWindowPanel(Properties ctx, int windowNo) { @@ -186,19 +186,14 @@ public class ADWindowPanel extends AbstractADWindowPanel } if (!isEmbedded()) { -// if (keyListener != null) -// keyListener.detach(); -// keyListener = new Keylistener(); -// statusBar.appendChild(keyListener); -// keyListener.setCtrlKeys("#f1#f2#f3#f4#f5#f6#f7#f8#f9#f10#f11#f12^f^i^n^s^d@#left@#right@#up@#down@#pgup@#pgdn@p^p@z@x#enter"); -// keyListener.addEventListener(Events.ON_CTRL_KEY, toolbar); -// keyListener.addEventListener(Events.ON_OK, this); -// keyListener.setAutoBlur(false); - - //FIXME: only work when focus is at input element - contentArea.setCtrlKeys("#f1#f2#f3#f4#f5#f6#f7#f8#f9#f10#f11#f12^f^i^n^s^d@#left@#right@#up@#down@#pgup@#pgdn@p^p@z@x"); - contentArea.addEventListener(Events.ON_CTRL_KEY, toolbar); - contentArea.addEventListener(Events.ON_OK, this); + if (keyListener != null) + keyListener.detach(); + keyListener = new Keylistener(); + statusBar.appendChild(keyListener); + keyListener.setCtrlKeys("#f1#f2#f3#f4#f5#f6#f7#f8#f9#f10#f11#f12^f^i^n^s^d@#left@#right@#up@#down@#pgup@#pgdn@p^p@z@x#enter"); + keyListener.addEventListener(Events.ON_CTRL_KEY, toolbar); + keyListener.addEventListener(Events.ON_CTRL_KEY, this); + keyListener.setAutoBlur(false); } layout.setAttribute(ITabOnSelectHandler.ATTRIBUTE_KEY, new ITabOnSelectHandler() { @@ -249,7 +244,6 @@ public class ADWindowPanel extends AbstractADWindowPanel * @see EventListener#onEvent(Event) */ public void onEvent(Event event) { - //FIXME: not working for zk6 if (Events.ON_CTRL_KEY.equals(event.getName())) { KeyEvent keyEvent = (KeyEvent) event; //enter == 13 @@ -261,13 +255,6 @@ public class ADWindowPanel extends AbstractADWindowPanel } } } - } else if (Events.ON_OK.equals(event.getName())) { - IADTabpanel panel = adTab.getSelectedTabpanel(); - if (panel != null) { - if (panel.onEnterKey()) { - event.stopPropagation(); - } - } } else { super.onEvent(event); } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Keylistener.java b/org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Keylistener.java new file mode 100644 index 0000000000..5e41b16698 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Keylistener.java @@ -0,0 +1,195 @@ +package org.zkforge.keylistener; + +import java.io.IOException; + +import org.zkoss.lang.Objects; +import org.zkoss.mesg.MCommon; +import org.zkoss.zk.ui.HtmlBasedComponent; +import org.zkoss.zk.ui.UiException; +import org.zkoss.zk.ui.WrongValueException; +import org.zkoss.zk.ui.sys.ContentRenderer; + +/** + * Keylistener component. See Window for specification of ctrlKey format. + * + * @author boha + * + */ +public class Keylistener extends HtmlBasedComponent { + + private String _ctrlKeys; + + private String _jsCtrlKeys; + + private boolean _autoBlur = true; + + /** + * Auto generated serial UID + */ + private static final long serialVersionUID = 4611014738053691844L; + + /** + * Is auto blur active + * + * @return the autoBlur + */ + public boolean isAutoBlur() { + return _autoBlur; + } + + /** + * Set auto blur. If auto blur is set focus will be moved to keylistener + * component before onCtrlKey event is triggered. This is used to force any + * pending onChange events to be triggered first. + * + * @param autoBlur + * the autoBlur to set + */ + public void setAutoBlur(boolean autoBlur) { + this._autoBlur = autoBlur; + smartUpdate("autoblur", _autoBlur); + } + + /** + * Get control keys + * + * @return the ctrlKeys + */ + public String getCtrlKeys() { + return _ctrlKeys; + } + + /** + * Set control keys to listen for + * + * @param ctrlKeys + * the ctrlKeys to set + */ + public void setCtrlKeys(String ctrlKeys) { + if (ctrlKeys != null && ctrlKeys.length() == 0) + ctrlKeys = null; + if (!Objects.equals(this._ctrlKeys, ctrlKeys)) { + parseCtrlKeys(ctrlKeys); + smartUpdate("ctrlKeys", _jsCtrlKeys); + } + } + + @Override + protected void renderProperties(ContentRenderer renderer) + throws IOException { + super.renderProperties(renderer); + render(renderer, "ctrlKeys", _jsCtrlKeys); + render(renderer, "autoblur", _autoBlur); + } + + private void parseCtrlKeys(String keys) throws UiException { + if (keys == null || keys.length() == 0) { + _ctrlKeys = _jsCtrlKeys = null; + return; + } + + final StringBuffer sbctl = new StringBuffer(), sbsft = new StringBuffer(), sbalt = new StringBuffer(), sbext = new StringBuffer(); + StringBuffer sbcur = null; + for (int j = 0, len = keys.length(); j < len; ++j) { + char cc = keys.charAt(j); + switch (cc) { + case '^': + case '$': + case '@': + if (sbcur != null) + throw new WrongValueException( + "Combination of Shift, Alt and Ctrl not supported: " + + keys); + sbcur = cc == '^' ? sbctl : cc == '@' ? sbalt : sbsft; + break; + case '#': { + int k = j + 1; + for (; k < len; ++k) { + final char c2 = (char) keys.charAt(k); + if ((c2 > 'Z' || c2 < 'A') && (c2 > 'z' || c2 < 'a') + && (c2 > '9' || c2 < '0')) + break; + } + if (k == j + 1) + throw new WrongValueException(MCommon.UNEXPECTED_CHARACTER, + new Object[] { new Character(cc), keys }); + + final String s = keys.substring(j + 1, k).toLowerCase(); + if ("pgup".equals(s)) + cc = 'A'; + else if ("pgdn".equals(s)) + cc = 'B'; + else if ("end".equals(s)) + cc = 'C'; + else if ("home".equals(s)) + cc = 'D'; + else if ("left".equals(s)) + cc = 'E'; + else if ("up".equals(s)) + cc = 'F'; + else if ("right".equals(s)) + cc = 'G'; + else if ("down".equals(s)) + cc = 'H'; + else if ("ins".equals(s)) + cc = 'I'; + else if ("del".equals(s)) + cc = 'J'; + else if ("enter".equals(s)) + cc = 'K'; + else if (s.length() > 1 && s.charAt(0) == 'f') { + final int v; + try { + v = Integer.parseInt(s.substring(1)); + } catch (Throwable ex) { + throw new WrongValueException("Unknown #" + s + " in " + + keys); + } + if (v == 0 || v > 12) + throw new WrongValueException( + "Unsupported function key: #f" + v); + cc = (char) ('O' + v); // 'P': F1, 'Q': F2... 'Z': F12 + } else + throw new WrongValueException("Unknown #" + s + " in " + + keys); + + if (sbcur == null) + sbext.append(cc); + else { + sbcur.append(cc); + sbcur = null; + } + j = k - 1; + } + break; + default: + if (sbcur == null + || ((cc > 'Z' || cc < 'A') && (cc > 'z' || cc < 'a') && (cc > '9' || cc < '0'))) + throw new WrongValueException(MCommon.UNEXPECTED_CHARACTER, + new Object[] { new Character(cc), keys }); + if (sbcur == sbsft) + throw new WrongValueException("$" + cc + " not supported: " + + keys); + + if (cc <= 'Z' && cc >= 'A') + cc = (char) (cc + ('a' - 'A')); // to lower case + sbcur.append(cc); + sbcur = null; + break; + } + } + + _jsCtrlKeys = new StringBuffer().append('^').append(sbctl).append(';') + .append('@').append(sbalt).append(';').append('$') + .append(sbsft).append(';').append('#').append(sbext) + .append(';').toString(); + _ctrlKeys = keys; + } + + /* (non-Javadoc) + * @see org.zkoss.zk.ui.AbstractComponent#isChildable() + */ + public boolean isChildable() { + return false; + } +} \ No newline at end of file diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Version.java b/org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Version.java new file mode 100644 index 0000000000..441815d98e --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/org/zkforge/keylistener/Version.java @@ -0,0 +1,11 @@ +package org.zkforge.keylistener; + +/** + * Version + * @author Bobo H�ggstr�m + */ +public class Version { + + public static final String UID = "1.0.1"; + +} diff --git a/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/KeyListener.js b/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/KeyListener.js new file mode 100644 index 0000000000..6e5da8431e --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/KeyListener.js @@ -0,0 +1,128 @@ +/* keylistener.js + +{{IS_NOTE + Purpose: + zkforge.KeyListener + Description: + Keylistener component for ZK. +}}IS_NOTE + +Copyright 2007 by Easit AB. All rights reserved. + +{{IS_RIGHT + This program is distributed under GPL Version 2.0 in the hope that + it will be useful, but WITHOUT ANY WARRANTY. +}}IS_RIGHT +*/ + +zk.$package('zkforge'); +zkforge.KeyListener = zk.$extends(zul.Widget, { + _ctrlKeys: null, + _autoBlur: true, + + getCtrlKeys: function() { + return this._ctrlKeys; + }, + + setCtrlKeys: function(ctrlKeys) { + if(this._ctrlKeys != ctrlKeys) { + this._ctrlKeys = ctrlKeys; + } + }, + + getAutoBlur: function() { + return this._autoBlur; + }, + + setAutoBlur: function(autoBlur) { + if(this._autoBlur != autoBlur) { + this._autoBlur = autoBlur; + } + }, + + bind_: function (desktop, skipper, after) { + this.$supers('bind_', arguments); + + var self = this; + jq(document).ready(function () { + jq(document).keydown(function (evt) { + self.keyDown(evt); + }); + }); + }, + + keyDown: function(evt) { + if (!evt) evt = window.event; + + var keycode = evt.keyCode, zkcode; //zkcode used to search z.ctkeys + switch (keycode) { + case 13: //ENTER + zkcode = 'K'; + break; + case 27: //ESC + break; + case 16: //Shift + case 17: //Ctrl + case 18: //Alt + return true; + case 44: //Ins + case 45: //Del + zkcode = keycode == 44 ? 'I': 'J'; + break; + default: + if (keycode >= 33 && keycode <= 40) { //PgUp, PgDn, End, Home, L, U, R, D + zkcode = String.fromCharCode('A'.charCodeAt(0) + (keycode - 33)); + //A~H: PgUp, ... + break; + } else if (keycode >= 112 && keycode <= 123) { //F1: 112, F12: 123 + zkcode = String.fromCharCode('P'.charCodeAt(0) + (keycode - 112)); + //M~Z: F1~F12 + break; + } else if (evt.ctrlKey || evt.altKey) { + zkcode = String.fromCharCode(keycode).toLowerCase(); + break; + } + return true; + } + + // If keyboard command is registered for this component, send request + if(this.inCtrlKeys(evt, zkcode, this._ctrlKeys) ) { + + // If autoblur is specified, set focus to keylistener to trigger onBlur for focused component + if(this._autoBlur == true){ + this.tabIndex = 32000; + this.focus(); + this.tabIndex = 0; + } + + zAu.send(new zk.Event(zk.Widget.$(this), 'onCtrlKey', {keyCode: keycode, ctrlKey: evt.ctrlKey, shiftKey: evt.shiftKey, altKey: evt.altKey}, {toServer: true})); + + // Do not send request directly, otherwise onChange events won't be fired correctly in IE + //setTimeout(function () { + // zAu.send(new zk.Event(zk.Widget.$(this), 'onCtrlKey', {keyCode: keycode, ctrlKey: evt.ctrlKey, shiftKey: evt.shiftKey, altKey: evt.altKey}, {toServer: true}), 38); + //}, 10); + + evt.stop(); + + // Special handling for IE that Event.stop doesn't support + if (document.all && window.event && !evt.preventDefault) { + evt.keyCode = 0; + } + return false; + } + return true; + }, + + inCtrlKeys: function(evt, zkcode, keys) { + if (keys) { + //format: ctl+k;alt+k;shft+k;k + var cc = evt.ctrlKey ? '^': evt.altKey ? '@': evt.shiftKey ? '$': '#'; + var j = keys.indexOf(cc), k = keys.indexOf(';', j + 1); + if (j >=0 && k >= 0) { + keys = keys.substring(j + 1, k); + return keys.indexOf(zkcode) >= 0; + } + } + return false; + } +}); diff --git a/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/mold/key-listener.js b/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/mold/key-listener.js new file mode 100644 index 0000000000..d489f50ca9 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/mold/key-listener.js @@ -0,0 +1,3 @@ +function (out) { + out.push('
', '
'); +} \ No newline at end of file diff --git a/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/zk.wpd b/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/zk.wpd new file mode 100644 index 0000000000..302ba275c4 --- /dev/null +++ b/org.adempiere.ui.zk/WEB-INF/src/web/js/zkforge/zk.wpd @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/org.adempiere.ui.zk/WEB-INF/zk.xml b/org.adempiere.ui.zk/WEB-INF/zk.xml index bd21c33785..ba413bb7cd 100644 --- a/org.adempiere.ui.zk/WEB-INF/zk.xml +++ b/org.adempiere.ui.zk/WEB-INF/zk.xml @@ -20,7 +20,7 @@ - false + true 500 diff --git a/org.zkoss.zk.library/.classpath b/org.zkoss.zk.library/.classpath index e3e9b14c01..cc177cb75d 100644 --- a/org.zkoss.zk.library/.classpath +++ b/org.zkoss.zk.library/.classpath @@ -1,37 +1,36 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.zkoss.zk.library/META-INF/MANIFEST.MF b/org.zkoss.zk.library/META-INF/MANIFEST.MF index 0249b7d2a1..263a449c63 100644 --- a/org.zkoss.zk.library/META-INF/MANIFEST.MF +++ b/org.zkoss.zk.library/META-INF/MANIFEST.MF @@ -524,7 +524,6 @@ Export-Package: Lib, org.zkforge.ckez, org.zkforge.json.simple, org.zkforge.json.simple.parser, - org.zkforge.keylistener, org.zkforge.timeline, org.zkforge.timeline.data, org.zkforge.timeline.decorator, @@ -880,8 +879,6 @@ Export-Package: Lib, web.js.zk.wgt, web.js.zk.xml, web.js.zk.zuml, - web.js.zkforge, - web.js.zkforge.mold, web.js.zul, web.js.zul.box, web.js.zul.box.css,