From d168b3508064ccfb7f1ebf635c0ba71734750ced Mon Sep 17 00:00:00 2001 From: xue <> Date: Mon, 27 Aug 2007 20:14:09 +0000 Subject: Added TKeyboard. --- .../Javascripts/source/prado/controls/controls.js | 173 +++++++++++++++++++ framework/Web/UI/WebControls/TKeyboard.php | 183 +++++++++++++++++++++ framework/Web/UI/WebControls/keyboard.css | 80 +++++++++ 3 files changed, 436 insertions(+) create mode 100644 framework/Web/UI/WebControls/TKeyboard.php create mode 100644 framework/Web/UI/WebControls/keyboard.css (limited to 'framework/Web') diff --git a/framework/Web/Javascripts/source/prado/controls/controls.js b/framework/Web/Javascripts/source/prado/controls/controls.js index e024234c..8975a7a2 100644 --- a/framework/Web/Javascripts/source/prado/controls/controls.js +++ b/framework/Web/Javascripts/source/prado/controls/controls.js @@ -339,3 +339,176 @@ Prado.WebUI.TTabPanel.prototype = } } }; + + +Prado.WebUI.TKeyboard = Class.create(); +Prado.WebUI.TKeyboard.prototype = +{ + initialize : function(options) + { + this.element = $(options.ID); + this.onInit(options); + }, + + onInit : function(options) + { + this.cssClass = options['CssClass']; + this.forControl = document.getElementById(options['ForControl']); + this.autoHide = options['AutoHide']; + + this.flagShift = false; + this.flagCaps = false; + this.flagHover = false; + this.flagFocus = false; + + this.keys = new Array + ( + new Array('` ~ D', '1 ! D', '2 @ D', '3 # D', '4 $ D', '5 % D', '6 ^ D', '7 & D', '8 * D', '9 ( D', '0 ) D', '- _ D', '= + D', 'Bksp Bksp Bksp'), + new Array('Del Del Del', 'q Q L', 'w W L', 'e E L', 'r R L', 't T L', 'y Y L', 'u U L', 'i I L', 'o O L', 'p P L', '[ { D', '] } D', '\\ | \\'), + new Array('Caps Caps Caps', 'a A L', 's S L', 'd D L', 'f F L', 'g G L', 'h H L', 'j J L', 'k K L', 'l L L', '; : D', '\' " D', 'Exit Exit Exit'), + new Array('Shift Shift Shift', 'z Z L', 'x X L', 'c C L', 'v V L', 'b B L', 'n N L', 'm M L', ', < D', '. > D', '/ ? D', 'Shift Shift Shift') + ); + + if (this.isObject(this.forControl)) + { + this.forControl.keyboard = this; + this.forControl.onfocus = function() {this.keyboard.show(); }; + this.forControl.onblur = function() {if (this.keyboard.flagHover == false) this.keyboard.hide();}; + this.forControl.onkeydown = function(e) {if (!e) e = window.event; var key = (e.keyCode)?e.keyCode:e.which; if(key == 9) this.keyboard.hide();;}; + this.forControl.onselect = this.saveSelection; + this.forControl.onclick = this.saveSelection; + this.forControl.onkeyup = this.saveSelection; + } + + this.render(); + + this.tagKeyboard.onmouseover = function() {this.keyboard.flagHover = true;}; + this.tagKeyboard.onmouseout = function() {this.keyboard.flagHover = false;}; + + if (!this.autoHide) this.show(); + }, + + isObject : function(a) + { + return (typeof a == 'object' && !!a) || typeof a == 'function'; + }, + + createElement : function(tagName, attributes, parent) + { + var tagElement = document.createElement(tagName); + if (this.isObject(attributes)) for (attribute in attributes) tagElement[attribute] = attributes[attribute]; + if (this.isObject(parent)) parent.appendChild(tagElement); + return tagElement; + }, + + onmouseover : function() + { + this.className += ' Hover'; + }, + + onmouseout : function() + { + this.className = this.className.replace(/( Hover| Active)/ig, ''); + }, + + onmousedown : function() + { + this.className += ' Active'; + }, + + onmouseup : function() + { + this.className = this.className.replace(/( Active)/ig, ''); + this.keyboard.type(this.innerHTML); + }, + + render : function() + { + this.tagKeyboard = this.createElement('div', {className: this.cssClass, onselectstart: function() {return false;}}, this.element); + this.tagKeyboard.keyboard = this; + + for (var line = 0; line < this.keys.length; line++) + { + var tagLine = this.createElement('div', {className: 'Line'}, this.tagKeyboard); + for (var key = 0; key < this.keys[line].length; key++) + { + var split = this.keys[line][key].split(' '); + var tagKey = this.createElement('div', {className: 'Key ' + split[2]}, tagLine); + var tagKey1 = this.createElement('div', {className: 'Key1', innerHTML: split[0], keyboard: this, onmouseover: this.onmouseover, onmouseout: this.onmouseout, onmousedown: this.onmousedown, onmouseup: this.onmouseup}, tagKey); + var tagKey2 = this.createElement('div', {className: 'Key2', innerHTML: split[1], keyboard: this, onmouseover: this.onmouseover, onmouseout: this.onmouseout, onmousedown: this.onmousedown, onmouseup: this.onmouseup}, tagKey); + } + } + }, + + isShown : function() + { + return (this.tagKeyboard.style.visibility.toLowerCase() == 'visible'); + }, + + show : function() + { + if (this.isShown() == false) this.tagKeyboard.style.visibility = 'visible'; + }, + + hide : function() + { + if (this.isShown() == true && this.autoHide) {this.tagKeyboard.style.visibility = 'hidden'; } + }, + + type : function(key) + { + + var input = this.forControl; + var command = key.toLowerCase(); + + if (command == 'exit') {this.hide();} + else if (input != 'undefined' && input != null && command == 'bksp') {this.insert(input, 'bksp');} + else if (input != 'undefined' && input != null && command == 'del') {this.insert(input, 'del');} + else if (command == 'shift') {this.tagKeyboard.className = this.flagShift?'Keyboard Off':'Keyboard Shift';this.flagShift = this.flagShift?false:true;} + else if (command == 'caps') {this.tagKeyboard.className = this.caps?'Keyboard Off':'Keyboard Caps';this.caps = this.caps?false:true;} + else if (input != 'undefined' && input != null) + { + if (this.flagShift == true) {this.flagShift = false; this.tagKeyboard.className = 'Keyboard Off';} + key = key.replace(/>/, '>'); key = key.replace(/</, '<'); key = key.replace(/&/, '&'); + this.insert(input, key); + } + + if (command != 'exit') input.focus(); + + }, + + saveSelection : function() + { + if (this.keyboard.forControl.createTextRange) + { + this.keyboard.selection = document.selection.createRange().duplicate(); + return; + } + }, + + insert : function(field, value) + { + if (this.forControl.createTextRange && this.selection) + { + if (value == 'bksp') {this.selection.moveStart("character", -1); this.selection.text = '';} + else if (value == 'del') {this.selection.moveEnd("character", 1); this.selection.text = '';} + else {this.selection.text = value;} + + this.selection.select(); + } + else + { + var selectStart = this.forControl.selectionStart; + var selectEnd = this.forControl.selectionEnd; + var start = (this.forControl.value).substring(0, selectStart); + var end = (this.forControl.value).substring(selectEnd, this.forControl.textLength); + + if (value == 'bksp') {start = start.substring(0, start.length - 1); selectStart -= 1; value = '';} + if (value == 'del') {end = end.substring(1, end.length); value = '';} + + this.forControl.value = start + value + end; + this.forControl.selectionStart = selectEnd + value.length; + this.forControl.selectionEnd = selectStart + value.length; + } + } +} \ No newline at end of file diff --git a/framework/Web/UI/WebControls/TKeyboard.php b/framework/Web/UI/WebControls/TKeyboard.php new file mode 100644 index 00000000..4ff15613 --- /dev/null +++ b/framework/Web/UI/WebControls/TKeyboard.php @@ -0,0 +1,183 @@ + and Qiang Xue + * @link http://www.pradosoft.com/ + * @copyright Copyright © 2005-2007 PradoSoft + * @license http://www.pradosoft.com/license/ + * @version $Id: $ + * @package System.Web.UI.WebControls + * @since 3.1.1 + */ + +/** + * Class TKeyboard. + * + * TKeyboard displays a virtual keyboard that users can click on to enter input in + * an associated text box. It helps to reduce the keyboard recording hacking. + * + * To use TKeyboard, write a template like following: + * + * + * + * + * + * A TKeyboard control is associated with a {@link TTextBox} control by specifying {@link setForControl ForControl} + * to be the ID of that control. When the textbox is in focus, a virtual keyboard will pop up; and when + * the text box is losing focus, the keyboard will hide automatically. Set {@link setAutoHide AutoHide} to + * false to keep the keyboard showing all the time. + * + * The appearance of the keyboard can also be changed by specifying a customized CSS file via + * {@link setCssUrl CssUrl}. By default, the CSS class name for the keyboard is 'Keyboard'. This may + * also be changed by specifying {@link setKeyboardCssClass KeyboardCssClass}. + * + * @author Sergey Morkovkin and Qiang Xue + * @version $Id: $ + * @since 3.1.1 + */ +class TKeyboard extends TWebControl +{ + /** + * @return string the ID path of the {@link TTextBox} control + */ + public function getForControl() + { + return $this->getViewState('ForControl',''); + } + + /** + * Sets the ID path of the {@link TTextBox} control. + * The ID path is the dot-connected IDs of the controls reaching from + * the keyboard's naming container to the target control. + * @param string the ID path + */ + public function setForControl($value) + { + $this->setViewState('ForControl', TPropertyValue::ensureString($value)); + } + + /** + * @return boolean whether the keyboard should be hidden when the textbox is not in focus. Defaults to true. + */ + public function getAutoHide() + { + return $this->getViewState('AutoHide', true); + } + + /** + * @param boolean whether the keyboard should be hidden when the textbox is not in focus. + */ + public function setAutoHide($value) + { + $this->setViewState('AutoHide', TPropertyValue::ensureBoolean($value), true); + } + + /** + * @return string the CSS class name for the keyboard
element. Defaults to 'Keyboard'. + */ + public function getKeyboardCssClass() + { + return $this->getViewState('KeyboardCssClass', 'Keyboard'); + } + + /** + * Sets a value indicating the CSS class name for the keyboard
element. + * Note, if you change this property, make sure you also supply a customized CSS file + * by specifying {@link setCssUrl CssUrl} which uses the new CSS class name for styling. + * @param string the CSS class name for the keyboard
element. + */ + public function setKeyboardCssClass($value) + { + $this->setViewState('KeyboardCssClass', $value, 'Keyboard'); + } + + /** + * @return string the URL for the CSS file to customize the appearance of the keyboard. + */ + public function getCssUrl() + { + return $this->getViewState('CssUrl', ''); + } + + /** + * @param string the URL for the CSS file to customize the appearance of the keyboard. + */ + public function setCssUrl($value) + { + $this->setViewState('CssUrl', $value, ''); + } + + /** + * Registers CSS and JS. + * This method is invoked right before the control rendering, if the control is visible. + * @param mixed event parameter + */ + public function onPreRender($param) + { + parent::onPreRender($param); + if($this->getPage()->getClientSupportsJavaScript()) + { + $this->registerStyleSheet(); + $this->registerClientScript(); + } + } + + /** + * Adds attribute name-value pairs to renderer. + * This method overrides the parent implementation with additional TKeyboard specific attributes. + * @param THtmlWriter the writer used for the rendering purpose + */ + protected function addAttributesToRender($writer) + { + parent::addAttributesToRender($writer); + if($this->getPage()->getClientSupportsJavaScript()) + $writer->addAttribute('id',$this->getClientID()); + } + + /** + * Registers the CSS relevant to the TKeyboard. + * It will register the CSS file specified by {@link getCssUrl CssUrl}. + * If that is not set, it will use the default CSS. + */ + protected function registerStyleSheet() + { + if(($url=$this->getCssUrl())==='') + $url=$this->publishAsset('keyboard.css',__CLASS__); + $this->getPage()->getClientScript()->registerStyleSheetFile($url,$url); + } + + /** + * Registers the relevant JavaScript. + */ + protected function registerClientScript() + { + $options=TJavaScript::encode($this->getClientOptions()); + $className=$this->getClientClassName(); + $cs=$this->getPage()->getClientScript(); + $cs->registerPradoScript('prado'); + $cs->registerEndScript('prado:'.$this->getClientID(), "new $className($options);"); + } + + protected function getClientClassName() + { + return 'Prado.WebUI.TKeyboard'; + } + + protected function getClientOptions() + { + if(($forControl=$this->getForControl())==='') + throw new TConfigurationException('keyboard_forcontrol_required'); + if(($target=$this->findControl($forControl))===null) + throw new TConfigurationException('keyboard_forcontrol_invalid',$forControl); + + $options['ID'] = $this->getClientID(); + $options['ForControl'] = $target->getClientID(); + $options['AutoHide'] = $this->getAutoHide(); + $options['CssClass'] = $this->getKeyboardCssClass(); + + return $options; + } +} + +?> \ No newline at end of file diff --git a/framework/Web/UI/WebControls/keyboard.css b/framework/Web/UI/WebControls/keyboard.css new file mode 100644 index 00000000..ad88d76b --- /dev/null +++ b/framework/Web/UI/WebControls/keyboard.css @@ -0,0 +1,80 @@ +div.Keyboard +{ + -moz-background-clip: -moz-initial; + -moz-background-origin: -moz-initial; + -moz-background-inline-policy: -moz-initial; + -moz-user-select: none; + + display: block; + position: absolute; + border: 1px solid #698977; + background-color: #DDDDDD; + z-index: 1000 !important; + visibility: hidden; + padding: 4px 4px 4px 4px; + text-align: center; +} + +div.Keyboard div.Line +{ + width: 267px; + height: 18px; +} + +div.Keyboard div.Key +{ + width: 17px; + height: 17px; + margin: 1px 0px 0px 1px; + overflow: hidden; + float: left; + display: inline; +} + +div.Keyboard div.Key div.Key1, +div.Keyboard div.Key div.Key2 +{ + overflow: hidden; + border: 1px solid #A5A5A5; + background-color: #F7F7F7; + font-family: Verdana, Arial, Helvetica, sans-serif; + font-size: 11px; + color: #556C5F; + font-weight: normal; + text-align: center; + line-height: 15px; + vertical-align: middle; + display: block; + cursor: pointer; +} + +div.Keyboard div.Key div.Hover +{ + color: #E02C03; + border-color: #E0431D; +} + +div.Keyboard div.Key div.Active +{ + color: #FFFFFF; + background-color: #E0431D; +} + +div.Keyboard.Shift div.Key div.Key1, +div.Keyboard.Caps div.L div.Key1, +div.Keyboard.Off div.Key div.Key2 +{ + display: none; +} + +div.Keyboard.Caps div.L div.Key2 +{ + display: block; +} + +div.Keyboard div.Bksp {width: 31px;} +div.Keyboard div.Exit {width: 33px;} +div.Keyboard div.Caps {width: 33px;} +div.Keyboard div.\\ {width: 24px;} +div.Keyboard div.Del {width: 24px;} +div.Keyboard div.Shift {width: 42px;} \ No newline at end of file -- cgit v1.2.3