diff options
Diffstat (limited to 'javascript/MochiKit/Controls.js')
| -rwxr-xr-x | javascript/MochiKit/Controls.js | 1388 |
1 files changed, 0 insertions, 1388 deletions
diff --git a/javascript/MochiKit/Controls.js b/javascript/MochiKit/Controls.js deleted file mode 100755 index c044ef2..0000000 --- a/javascript/MochiKit/Controls.js +++ /dev/null @@ -1,1388 +0,0 @@ -/*** -Copyright (c) 2005 Thomas Fuchs (http://script.aculo.us, http://mir.aculo.us) - (c) 2005 Ivan Krstic (http://blogs.law.harvard.edu/ivan) - (c) 2005 Jon Tirsen (http://www.tirsen.com) -Contributors: - Richard Livsey - Rahul Bhargava - Rob Wills - Mochi-ized By Thomas Herve (_firstname_@nimail.org) - -See scriptaculous.js for full license. - -Autocompleter.Base handles all the autocompletion functionality -that's independent of the data source for autocompletion. This -includes drawing the autocompletion menu, observing keyboard -and mouse events, and similar. - -Specific autocompleters need to provide, at the very least, -a getUpdatedChoices function that will be invoked every time -the text inside the monitored textbox changes. This method -should get the text for which to provide autocompletion by -invoking this.getToken(), NOT by directly accessing -this.element.value. This is to allow incremental tokenized -autocompletion. Specific auto-completion logic (AJAX, etc) -belongs in getUpdatedChoices. - -Tokenized incremental autocompletion is enabled automatically -when an autocompleter is instantiated with the 'tokens' option -in the options parameter, e.g.: -new Ajax.Autocompleter('id','upd', '/url/', { tokens: ',' }); -will incrementally autocomplete with a comma as the token. -Additionally, ',' in the above example can be replaced with -a token array, e.g. { tokens: [',', '\n'] } which -enables autocompletion on multiple tokens. This is most -useful when one of the tokens is \n (a newline), as it -allows smart autocompletion after linebreaks. - -***/ - -MochiKit.Base.update(MochiKit.Base, { - ScriptFragment: '(?:<script.*?>)((\n|\r|.)*?)(?:<\/script>)', - -/** @id MochiKit.Base.stripScripts */ - stripScripts: function (str) { - return str.replace(new RegExp(MochiKit.Base.ScriptFragment, 'img'), ''); - }, - -/** @id MochiKit.Base.stripTags */ - stripTags: function(str) { - return str.replace(/<\/?[^>]+>/gi, ''); - }, - -/** @id MochiKit.Base.extractScripts */ - extractScripts: function (str) { - var matchAll = new RegExp(MochiKit.Base.ScriptFragment, 'img'); - var matchOne = new RegExp(MochiKit.Base.ScriptFragment, 'im'); - return MochiKit.Base.map(function (scriptTag) { - return (scriptTag.match(matchOne) || ['', ''])[1]; - }, str.match(matchAll) || []); - }, - -/** @id MochiKit.Base.evalScripts */ - evalScripts: function (str) { - return MochiKit.Base.map(function (scr) { - eval(scr); - }, MochiKit.Base.extractScripts(str)); - } -}); - -MochiKit.Form = { - -/** @id MochiKit.Form.serialize */ - serialize: function (form) { - var elements = MochiKit.Form.getElements(form); - var queryComponents = []; - - for (var i = 0; i < elements.length; i++) { - var queryComponent = MochiKit.Form.serializeElement(elements[i]); - if (queryComponent) { - queryComponents.push(queryComponent); - } - } - - return queryComponents.join('&'); - }, - -/** @id MochiKit.Form.getElements */ - getElements: function (form) { - form = MochiKit.DOM.getElement(form); - var elements = []; - - for (var tagName in MochiKit.Form.Serializers) { - var tagElements = form.getElementsByTagName(tagName); - for (var j = 0; j < tagElements.length; j++) { - elements.push(tagElements[j]); - } - } - return elements; - }, - -/** @id MochiKit.Form.serializeElement */ - serializeElement: function (element) { - element = MochiKit.DOM.getElement(element); - var method = element.tagName.toLowerCase(); - var parameter = MochiKit.Form.Serializers[method](element); - - if (parameter) { - var key = encodeURIComponent(parameter[0]); - if (key.length === 0) { - return; - } - - if (!(parameter[1] instanceof Array)) { - parameter[1] = [parameter[1]]; - } - - return parameter[1].map(function (value) { - return key + '=' + encodeURIComponent(value); - }).join('&'); - } - } -}; - -MochiKit.Form.Serializers = { - -/** @id MochiKit.Form.Serializers.input */ - input: function (element) { - switch (element.type.toLowerCase()) { - case 'submit': - case 'hidden': - case 'password': - case 'text': - return MochiKit.Form.Serializers.textarea(element); - case 'checkbox': - case 'radio': - return MochiKit.Form.Serializers.inputSelector(element); - } - return false; - }, - -/** @id MochiKit.Form.Serializers.inputSelector */ - inputSelector: function (element) { - if (element.checked) { - return [element.name, element.value]; - } - }, - -/** @id MochiKit.Form.Serializers.textarea */ - textarea: function (element) { - return [element.name, element.value]; - }, - -/** @id MochiKit.Form.Serializers.select */ - select: function (element) { - return MochiKit.Form.Serializers[element.type == 'select-one' ? - 'selectOne' : 'selectMany'](element); - }, - -/** @id MochiKit.Form.Serializers.selectOne */ - selectOne: function (element) { - var value = '', opt, index = element.selectedIndex; - if (index >= 0) { - opt = element.options[index]; - value = opt.value; - if (!value && !('value' in opt)) { - value = opt.text; - } - } - return [element.name, value]; - }, - -/** @id MochiKit.Form.Serializers.selectMany */ - selectMany: function (element) { - var value = []; - for (var i = 0; i < element.length; i++) { - var opt = element.options[i]; - if (opt.selected) { - var optValue = opt.value; - if (!optValue && !('value' in opt)) { - optValue = opt.text; - } - value.push(optValue); - } - } - return [element.name, value]; - } -}; - -/** @id Ajax */ -var Ajax = { - activeRequestCount: 0 -}; - -Ajax.Responders = { - responders: [], - -/** @id Ajax.Responders.register */ - register: function (responderToAdd) { - if (MochiKit.Base.find(this.responders, responderToAdd) == -1) { - this.responders.push(responderToAdd); - } - }, - -/** @id Ajax.Responders.unregister */ - unregister: function (responderToRemove) { - this.responders = this.responders.without(responderToRemove); - }, - -/** @id Ajax.Responders.dispatch */ - dispatch: function (callback, request, transport, json) { - MochiKit.Iter.forEach(this.responders, function (responder) { - if (responder[callback] && - typeof(responder[callback]) == 'function') { - try { - responder[callback].apply(responder, [request, transport, json]); - } catch (e) {} - } - }); - } -}; - -Ajax.Responders.register({ - -/** @id Ajax.Responders.onCreate */ - onCreate: function () { - Ajax.activeRequestCount++; - }, - -/** @id Ajax.Responders.onComplete */ - onComplete: function () { - Ajax.activeRequestCount--; - } -}); - -/** @id Ajax.Base */ -Ajax.Base = function () {}; - -Ajax.Base.prototype = { - -/** @id Ajax.Base.prototype.setOptions */ - setOptions: function (options) { - this.options = { - method: 'post', - asynchronous: true, - parameters: '' - } - MochiKit.Base.update(this.options, options || {}); - }, - -/** @id Ajax.Base.prototype.responseIsSuccess */ - responseIsSuccess: function () { - return this.transport.status == undefined - || this.transport.status === 0 - || (this.transport.status >= 200 && this.transport.status < 300); - }, - -/** @id Ajax.Base.prototype.responseIsFailure */ - responseIsFailure: function () { - return !this.responseIsSuccess(); - } -}; - -/** @id Ajax.Request */ -Ajax.Request = function (url, options) { - this.__init__(url, options); -}; - -/** @id Ajax.Events */ -Ajax.Request.Events = ['Uninitialized', 'Loading', 'Loaded', - 'Interactive', 'Complete']; - -MochiKit.Base.update(Ajax.Request.prototype, Ajax.Base.prototype); - -MochiKit.Base.update(Ajax.Request.prototype, { - __init__: function (url, options) { - this.transport = MochiKit.Async.getXMLHttpRequest(); - this.setOptions(options); - this.request(url); - }, - -/** @id Ajax.Request.prototype.request */ - request: function (url) { - var parameters = this.options.parameters || ''; - if (parameters.length > 0){ - parameters += '&_='; - } - - try { - this.url = url; - if (this.options.method == 'get' && parameters.length > 0) { - this.url += (this.url.match(/\?/) ? '&' : '?') + parameters; - } - Ajax.Responders.dispatch('onCreate', this, this.transport); - - this.transport.open(this.options.method, this.url, - this.options.asynchronous); - - if (this.options.asynchronous) { - this.transport.onreadystatechange = MochiKit.Base.bind(this.onStateChange, this); - setTimeout(MochiKit.Base.bind(function () { - this.respondToReadyState(1); - }, this), 10); - } - - this.setRequestHeaders(); - - var body = this.options.postBody ? this.options.postBody : parameters; - this.transport.send(this.options.method == 'post' ? body : null); - - } catch (e) { - this.dispatchException(e); - } - }, - -/** @id Ajax.Request.prototype.setRequestHeaders */ - setRequestHeaders: function () { - var requestHeaders = ['X-Requested-With', 'XMLHttpRequest']; - - if (this.options.method == 'post') { - requestHeaders.push('Content-type', - 'application/x-www-form-urlencoded'); - - /* Force 'Connection: close' for Mozilla browsers to work around - * a bug where XMLHttpRequest sends an incorrect Content-length - * header. See Mozilla Bugzilla #246651. - */ - if (this.transport.overrideMimeType) { - requestHeaders.push('Connection', 'close'); - } - } - - if (this.options.requestHeaders) { - requestHeaders.push.apply(requestHeaders, this.options.requestHeaders); - } - - for (var i = 0; i < requestHeaders.length; i += 2) { - this.transport.setRequestHeader(requestHeaders[i], requestHeaders[i+1]); - } - }, - -/** @id Ajax.Request.prototype.onStateChange */ - onStateChange: function () { - var readyState = this.transport.readyState; - if (readyState != 1) { - this.respondToReadyState(this.transport.readyState); - } - }, - -/** @id Ajax.Request.prototype.header */ - header: function (name) { - try { - return this.transport.getResponseHeader(name); - } catch (e) {} - }, - -/** @id Ajax.Request.prototype.evalJSON */ - evalJSON: function () { - try { - return eval(this.header('X-JSON')); - } catch (e) {} - }, - -/** @id Ajax.Request.prototype.evalResponse */ - evalResponse: function () { - try { - return eval(this.transport.responseText); - } catch (e) { - this.dispatchException(e); - } - }, - -/** @id Ajax.Request.prototype.respondToReadyState */ - respondToReadyState: function (readyState) { - var event = Ajax.Request.Events[readyState]; - var transport = this.transport, json = this.evalJSON(); - - if (event == 'Complete') { - try { - (this.options['on' + this.transport.status] - || this.options['on' + (this.responseIsSuccess() ? 'Success' : 'Failure')] - || MochiKit.Base.noop)(transport, json); - } catch (e) { - this.dispatchException(e); - } - - if ((this.header('Content-type') || '').match(/^text\/javascript/i)) { - this.evalResponse(); - } - } - - try { - (this.options['on' + event] || MochiKit.Base.noop)(transport, json); - Ajax.Responders.dispatch('on' + event, this, transport, json); - } catch (e) { - this.dispatchException(e); - } - - /* Avoid memory leak in MSIE: clean up the oncomplete event handler */ - if (event == 'Complete') { - this.transport.onreadystatechange = MochiKit.Base.noop; - } - }, - -/** @id Ajax.Request.prototype.dispatchException */ - dispatchException: function (exception) { - (this.options.onException || MochiKit.Base.noop)(this, exception); - Ajax.Responders.dispatch('onException', this, exception); - } -}); - -/** @id Ajax.Updater */ -Ajax.Updater = function (container, url, options) { - this.__init__(container, url, options); -}; - -MochiKit.Base.update(Ajax.Updater.prototype, Ajax.Request.prototype); - -MochiKit.Base.update(Ajax.Updater.prototype, { - __init__: function (container, url, options) { - this.containers = { - success: container.success ? MochiKit.DOM.getElement(container.success) : MochiKit.DOM.getElement(container), - failure: container.failure ? MochiKit.DOM.getElement(container.failure) : - (container.success ? null : MochiKit.DOM.getElement(container)) - } - this.transport = MochiKit.Async.getXMLHttpRequest(); - this.setOptions(options); - - var onComplete = this.options.onComplete || MochiKit.Base.noop; - this.options.onComplete = MochiKit.Base.bind(function (transport, object) { - this.updateContent(); - onComplete(transport, object); - }, this); - - this.request(url); - }, - -/** @id Ajax.Updater.prototype.updateContent */ - updateContent: function () { - var receiver = this.responseIsSuccess() ? - this.containers.success : this.containers.failure; - var response = this.transport.responseText; - - if (!this.options.evalScripts) { - response = MochiKit.Base.stripScripts(response); - } - - if (receiver) { - if (this.options.insertion) { - new this.options.insertion(receiver, response); - } else { - MochiKit.DOM.getElement(receiver).innerHTML = - MochiKit.Base.stripScripts(response); - setTimeout(function () { - MochiKit.Base.evalScripts(response); - }, 10); - } - } - - if (this.responseIsSuccess()) { - if (this.onComplete) { - setTimeout(MochiKit.Base.bind(this.onComplete, this), 10); - } - } - } -}); - -/** @id Field */ -var Field = { - -/** @id clear */ - clear: function () { - for (var i = 0; i < arguments.length; i++) { - MochiKit.DOM.getElement(arguments[i]).value = ''; - } - }, - -/** @id focus */ - focus: function (element) { - MochiKit.DOM.getElement(element).focus(); - }, - -/** @id present */ - present: function () { - for (var i = 0; i < arguments.length; i++) { - if (MochiKit.DOM.getElement(arguments[i]).value == '') { - return false; - } - } - return true; - }, - -/** @id select */ - select: function (element) { - MochiKit.DOM.getElement(element).select(); - }, - -/** @id activate */ - activate: function (element) { - element = MochiKit.DOM.getElement(element); - element.focus(); - if (element.select) { - element.select(); - } - }, - -/** @id scrollFreeActivate */ - scrollFreeActivate: function (field) { - setTimeout(function () { - Field.activate(field); - }, 1); - } -}; - - -/** @id Autocompleter */ -var Autocompleter = {}; - -/** @id Autocompleter.Base */ -Autocompleter.Base = function () {}; - -Autocompleter.Base.prototype = { - -/** @id Autocompleter.Base.prototype.baseInitialize */ - baseInitialize: function (element, update, options) { - this.element = MochiKit.DOM.getElement(element); - this.update = MochiKit.DOM.getElement(update); - this.hasFocus = false; - this.changed = false; - this.active = false; - this.index = 0; - this.entryCount = 0; - - if (this.setOptions) { - this.setOptions(options); - } - else { - this.options = options || {}; - } - - this.options.paramName = this.options.paramName || this.element.name; - this.options.tokens = this.options.tokens || []; - this.options.frequency = this.options.frequency || 0.4; - this.options.minChars = this.options.minChars || 1; - this.options.onShow = this.options.onShow || function (element, update) { - if (!update.style.position || update.style.position == 'absolute') { - update.style.position = 'absolute'; - MochiKit.Position.clone(element, update, { - setHeight: false, - offsetTop: element.offsetHeight - }); - } - MochiKit.Visual.appear(update, {duration:0.15}); - }; - this.options.onHide = this.options.onHide || function (element, update) { - MochiKit.Visual.fade(update, {duration: 0.15}); - }; - - if (typeof(this.options.tokens) == 'string') { - this.options.tokens = new Array(this.options.tokens); - } - - this.observer = null; - - this.element.setAttribute('autocomplete', 'off'); - - MochiKit.Style.hideElement(this.update); - - MochiKit.Signal.connect(this.element, 'onblur', this, this.onBlur); - MochiKit.Signal.connect(this.element, 'onkeypress', this, this.onKeyPress, this); - }, - -/** @id Autocompleter.Base.prototype.show */ - show: function () { - if (MochiKit.Style.getStyle(this.update, 'display') == 'none') { - this.options.onShow(this.element, this.update); - } - if (!this.iefix && /MSIE/.test(navigator.userAgent && - (MochiKit.Style.getStyle(this.update, 'position') == 'absolute'))) { - new Insertion.After(this.update, - '<iframe id="' + this.update.id + '_iefix" '+ - 'style="display:none;position:absolute;filter:progid:DXImageTransform.Microsoft.Alpha(opacity=0);" ' + - 'src="javascript:false;" frameborder="0" scrolling="no"></iframe>'); - this.iefix = MochiKit.DOM.getElement(this.update.id + '_iefix'); - } - if (this.iefix) { - setTimeout(MochiKit.Base.bind(this.fixIEOverlapping, this), 50); - } - }, - -/** @id Autocompleter.Base.prototype.fixIEOverlapping */ - fixIEOverlapping: function () { - MochiKit.Position.clone(this.update, this.iefix); - this.iefix.style.zIndex = 1; - this.update.style.zIndex = 2; - MochiKit.Style.showElement(this.iefix); - }, - -/** @id Autocompleter.Base.prototype.hide */ - hide: function () { - this.stopIndicator(); - if (MochiKit.Style.getStyle(this.update, 'display') != 'none') { - this.options.onHide(this.element, this.update); - } - if (this.iefix) { - MochiKit.Style.hideElement(this.iefix); - } - }, - -/** @id Autocompleter.Base.prototype.startIndicator */ - startIndicator: function () { - if (this.options.indicator) { - MochiKit.Style.showElement(this.options.indicator); - } - }, - -/** @id Autocompleter.Base.prototype.stopIndicator */ - stopIndicator: function () { - if (this.options.indicator) { - MochiKit.Style.hideElement(this.options.indicator); - } - }, - -/** @id Autocompleter.Base.prototype.onKeyPress */ - onKeyPress: function (event) { - if (this.active) { - if (event.key().string == "KEY_TAB" || event.key().string == "KEY_RETURN") { - this.selectEntry(); - MochiKit.Event.stop(event); - } else if (event.key().string == "KEY_ESCAPE") { - this.hide(); - this.active = false; - MochiKit.Event.stop(event); - return; - } else if (event.key().string == "KEY_LEFT" || event.key().string == "KEY_RIGHT") { - return; - } else if (event.key().string == "KEY_UP") { - this.markPrevious(); - this.render(); - if (/AppleWebKit'/.test(navigator.appVersion)) { - event.stop(); - } - return; - } else if (event.key().string == "KEY_DOWN") { - this.markNext(); - this.render(); - if (/AppleWebKit'/.test(navigator.appVersion)) { - event.stop(); - } - return; - } - } else { - if (event.key().string == "KEY_TAB" || event.key().string == "KEY_RETURN") { - return; - } - } - - this.changed = true; - this.hasFocus = true; - - if (this.observer) { - clearTimeout(this.observer); - } - this.observer = setTimeout(MochiKit.Base.bind(this.onObserverEvent, this), - this.options.frequency*1000); - }, - -/** @id Autocompleter.Base.prototype.findElement */ - findElement: function (event, tagName) { - var element = event.target; - while (element.parentNode && (!element.tagName || - (element.tagName.toUpperCase() != tagName.toUpperCase()))) { - element = element.parentNode; - } - return element; - }, - -/** @id Autocompleter.Base.prototype.hover */ - onHover: function (event) { - var element = this.findElement(event, 'LI'); - if (this.index != element.autocompleteIndex) { - this.index = element.autocompleteIndex; - this.render(); - } - event.stop(); - }, - -/** @id Autocompleter.Base.prototype.onClick */ - onClick: function (event) { - var element = this.findElement(event, 'LI'); - this.index = element.autocompleteIndex; - this.selectEntry(); - this.hide(); - }, - -/** @id Autocompleter.Base.prototype.onBlur */ - onBlur: function (event) { - // needed to make click events working - setTimeout(MochiKit.Base.bind(this.hide, this), 250); - this.hasFocus = false; - this.active = false; - }, - -/** @id Autocompleter.Base.prototype.render */ - render: function () { - if (this.entryCount > 0) { - for (var i = 0; i < this.entryCount; i++) { - this.index == i ? - MochiKit.DOM.addElementClass(this.getEntry(i), 'selected') : - MochiKit.DOM.removeElementClass(this.getEntry(i), 'selected'); - } - if (this.hasFocus) { - this.show(); - this.active = true; - } - } else { - this.active = false; - this.hide(); - } - }, - -/** @id Autocompleter.Base.prototype.markPrevious */ - markPrevious: function () { - if (this.index > 0) { - this.index-- - } else { - this.index = this.entryCount-1; - } - }, - -/** @id Autocompleter.Base.prototype.markNext */ - markNext: function () { - if (this.index < this.entryCount-1) { - this.index++ - } else { - this.index = 0; - } - }, - -/** @id Autocompleter.Base.prototype.getEntry */ - getEntry: function (index) { - return this.update.firstChild.childNodes[index]; - }, - -/** @id Autocompleter.Base.prototype.getCurrentEntry */ - getCurrentEntry: function () { - return this.getEntry(this.index); - }, - -/** @id Autocompleter.Base.prototype.selectEntry */ - selectEntry: function () { - this.active = false; - this.updateElement(this.getCurrentEntry()); - }, - -/** @id Autocompleter.Base.prototype.collectTextNodesIgnoreClass */ - collectTextNodesIgnoreClass: function (element, className) { - return MochiKit.Base.flattenArray(MochiKit.Base.map(function (node) { - if (node.nodeType == 3) { - return node.nodeValue; - } else if (node.hasChildNodes() && !MochiKit.DOM.hasElementClass(node, className)) { - return this.collectTextNodesIgnoreClass(node, className); - } - return ''; - }, MochiKit.DOM.getElement(element).childNodes)).join(''); - }, - -/** @id Autocompleter.Base.prototype.updateElement */ - updateElement: function (selectedElement) { - if (this.options.updateElement) { - this.options.updateElement(selectedElement); - return; - } - var value = ''; - if (this.options.select) { - var nodes = document.getElementsByClassName(this.options.select, selectedElement) || []; - if (nodes.length > 0) { - value = MochiKit.DOM.scrapeText(nodes[0]); - } - } else { - value = this.collectTextNodesIgnoreClass(selectedElement, 'informal'); - } - var lastTokenPos = this.findLastToken(); - if (lastTokenPos != -1) { - var newValue = this.element.value.substr(0, lastTokenPos + 1); - var whitespace = this.element.value.substr(lastTokenPos + 1).match(/^\s+/); - if (whitespace) { - newValue += whitespace[0]; - } - this.element.value = newValue + value; - } else { - this.element.value = value; - } - this.element.focus(); - - if (this.options.afterUpdateElement) { - this.options.afterUpdateElement(this.element, selectedElement); - } - }, - -/** @id Autocompleter.Base.prototype.updateChoices */ - updateChoices: function (choices) { - if (!this.changed && this.hasFocus) { - this.update.innerHTML = choices; - var d = MochiKit.DOM; - d.removeEmptyTextNodes(this.update); - d.removeEmptyTextNodes(this.update.firstChild); - - if (this.update.firstChild && this.update.firstChild.childNodes) { - this.entryCount = this.update.firstChild.childNodes.length; - for (var i = 0; i < this.entryCount; i++) { - var entry = this.getEntry(i); - entry.autocompleteIndex = i; - this.addObservers(entry); - } - } else { - this.entryCount = 0; - } - - this.stopIndicator(); - - this.index = 0; - this.render(); - } - }, - -/** @id Autocompleter.Base.prototype.addObservers */ - addObservers: function (element) { - MochiKit.Signal.connect(element, 'onmouseover', this, this.onHover); - MochiKit.Signal.connect(element, 'onclick', this, this.onClick); - }, - -/** @id Autocompleter.Base.prototype.onObserverEvent */ - onObserverEvent: function () { - this.changed = false; - if (this.getToken().length >= this.options.minChars) { - this.startIndicator(); - this.getUpdatedChoices(); - } else { - this.active = false; - this.hide(); - } - }, - -/** @id Autocompleter.Base.prototype.getToken */ - getToken: function () { - var tokenPos = this.findLastToken(); - if (tokenPos != -1) { - var ret = this.element.value.substr(tokenPos + 1).replace(/^\s+/,'').replace(/\s+$/,''); - } else { - var ret = this.element.value; - } - return /\n/.test(ret) ? '' : ret; - }, - -/** @id Autocompleter.Base.prototype.findLastToken */ - findLastToken: function () { - var lastTokenPos = -1; - - for (var i = 0; i < this.options.tokens.length; i++) { - var thisTokenPos = this.element.value.lastIndexOf(this.options.tokens[i]); - if (thisTokenPos > lastTokenPos) { - lastTokenPos = thisTokenPos; - } - } - return lastTokenPos; - } -} - -/** @id Ajax.Autocompleter */ -Ajax.Autocompleter = function (element, update, url, options) { - this.__init__(element, update, url, options); -}; - -MochiKit.Base.update(Ajax.Autocompleter.prototype, Autocompleter.Base.prototype); - -MochiKit.Base.update(Ajax.Autocompleter.prototype, { - __init__: function (element, update, url, options) { - this.baseInitialize(element, update, options); - this.options.asynchronous = true; - this.options.onComplete = MochiKit.Base.bind(this.onComplete, this); - this.options.defaultParams = this.options.parameters || null; - this.url = url; - }, - -/** @id Ajax.Autocompleter.prototype.getUpdatedChoices */ - getUpdatedChoices: function () { - var entry = encodeURIComponent(this.options.paramName) + '=' + - encodeURIComponent(this.getToken()); - - this.options.parameters = this.options.callback ? - this.options.callback(this.element, entry) : entry; - - if (this.options.defaultParams) { - this.options.parameters += '&' + this.options.defaultParams; - } - new Ajax.Request(this.url, this.options); - }, - -/** @id Ajax.Autocompleter.prototype.onComplete */ - onComplete: function (request) { - this.updateChoices(request.responseText); - } -}); - -/*** - -The local array autocompleter. Used when you'd prefer to -inject an array of autocompletion options into the page, rather -than sending out Ajax queries, which can be quite slow sometimes. - -The constructor takes four parameters. The first two are, as usual, -the id of the monitored textbox, and id of the autocompletion menu. -The third is the array you want to autocomplete from, and the fourth -is the options block. - -Extra local autocompletion options: -- choices - How many autocompletion choices to offer - -- partialSearch - If false, the autocompleter will match entered - text only at the beginning of strings in the - autocomplete array. Defaults to true, which will - match text at the beginning of any *word* in the - strings in the autocomplete array. If you want to - search anywhere in the string, additionally set - the option fullSearch to true (default: off). - -- fullSsearch - Search anywhere in autocomplete array strings. - -- partialChars - How many characters to enter before triggering - a partial match (unlike minChars, which defines - how many characters are required to do any match - at all). Defaults to 2. - -- ignoreCase - Whether to ignore case when autocompleting. - Defaults to true. - -It's possible to pass in a custom function as the 'selector' -option, if you prefer to write your own autocompletion logic. -In that case, the other options above will not apply unless -you support them. - -***/ - -/** @id Autocompleter.Local */ -Autocompleter.Local = function (element, update, array, options) { - this.__init__(element, update, array, options); -}; - -MochiKit.Base.update(Autocompleter.Local.prototype, Autocompleter.Base.prototype); - -MochiKit.Base.update(Autocompleter.Local.prototype, { - __init__: function (element, update, array, options) { - this.baseInitialize(element, update, options); - this.options.array = array; - }, - -/** @id Autocompleter.Local.prototype.getUpdatedChoices */ - getUpdatedChoices: function () { - this.updateChoices(this.options.selector(this)); - }, - -/** @id Autocompleter.Local.prototype.setOptions */ - setOptions: function (options) { - this.options = MochiKit.Base.update({ - choices: 10, - partialSearch: true, - partialChars: 2, - ignoreCase: true, - fullSearch: false, - selector: function (instance) { - var ret = []; // Beginning matches - var partial = []; // Inside matches - var entry = instance.getToken(); - var count = 0; - - for (var i = 0; i < instance.options.array.length && - ret.length < instance.options.choices ; i++) { - - var elem = instance.options.array[i]; - var foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase()) : - elem.indexOf(entry); - - while (foundPos != -1) { - if (foundPos === 0 && elem.length != entry.length) { - ret.push('<li><strong>' + elem.substr(0, entry.length) + '</strong>' + - elem.substr(entry.length) + '</li>'); - break; - } else if (entry.length >= instance.options.partialChars && - instance.options.partialSearch && foundPos != -1) { - if (instance.options.fullSearch || /\s/.test(elem.substr(foundPos - 1, 1))) { - partial.push('<li>' + elem.substr(0, foundPos) + '<strong>' + - elem.substr(foundPos, entry.length) + '</strong>' + elem.substr( - foundPos + entry.length) + '</li>'); - break; - } - } - - foundPos = instance.options.ignoreCase ? - elem.toLowerCase().indexOf(entry.toLowerCase(), foundPos + 1) : - elem.indexOf(entry, foundPos + 1); - - } - } - if (partial.length) { - ret = ret.concat(partial.slice(0, instance.options.choices - ret.length)) - } - return '<ul>' + ret.join('') + '</ul>'; - } - }, options || {}); - } -}); - -/*** - -AJAX in-place editor - -see documentation on http://wiki.script.aculo.us/scriptaculous/show/Ajax.InPlaceEditor - -Use this if you notice weird scrolling problems on some browsers, -the DOM might be a bit confused when this gets called so do this -waits 1 ms (with setTimeout) until it does the activation - -***/ - -/** @id Ajax.InPlaceEditor */ -Ajax.InPlaceEditor = function (element, url, options) { - this.__init__(element, url, options); -}; - -/** @id Ajax.InPlaceEditor.defaultHighlightColor */ -Ajax.InPlaceEditor.defaultHighlightColor = '#FFFF99'; - -Ajax.InPlaceEditor.prototype = { - __init__: function (element, url, options) { - this.url = url; - this.element = MochiKit.DOM.getElement(element); - - this.options = MochiKit.Base.update({ - okButton: true, - okText: 'ok', - cancelLink: true, - cancelText: 'cancel', - savingText: 'Saving...', - clickToEditText: 'Click to edit', - okText: 'ok', - rows: 1, - onComplete: function (transport, element) { - new MochiKit.Visual.Highlight(element, {startcolor: this.options.highlightcolor}); - }, - onFailure: function (transport) { - alert('Error communicating with the server: ' + MochiKit.Base.stripTags(transport.responseText)); - }, - callback: function (form) { - return MochiKit.DOM.formContents(form); - }, - handleLineBreaks: true, - loadingText: 'Loading...', - savingClassName: 'inplaceeditor-saving', - loadingClassName: 'inplaceeditor-loading', - formClassName: 'inplaceeditor-form', - highlightcolor: Ajax.InPlaceEditor.defaultHighlightColor, - highlightendcolor: '#FFFFFF', - externalControl: null, - submitOnBlur: false, - ajaxOptions: {} - }, options || {}); - - if (!this.options.formId && this.element.id) { - this.options.formId = this.element.id + '-inplaceeditor'; - if (MochiKit.DOM.getElement(this.options.formId)) { - // there's already a form with that name, don't specify an id - this.options.formId = null; - } - } - - if (this.options.externalControl) { - this.options.externalControl = MochiKit.DOM.getElement(this.options.externalControl); - } - - this.originalBackground = MochiKit.Style.getStyle(this.element, 'background-color'); - if (!this.originalBackground) { - this.originalBackground = 'transparent'; - } - - this.element.title = this.options.clickToEditText; - - this.onclickListener = MochiKit.Signal.connect(this.element, 'onclick', this, this.enterEditMode); - this.mouseoverListener = MochiKit.Signal.connect(this.element, 'onmouseover', this, this.enterHover); - this.mouseoutListener = MochiKit.Signal.connect(this.element, 'onmouseout', this, this.leaveHover); - if (this.options.externalControl) { - this.onclickListenerExternal = MochiKit.Signal.connect(this.options.externalControl, - 'onclick', this, this.enterEditMode); - this.mouseoverListenerExternal = MochiKit.Signal.connect(this.options.externalControl, - 'onmouseover', this, this.enterHover); - this.mouseoutListenerExternal = MochiKit.Signal.connect(this.options.externalControl, - 'onmouseout', this, this.leaveHover); - } - }, - -/** @id Ajax.InPlaceEditor.prototype.enterEditMode */ - enterEditMode: function (evt) { - if (this.saving) { - return; - } - if (this.editing) { - return; - } - this.editing = true; - this.onEnterEditMode(); - if (this.options.externalControl) { - MochiKit.Style.hideElement(this.options.externalControl); - } - MochiKit.Style.hideElement(this.element); - this.createForm(); - this.element.parentNode.insertBefore(this.form, this.element); - Field.scrollFreeActivate(this.editField); - // stop the event to avoid a page refresh in Safari - if (evt) { - evt.stop(); - } - return false; - }, - -/** @id Ajax.InPlaceEditor.prototype.createForm */ - createForm: function () { - this.form = document.createElement('form'); - this.form.id = this.options.formId; - MochiKit.DOM.addElementClass(this.form, this.options.formClassName) - this.form.onsubmit = MochiKit.Base.bind(this.onSubmit, this); - - this.createEditField(); - - if (this.options.textarea) { - var br = document.createElement('br'); - this.form.appendChild(br); - } - - if (this.options.okButton) { - okButton = document.createElement('input'); - okButton.type = 'submit'; - okButton.value = this.options.okText; - this.form.appendChild(okButton); - } - - if (this.options.cancelLink) { - cancelLink = document.createElement('a'); - cancelLink.href = '#'; - cancelLink.appendChild(document.createTextNode(this.options.cancelText)); - cancelLink.onclick = MochiKit.Base.bind(this.onclickCancel, this); - this.form.appendChild(cancelLink); - } - }, - -/** @id Ajax.InPlaceEditor.prototype.hasHTMLLineBreaks */ - hasHTMLLineBreaks: function (string) { - if (!this.options.handleLineBreaks) { - return false; - } - return string.match(/<br/i) || string.match(/<p>/i); - }, - -/** @id Ajax.InPlaceEditor.prototype.convertHTMLLineBreaks */ - convertHTMLLineBreaks: function (string) { - return string.replace(/<br>/gi, '\n').replace(/<br\/>/gi, '\n').replace(/<\/p>/gi, '\n').replace(/<p>/gi, ''); - }, - -/** @id Ajax.InPlaceEditor.prototype.createEditField */ - createEditField: function () { - var text; - if (this.options.loadTextURL) { - text = this.options.loadingText; - } else { - text = this.getText(); - } - - var obj = this; - - if (this.options.rows == 1 && !this.hasHTMLLineBreaks(text)) { - this.options.textarea = false; - var textField = document.createElement('input'); - textField.obj = this; - textField.type = 'text'; - textField.name = 'value'; - textField.value = text; - textField.style.backgroundColor = this.options.highlightcolor; - var size = this.options.size || this.options.cols || 0; - if (size !== 0) { - textField.size = size; - } - if (this.options.submitOnBlur) { - textField.onblur = MochiKit.Base.bind(this.onSubmit, this); - } - this.editField = textField; - } else { - this.options.textarea = true; - var textArea = document.createElement('textarea'); - textArea.obj = this; - textArea.name = 'value'; - textArea.value = this.convertHTMLLineBreaks(text); - textArea.rows = this.options.rows; - textArea.cols = this.options.cols || 40; - if (this.options.submitOnBlur) { - textArea.onblur = MochiKit.Base.bind(this.onSubmit, this); - } - this.editField = textArea; - } - - if (this.options.loadTextURL) { - this.loadExternalText(); - } - this.form.appendChild(this.editField); - }, - -/** @id Ajax.InPlaceEditor.prototype.getText */ - getText: function () { - return this.element.innerHTML; - }, - -/** @id Ajax.InPlaceEditor.prototype.loadExternalText */ - loadExternalText: function () { - MochiKit.DOM.addElementClass(this.form, this.options.loadingClassName); - this.editField.disabled = true; - new Ajax.Request( - this.options.loadTextURL, - MochiKit.Base.update({ - asynchronous: true, - onComplete: MochiKit.Base.bind(this.onLoadedExternalText, this) - }, this.options.ajaxOptions) - ); - }, - -/** @id Ajax.InPlaceEditor.prototype.onLoadedExternalText */ - onLoadedExternalText: function (transport) { - MochiKit.DOM.removeElementClass(this.form, this.options.loadingClassName); - this.editField.disabled = false; - this.editField.value = MochiKit.Base.stripTags(transport); - }, - -/** @id Ajax.InPlaceEditor.prototype.onclickCancel */ - onclickCancel: function () { - this.onComplete(); - this.leaveEditMode(); - return false; - }, - -/** @id Ajax.InPlaceEditor.prototype.onFailure */ - onFailure: function (transport) { - this.options.onFailure(transport); - if (this.oldInnerHTML) { - this.element.innerHTML = this.oldInnerHTML; - this.oldInnerHTML = null; - } - return false; - }, - -/** @id Ajax.InPlaceEditor.prototype.onSubmit */ - onSubmit: function () { - // onLoading resets these so we need to save them away for the Ajax call - var form = this.form; - var value = this.editField.value; - - // do this first, sometimes the ajax call returns before we get a - // chance to switch on Saving which means this will actually switch on - // Saving *after* we have left edit mode causing Saving to be - // displayed indefinitely - this.onLoading(); - - new Ajax.Updater( - { - success: this.element, - // dont update on failure (this could be an option) - failure: null - }, - this.url, - MochiKit.Base.update({ - parameters: this.options.callback(form, value), - onComplete: MochiKit.Base.bind(this.onComplete, this), - onFailure: MochiKit.Base.bind(this.onFailure, this) - }, this.options.ajaxOptions) - ); - // stop the event to avoid a page refresh in Safari - if (arguments.length > 1) { - arguments[0].stop(); - } - return false; - }, - -/** @id Ajax.InPlaceEditor.prototype.onLoading */ - onLoading: function () { - this.saving = true; - this.removeForm(); - this.leaveHover(); - this.showSaving(); - }, - -/** @id Ajax.InPlaceEditor.prototype.onSaving */ - showSaving: function () { - this.oldInnerHTML = this.element.innerHTML; - this.element.innerHTML = this.options.savingText; - MochiKit.DOM.addElementClass(this.element, this.options.savingClassName); - this.element.style.backgroundColor = this.originalBackground; - MochiKit.Style.showElement(this.element); - }, - -/** @id Ajax.InPlaceEditor.prototype.removeForm */ - removeForm: function () { - if (this.form) { - if (this.form.parentNode) { - MochiKit.DOM.removeElement(this.form); - } - this.form = null; - } - }, - -/** @id Ajax.InPlaceEditor.prototype.enterHover */ - enterHover: function () { - if (this.saving) { - return; - } - this.element.style.backgroundColor = this.options.highlightcolor; - if (this.effect) { - this.effect.cancel(); - } - MochiKit.DOM.addElementClass(this.element, this.options.hoverClassName) - }, - -/** @id Ajax.InPlaceEditor.prototype.leaveHover */ - leaveHover: function () { - if (this.options.backgroundColor) { - this.element.style.backgroundColor = this.oldBackground; - } - MochiKit.DOM.removeElementClass(this.element, this.options.hoverClassName) - if (this.saving) { - return; - } - this.effect = new MochiKit.Visual.Highlight(this.element, { - startcolor: this.options.highlightcolor, - endcolor: this.options.highlightendcolor, - restorecolor: this.originalBackground - }); - }, - -/** @id Ajax.InPlaceEditor.prototype.leaveEditMode */ - leaveEditMode: function () { - MochiKit.DOM.removeElementClass(this.element, this.options.savingClassName); - this.removeForm(); - this.leaveHover(); - this.element.style.backgroundColor = this.originalBackground; - MochiKit.Style.showElement(this.element); - if (this.options.externalControl) { - MochiKit.Style.showElement(this.options.externalControl); - } - this.editing = false; - this.saving = false; - this.oldInnerHTML = null; - this.onLeaveEditMode(); - }, - -/** @id Ajax.InPlaceEditor.prototype.onComplete */ - onComplete: function (transport) { - this.leaveEditMode(); - MochiKit.Base.bind(this.options.onComplete, this)(transport, this.element); - }, - -/** @id Ajax.InPlaceEditor.prototype.onEnterEditMode */ - onEnterEditMode: function () {}, - -/** @id Ajax.InPlaceEditor.prototype.onLeaveEditMode */ - onLeaveEditMode: function () {}, - - /** @id Ajax.InPlaceEditor.prototype.dispose */ - dispose: function () { - if (this.oldInnerHTML) { - this.element.innerHTML = this.oldInnerHTML; - } - this.leaveEditMode(); - MochiKit.Signal.disconnect(this.onclickListener); - MochiKit.Signal.disconnect(this.mouseoverListener); - MochiKit.Signal.disconnect(this.mouseoutListener); - if (this.options.externalControl) { - MochiKit.Signal.disconnect(this.onclickListenerExternal); - MochiKit.Signal.disconnect(this.mouseoverListenerExternal); - MochiKit.Signal.disconnect(this.mouseoutListenerExternal); - } - } -}; - |
