var SuperclassInput = Class.create(JSControl, { explainer: {"msg": ""}, disabled: false, initialize: function(element, button){ element.JSControl = this; this.element = $(element); this.inputSize = this.element.readAttribute("size"); if (typeof button != "undefined"){ this.button = $(button); if (this.button && typeof this.setCurrent == "function") Event.observe(this.button, "dblclick", this.setCurrent.bindAsEventListener(this)); } this.id = this.element.readAttribute("id"); }, GetElement: function(){ return this.element; }, completeInitialization: function(){ this.setEventListeners(); this.hint = new InputHint(this.element, this.formatToDisplay, function(){ return !this.disabled(); }.bind(this)); }, setEventListeners: function(){ Event.observe(this.element, "focus", this.onfocus.bindAsEventListener(this)); Event.observe(this.element, "blur", this.onblur.bindAsEventListener(this)); Event.observe(this.element, "keypress", this.onkeypress.bindAsEventListener(this)); if (this.button){ Event.observe(this.button, "click", this.onfocus.bind(this)); } }, hintIsVisible: function(){ return this.hint && this.hint.IsVisible(); }, showHint: function(){ if (this.hint) this.hint.show(); }, hideHint: function(){ if (this.hint) this.hint.hide(); }, setErrorMessage: function(str, silent){ if (typeof silent == "undefined") silent = false; if (!silent) this.explainer.msg = str; }, setErrorSource: function(str, silent){ if (typeof silent == "undefined") silent = false; if (!silent) this.explainer.errorSource = str; }, clearErrorMessage: function(silent){ this.setErrorMessage("", silent); this.setErrorSource("", silent); }, getErrorMessage: function(){ var errsrc = this.explainer.errorSource; return (errsrc && errsrc.length > 0 ? errsrc + ": " : "") + this.explainer.msg; }, displayErrorMessage: function(){ ShowTip(this.element, this.getErrorMessage()); new BlinkAnimation(this.element); }, clear: function(){ this.hideHint(); this.element.value = ""; if (this.auxSpan) this.auxSpan.innerHTML=""; this.showHint(); this.check_state(true); }, ID: function(){ return this.id; }, onclick: function(){ if ("link" == this.visibility_) new AEvent("CLICK", {}, this); }, onfocus: function(){ if (this.disabled()) return; this.set_state(true); this.onfocusValue = this.Value().toString(); this.insertMode = true; }, getModifiedStr: function(str, newch, ss, se){ if (typeof se == "undefined") se = ss; return str.substr(0, ss) + newch + str.substr(se); }, incorrectFormatMessage: "", checkSyntax: function(str, silent, fullCheck){ var syntax = fullCheck ? this.syntaxFull : this.syntax; if (!syntax) return true; if (syntax.test(str)) return true; this.setErrorMessage(this.incorrectFormatMessage, silent); return false; }, checkSemantics: function(str, silent, fullCheck){ return true; }, check: function(str, silent, fullCheck){ if (typeof fullCheck == "undefined") fullCheck = false; this.clearErrorMessage(silent); return this.checkSyntax(str, silent, fullCheck) && this.checkSemantics(str, silent, fullCheck); }, autoModify: function(str, ss, se){ return {"str": str, "ss": ss, "se": se}; }, modify: function(str, newch, ss, se){ // if (ss == str.length && this.check(str, true, true)) return {"str": str, "ss": ss, "se": ss, "error": false}; if (typeof this.preModify == "function"){ var preModified = this.preModify(str, newch, ss, se); str = preModified.str; ss = preModified.ss; se = preModified.se; } var newstr = this.getModifiedStr(str, newch, ss, se); if (this.check(newstr, false, false)){ ss += newch.length; se = ss; return newch.length > 0 && typeof this.autoModify == "function" ? // Object.extend(this.autoModify(newstr, ss, se), {"error": false}) : // {"str": newstr, "ss": ss, "se": se, "error": false}; }else return {"str": str, "ss": ss, "se": ss, "error": true, "newstr": newstr}; }, remove: function(str, ss, se){ return this.modify(str, "", ss, se); }, processResult: function(result){ this.element.value = result.str; setSelectionRange(this.element, result.ss, // this.insertMode ? Math.min(result.str.length, Math.max(result.ss + 1, result.se)): result.se); if (result.error){ this.setErrorSource(result.newstr); this.displayErrorMessage(); }else HideTip(); }, getSelectionStart: function(element) { if (Prototype.Browser.IE){ var docRange = document.selection.createRange(); var eleRange = element.createTextRange(); docRange.setEndPoint("EndToStart",eleRange); return docRange.text.length; }else return element.selectionStart; }, getSelectionEnd: function(element) { if(Prototype.Browser.IE) { var docRange=document.selection.createRange(); var eleRange=element.createTextRange(); docRange.setEndPoint("StartToStart",eleRange); return docRange.text.length; } else return element.selectionEnd; }, onkeypress: function(event){ if (this.disabled()) return; var keycode = event.keyCode; if (event.altKey || event.ctrlKey && keycode != Event.KEY_BACKSPACE && keycode != Event.KEY_DELETE || // event.shiftKey && event.ctrlKey && keycode == Event.KEY_DELETE) return; var val = this.element.value; var ss = this.getSelectionStart(this.element); var se = this.getSelectionEnd(this.element); switch (keycode){ case Event.KEY_TAB: return; case Event.KEY_BACKSPACE: Event.stop(event); if (!event.ctrlKey && this.delimiter && se == val.length && ss == se && val.endsWith(this.delimiter)) return this.processResult(this.remove(val, Math.max(0, val.length - this.delimiter.length - 1), val.length)); return this.processResult(this.remove(val, event.ctrlKey ? 0 : Math.max(0, Math.min(se - 1, ss)), se)); case Event.KEY_DELETE: Event.stop(event); return this.processResult(this.remove(val, ss, event.ctrlKey ? val.length : Math.min(val.length, Math.max(ss + 1, se)))); case Event.KEY_INSERT: Event.stop(event); this.insertMode = !this.insertMode; if (this.insertMode && ss == se && ss < val.length) setSelectionRange(this.element, ss, ss + 1); if (!this.insertMode && ss < se) setSelectionRange(this.element, ss, ss); break; case Event.KEY_LEFT: case Event.KEY_RIGHT: case Event.KEY_HOME: if (event.shiftKey || !this.insertMode) break; Event.stop(event); switch (keycode){ case Event.KEY_LEFT: ss = Math.max(0, ss - 1); break; case Event.KEY_RIGHT: ss = Math.min(val.length, ss + 1); break; case Event.KEY_HOME: ss = 0; break; } se = Math.min(val.length, ss + 1); setSelectionRange(this.element, ss, se); break; default: var charCode = this.getCharCode(event); if (!SuperclassInput.isVisibleCharacter(charCode)) break; Event.stop(event); return this.processResult(this.modify(val, String.fromCharCode(charCode), ss, se)); } HideTip(); }, onblur: function(){ if (this.disabled()) return; if (this.onfocusValue != this.Value().toString()) this.onchange(); if (typeof this.ultimateTest != "function" || this.ultimateTest()) HideTip(); else{ this.displayErrorMessage(); this.postBlurTipHidden = false; Event.observe(document, "mousedown", this.hideTipAfterBlurCallback); this.hideTipAfterBlurCallback.bind(this).delay(2); } this.check_state(); }, hideTipAfterBlurCallback: function(){ if (this.postBlurTipHidden) return; HideTip(); Event.stopObserving(document, "mousedown", this.hideTipAfterBlurCallback); this.postBlurTipHidden = true; }, onchange: function(){ new AEvent("CHANGE", null, this); }, SetTabOrder: function(nTabBase){ this.tabbase_ = this.element.tabIndex = nTabBase; if (typeof this.button != "undefined") this.button.tabIndex = ++nTabBase; return ++nTabBase; }, getCharCode: function(event){ if (!event) return 0; if (typeof event.charCode != "undefined") return event.charCode; if (typeof event.which != "undefined") return event.which; return event.keyCode; }, SetValue: function(val){ if (this.auxSpan) { this.auxSpan.innerHTML=this.element.value; } this.check_state(); }, check_state: function(){ var val = this.Value(); var badstate = !this.disabled() && (this.element.value && !this.hintIsVisible()) &&// typeof val.IsIncorrect === "function" && val.IsIncorrect(); this.set_state(!badstate); }, set_state: function(goodstate){ Element[goodstate ? "removeClassName" : "addClassName"](this.element, "Bad"); this.element.setAttribute("title", goodstate ? "" : this.getErrorMessage()); }, disabled: function(){ return typeof this.visibility_ != "undefined" && this.visibility_ != "yes"; }, SetAttribute: function(nam, val){ switch (nam){ case "title": this.title_ = val; break; case "class": case "disabled": break; case "visibility": if (["yes", "ro", "vo", "link", "no"].indexOf(val) == -1) return; if (typeof this.visibility_ == "undefined") this.visibility_ = "yes"; if (val == this.visibility_) return; var disabled = "yes" != val; this.element.readOnly = disabled; this[disabled ? "hideHint" : "showHint"](); if (this.button) Element.setStyle(this.button, {"display": (disabled ? "none" : "")}); Element.setStyle(this.element, {"display": ((["yes", "ro"].indexOf(val) != -1) ? "" : "none")}); Element["ro" == val ? "addClassName" : "removeClassName"](this.element, "RO"); if (disabled) this.element.tabIndex = -1; else if (typeof this.tabbase_ != "undefined") this.SetTabOrder(this.tabbase_); if (["vo", "link"].indexOf(val) == -1){ if (this.auxSpan && this.auxSpan.parentNode) this.auxSpan.parentNode.removeChild(this.auxSpan); }else{ if (!this.auxSpan){ this.auxSpan = document.createElement("span"); this.auxSpan.setAttribute("class", "SuperclassInput"); this.auxSpan.setAttribute("style", this.element.getAttribute("style")); Event.observe(this.auxSpan, "click", this.onclick.bindAsEventListener(this)); }else{ while (this.auxSpan.firstChild) this.auxSpan.removeChild(this.auxSpan.firstChild); } if (!this.auxSpan.parentNode) Element.insert(this.element, {"before": this.auxSpan}); Element.setStyle(this.auxSpan, {"display": ""}); Element["link" == val ? "addClassName" : "removeClassName"](this.auxSpan, "Link"); this.auxSpan.appendChild(document.createTextNode(this.element.value)); } this.visibility_ = val; default: Element.writeAttribute(this.element, nam, val); if (this.auxSpan) Element.writeAttribute(this.auxSpan, nam, val); break; } } }); SuperclassInput.addBackslashForRegexp = function(str){ return String(str).replace(/([\^\$\.\*\+\?\=\!\:\|\\\/\(\)\[\]\{\}])/g, "\\$1"); }; SuperclassInput.constructPartialMatchFromArray = function(array, includeEmpty){ if (array.length == 0) return ""; if (typeof includeEmpty == "undefined") includeEmpty = true; var firstElement = String(array.shift()); var otherElements = SuperclassInput.constructPartialMatchFromArray(array, includeEmpty); return includeEmpty ? // "(?:" + firstElement + otherElements + ")?" : // firstElement + (otherElements.length > 0 ? "(?:" + otherElements + ")?" : ""); }; SuperclassInput.constructPartialMatch = function(str, includeEmpty){ return SuperclassInput.constructPartialMatchFromArray(str.split("").collect( function(char){ return SuperclassInput.addBackslashForRegexp(char); } ), includeEmpty); }; SuperclassInput.isVisibleCharacter = function(charCode){ return charCode >= 0x20; }; SuperclassInput.keypress_name = function(){ return Prototype.Browser.IE || Prototype.Browser.WebKit ? "keydown" : "keypress"; }; var BlinkAnimation = Class.create({ errorClassName: "Error", initialize: function(element, errorClassName){ this.element = $(element); if (!this.element) return; if (typeof errorClassName != "undefined") this.errorClassName = errorClassName; if (typeof this.element.blinkAnimation == "object" && typeof this.element.blinkAnimation.cleanup == "function") this.element.blinkAnimation.cleanup(); this.element.blinkAnimation = this; this.style_ = JSControl.parseStyle(this.element.getAttribute("style")); var color = Element.getStyle(this.element, "backgroundColor"); Element.setStyle(this.element, {"backgroundColor": ""}); Element.addClassName(this.element, this.errorClassName); var errBG = Element.getStyle(this.element, "backgroundColor"); this.animation = new Animation(this.element, 6); this.animation.addAnimation("backgroundColor", getHexRGBColor(errBG), getHexRGBColor(color)); this.animation.run(); this.animation.onfinish = this.cleanup.bind(this); }, cleanup: function(){ if (this.animation && typeof this.animation.stop == "function") this.animation.stop(); delete this.animation; Element.removeClassName(this.element, this.errorClassName); Element.setStyle(this.element, {"backgroundColor": this.style_.backgroundColor || ""}); delete this.style_; try{ delete this.element.blinkAnimation; }catch(err){ this.element.blinkAnimation = 0; } //for IE exclusively } }); var InputHint = Class.create({ isAllowed: function(){ return true; }, initialize: function(input, hint, isAllowed){ if (!Element.match(input, "input")) return; this.input = $(input); this.hint = String(hint); if (typeof isAllowed == "function") this.isAllowed = isAllowed; this.setEventListeners(); this.show(); }, setEventListeners: function(){ Event.observe(this.input, "focus", this.onfocus.bind(this)); Event.observe(this.input, "blur", this.show.bind(this)); }, className: "Hint", isVisible: false, show: function(){ if (this.isVisible || this.input.value.length != 0 || !this.isAllowed()) return; Element.addClassName(this.input, this.className); this.input.value = this.hint; this.isVisible = true; }, hide: function(){ if (!this.isVisible) return; Element.removeClassName(this.input, this.className); this.input.value = ""; this.isVisible = false; }, onfocus: function(){ this.hide(); if (!this.input.value) Form.Element.activate(this.input); }, IsVisible: function(){ return this.isVisible; } }); var SIPopupOpener = Class.create({ initialize: function(switcher, params){ this.switcher = $(switcher); if (!this.switcher) return; this.params = params || {}; Event.observe(this.switcher, "click", this.toggleOpen.bindAsEventListener(this)); Event.observe(this.switcher, "keydown", this.OnKeyDown.bindAsEventListener(this)); if (Prototype.Browser.IE) Event.observe(this.switcher, "dblclick", this.toggleOpen.bindAsEventListener(this)); var awnd = this.awindow(); if (awnd) awnd.Subscribe("WM_DESTROY", this.DESTROY, this); }, awindow: function(){ return AControl.GetParentWindow(this.switcher); }, OnKeyDown: function(event) { if(event.ctrlKey || event.altKey) return; var key = event.which || event.keyCode; if(key==Event.KEY_RETURN) { this.toggleOpen(); Event.stop(event); return false; } }, toggleOpen: function(){ if (typeof this.timer_ != "undefined"){ window.clearTimeout(this.timer_); delete this.timer_; }else{ var func = this.visible_ ? "Hide" : "Show"; this.timer_ = window.setTimeout(function(){ this[func](); delete this.timer_; }.bind(this), 300); } }, Show: function(){ if (this.visible_) return; this.touch(); this.position(); if (typeof this.callbacks_ == "undefined"){ var ondocclick = this.ondocclick.bindAsEventListener(this); this.callbacks_ = [ [document, "click", ondocclick], [document, "mousedown", ondocclick] ]; } this.callbacks_.each(function(args){ Event.observe.apply(null, args); }); this.popup.Show(); GPopupContainer.Activate(this.popup); var focusable = JSControl.FindFirstFocusable(this.popup.Contents()); if (focusable) focusable.focus(); Element.fire(this.switcher, "SI:SHOW", this); this.visible_ = true; }, Hide: function(){ if (!this.visible_) return; this.popup.Hide(); if (typeof this.callbacks_ != "undefined") this.callbacks_.each(function(args){ Event.stopObserving.apply(null, args); }); this.switcher.focus(); this.visible_ = false; }, ondocclick: function(event){ var element = Event.element(event); if (!element) return; if (!XMLElement.DescendantOrSelf(element, this.switcher) && !XMLElement.DescendantOrSelf(element, this.popup.div)) this.Hide(); }, touch: function(){ if (this.popup) return; this.popup = new APopup({ "showState": "hidden", "showHeader": true, "canResize": false, "fCloseCallback": this.Hide.bind(this) }); var contents = this.popup.Contents(); var html = String(typeof this.params.html == "function" ? this.params.html() : this.params.html); var scripts = html.extractScripts(); contents.innerHTML = html.stripScripts(); // avoid empty tags in $html since Opera sucks here for (var iii = 0; iii < scripts.length; ++iii) try{ eval(scripts[iii]); }catch(err){ alert(["ERROR in eval:", "Error name: " + err.name, "Error message: " + err.message,// "========== SCRIPT ==========", scripts[iii]].join("\n")); LogL(scripts[iii]); throw err; } if (typeof this.tabbase != "undefined"){ var tabbase = this.tabbase; JSControl.GetChildControls(contents).each(function(jscontrol){ if (typeof jscontrol.SetTabOrder == "function") tabbase = jscontrol.SetTabOrder(tabbase); }); } }, SetTabOrder: function(tabbase){ if (typeof this.params.tablimit == "undefined") return tabbase; this.tabbase = tabbase; return tabbase + this.params.tablimit; }, position: function(){ this.popup.SetPosition(0, 0); var aln = $(this.params["align-id"]) || this.switcher; var pos = Element.cumulativeOffset(aln); var scrl = Element.cumulativeScrollOffset(aln) pos.top -= scrl.top; pos.left -= scrl.left; var pup = Element.getDimensions(this.popup.div); var wnd = {"width": document.body.scrollWidth, "height": document.body.scrollHeight}; var pos = { "left": Math.max(0, Math.min(pos.left, wnd.width - pup.width)), "top": Math.max(0, Math.min(pos.top + aln.offsetHeight, wnd.height - pup.height)) }; this.popup.SetPosition(pos.left, pos.top); }, DESTROY: function(aevent){ var emitter = aevent.Emitter(); if (emitter && this.popup && emitter == this.awindow()) this.popup.Close(); } });