diff --git a/addons/web/static/lib/jquery.textext/jquery.textext.css b/addons/web/static/lib/jquery.textext/jquery.textext.css deleted file mode 100644 index f180ee66184..00000000000 --- a/addons/web/static/lib/jquery.textext/jquery.textext.css +++ /dev/null @@ -1,148 +0,0 @@ - -.text-core { - position: relative; -} -.text-core .text-wrap { - background: #fff; - position: absolute; -} -.text-core .text-wrap textarea, .text-core .text-wrap input { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - border-radius: 3px; - outline: none; - resize: none; - position: absolute; - background: none; - overflow: hidden; - margin: 0; - padding: 3px 5px 4px 5px; - white-space: nowrap; - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif; - line-height: 13px; - height: auto; -} -.text-core .text-wrap .text-arrow { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - position: absolute; - top: 0; - right: 0; - width: 22px; - height: 22px; - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAOAQMAAADHWqTrAAAAA3NCSVQICAjb4U/gAAAABlBMVEX///8yXJnt8Ns4AAAACXBIWXMAAAsSAAALEgHS3X78AAAAHHRFWHRTb2Z0d2FyZQBBZG9iZSBGaXJld29ya3MgQ1MzmNZGAwAAABpJREFUCJljYEAF/xsY6hkY7BgYZBgYOFBkADkdAmFDagYFAAAAAElFTkSuQmCC") 50% 50% no-repeat; - cursor: pointer; - z-index: 2; -} -.text-core .text-wrap .text-dropdown { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - padding: 0; - position: absolute; - z-index: 3; - background: #fff; - border: 1px solid #9daccc; - width: 100%; - max-height: 100px; - padding: 1px; - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif; - display: none; - overflow-x: hidden; - overflow-y: auto; -} -.text-core .text-wrap .text-dropdown.text-position-below { - margin-top: 1px; -} -.text-core .text-wrap .text-dropdown.text-position-above { - margin-bottom: 1px; -} -.text-core .text-wrap .text-dropdown .text-list .text-suggestion { - padding: 3px 5px; - cursor: pointer; -} -.text-core .text-wrap .text-dropdown .text-list .text-suggestion.text-selected { - color: #fff; - background: #6d84b4; -} -.text-core .text-wrap .text-focus { - -webkit-box-shadow: 0px 0px 6px #6d84b4; - -moz-box-shadow: 0px 0px 6px #6d84b4; - box-shadow: 0px 0px 6px #6d84b4; - position: absolute; - width: 100%; - height: 100%; - display: none; -} -.text-core .text-wrap .text-focus.text-show-focus { - display: block; -} -.text-core .text-wrap .text-prompt { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - position: absolute; - width: 100%; - height: 100%; - margin: 1px 0 0 2px; - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif; - color: #c0c0c0; - overflow: hidden; - white-space: pre; -} -.text-core .text-wrap .text-prompt.text-hide-prompt { - display: none; -} -.text-core .text-wrap .text-tags { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - position: absolute; - width: 100%; - height: 100%; - padding: 3px 35px 3px 3px; - cursor: text; -} -.text-core .text-wrap .text-tags.text-tags-on-top { - z-index: 2; -} -.text-core .text-wrap .text-tags .text-tag { - float: left; -} -.text-core .text-wrap .text-tags .text-tag .text-button { - -webkit-border-radius: 2px; - -moz-border-radius: 2px; - border-radius: 2px; - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; - position: relative; - float: left; - border: 1px solid #9daccc; - background: #e2e6f0; - color: #000; - padding: 0px 17px 0px 3px; - margin: 0 2px 2px 0; - cursor: pointer; - height: 16px; - font: 11px "lucida grande", tahoma, verdana, arial, sans-serif; -} -.text-core .text-wrap .text-tags .text-tag .text-button a.text-remove { - position: absolute; - right: 3px; - top: 2px; - display: block; - width: 11px; - height: 11px; - background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAsAAAAhCAYAAAAPm1F2AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAAB50RVh0U29mdHdhcmUAQWRvYmUgRmlyZXdvcmtzIENTNS4xqx9I6wAAAQ5JREFUOI2dlD0WwiAQhCc8L6HHgAPoASwtSYvX8BrQxtIyveYA8RppLO1jE+LwE8lzms2yH8MCj1QoaBzH+VuUYNYMS213UlvDRamtUbXb5ZyPHuDoxwGgip3ipfvGuGzPz+vZ/coDONdzFuYCO6ramQQG0DJIE1oPBBvM6e9LqaS2FwD7FWwnVoIAsOc2Xn1jDlyd8pfPBRVOBHA8cc/3yCmQqt0jcY4LuTyAF3pOYS6wI48LAm4MUrx5JthgSQJAt5LtNgAUgEMBBIC3AL2xgo58dEPfhE9wygef89FtCeC49UwltR1pQrK2qr9vNr7uRTCBF3pOYS6wI4/zdQ8MUpxPI9hgSQL0Xyio/QBt54DzsHQx6gAAAABJRU5ErkJggg==") 0 0 no-repeat; -} -.text-core .text-wrap .text-tags .text-tag .text-button a.text-remove:hover { - background-position: 0 -11px; -} -.text-core .text-wrap .text-tags .text-tag .text-button a.text-remove:active { - background-position: 0 -22px; -} diff --git a/addons/web/static/lib/jquery.textext/jquery.textext.js b/addons/web/static/lib/jquery.textext/jquery.textext.js deleted file mode 100644 index 94a78b6bb7a..00000000000 --- a/addons/web/static/lib/jquery.textext/jquery.textext.js +++ /dev/null @@ -1,4776 +0,0 @@ -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($, undefined) -{ - /** - * TextExt is the main core class which by itself doesn't provide any functionality - * that is user facing, however it has the underlying mechanics to bring all the - * plugins together under one roof and make them work with each other or on their - * own. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt - */ - function TextExt() {}; - - /** - * ItemManager is used to seamlessly convert between string that come from the user input to whatever - * the format the item data is being passed around in. It's used by all plugins that in one way or - * another operate with items, such as Tags, Filter, Autocomplete and Suggestions. Default implementation - * works with `String` type. - * - * Each instance of `TextExt` creates a new instance of default implementation of `ItemManager` - * unless `itemManager` option was set to another implementation. - * - * To satisfy requirements of managing items of type other than a `String`, different implementation - * if `ItemManager` should be supplied. - * - * If you wish to bring your own implementation, you need to create a new class and implement all the - * methods that `ItemManager` has. After, you need to supply your pass via the `itemManager` option during - * initialization like so: - * - * $('#input').textext({ - * itemManager : CustomItemManager - * }) - * - * @author agorbatchev - * @date 2011/08/19 - * @id ItemManager - */ - function ItemManager() {}; - - /** - * TextExtPlugin is a base class for all plugins. It provides common methods which are reused - * by majority of plugins. - * - * All plugins must register themselves by calling the `$.fn.textext.addPlugin(name, constructor)` - * function while providing plugin name and constructor. The plugin name is the same name that user - * will identify the plugin in the `plugins` option when initializing TextExt component and constructor - * function will create a new instance of the plugin. *Without registering, the core won't - * be able to see the plugin.* - * - * new in 1.2.0 You can get instance of each plugin from the core - * via associated function with the same name as the plugin. For example: - * - * $('#input').textext()[0].tags() - * $('#input').textext()[0].autocomplete() - * ... - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin - */ - function TextExtPlugin() {}; - - var stringify = (JSON || {}).stringify, - slice = Array.prototype.slice, - - UNDEFINED = 'undefined', - - /** - * TextExt provides a way to pass in the options to configure the core as well as - * each plugin that is being currently used. The jQuery exposed plugin `$().textext()` - * function takes a hash object with key/value set of options. For example: - * - * $('textarea').textext({ - * enabled: true - * }) - * - * There are multiple ways of passing in the options: - * - * 1. Options could be nested multiple levels deep and accessed using all lowercased, dot - * separated style, eg `foo.bar.world`. The manual is using this style for clarity and - * consistency. For example: - * - * { - * item: { - * manager: ... - * }, - * - * html: { - * wrap: ... - * }, - * - * autocomplete: { - * enabled: ..., - * dropdown: { - * position: ... - * } - * } - * } - * - * 2. Options could be specified using camel cased names in a flat key/value fashion like so: - * - * { - * itemManager: ..., - * htmlWrap: ..., - * autocompleteEnabled: ..., - * autocompleteDropdownPosition: ... - * } - * - * 3. Finally, options could be specified in mixed style. It's important to understand that - * for each dot separated name, its alternative in camel case is also checked for, eg for - * `foo.bar.world` it's alternatives could be `fooBarWorld`, `foo.barWorld` or `fooBar.world`, - * which translates to `{ foo: { bar: { world: ... } } }`, `{ fooBarWorld: ... }`, - * `{ foo : { barWorld : ... } }` or `{ fooBar: { world: ... } }` respectively. For example: - * - * { - * itemManager : ..., - * htmlWrap: ..., - * autocomplete: { - * enabled: ..., - * dropdownPosition: ... - * } - * } - * - * Mixed case is used through out the code, wherever it seems appropriate. However in the code, all option - * names are specified in the dot notation because it works both ways where as camel case is not - * being converted to its alternative dot notation. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExt.options - */ - - /** - * Default instance of `ItemManager` which takes `String` type as default for tags. - * - * @name item.manager - * @default ItemManager - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.options.item.manager - */ - OPT_ITEM_MANAGER = 'item.manager', - - /** - * List of plugins that should be used with the current instance of TextExt. The list could be - * specified as array of strings or as comma or space separated string. - * - * @name plugins - * @default [] - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.options.plugins - */ - OPT_PLUGINS = 'plugins', - - /** - * TextExt allows for overriding of virtually any method that the core or any of its plugins - * use. This could be accomplished through the use of the `ext` option. - * - * It's possible to specifically target the core or any plugin, as well as overwrite all the - * desired methods everywhere. - * - * 1. Targeting the core: - * - * ext: { - * core: { - * trigger: function() - * { - * console.log('TextExt.trigger', arguments); - * $.fn.textext.TextExt.prototype.trigger.apply(this, arguments); - * } - * } - * } - * - * 2. Targeting individual plugins: - * - * ext: { - * tags: { - * addTags: function(tags) - * { - * console.log('TextExtTags.addTags', tags); - * $.fn.textext.TextExtTags.prototype.addTags.apply(this, arguments); - * } - * } - * } - * - * 3. Targeting `ItemManager` instance: - * - * ext: { - * itemManager: { - * stringToItem: function(str) - * { - * console.log('ItemManager.stringToItem', str); - * return $.fn.textext.ItemManager.prototype.stringToItem.apply(this, arguments); - * } - * } - * } - * - * 4. And finally, in edge cases you can extend everything at once: - * - * ext: { - * '*': { - * fooBar: function() {} - * } - * } - * - * @name ext - * @default {} - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.options.ext - */ - OPT_EXT = 'ext', - - /** - * HTML source that is used to generate elements necessary for the core and all other - * plugins to function. - * - * @name html.wrap - * @default '
' - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.options.html.wrap - */ - OPT_HTML_WRAP = 'html.wrap', - - /** - * HTML source that is used to generate hidden input value of which will be submitted - * with the HTML form. - * - * @name html.hidden - * @default '' - * @author agorbatchev - * @date 2011/08/20 - * @id TextExt.options.html.hidden - */ - OPT_HTML_HIDDEN = 'html.hidden', - - /** - * Hash table of key codes and key names for which special events will be created - * by the core. For each entry a `[name]KeyDown`, `[name]KeyUp` and `[name]KeyPress` events - * will be triggered along side with `anyKeyUp` and `anyKeyDown` events for every - * key stroke. - * - * Here's a list of default keys: - * - * { - * 8 : 'backspace', - * 9 : 'tab', - * 13 : 'enter!', - * 27 : 'escape!', - * 37 : 'left', - * 38 : 'up!', - * 39 : 'right', - * 40 : 'down!', - * 46 : 'delete', - * 108 : 'numpadEnter' - * } - * - * Please note the `!` at the end of some keys. This tells the core that by default - * this keypress will be trapped and not passed on to the text input. - * - * @name keys - * @default { ... } - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.options.keys - */ - OPT_KEYS = 'keys', - - /** - * The core triggers or reacts to the following events. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExt.events - */ - - /** - * Core triggers `preInvalidate` event before the dimensions of padding on the text input - * are set. - * - * @name preInvalidate - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.preInvalidate - */ - EVENT_PRE_INVALIDATE = 'preInvalidate', - - /** - * Core triggers `postInvalidate` event after the dimensions of padding on the text input - * are set. - * - * @name postInvalidate - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.postInvalidate - */ - EVENT_POST_INVALIDATE = 'postInvalidate', - - /** - * Core triggers `getFormData` on every key press to collect data that will be populated - * into the hidden input that will be submitted with the HTML form and data that will - * be displayed in the input field that user is currently interacting with. - * - * All plugins that wish to affect how the data is presented or sent must react to - * `getFormData` and populate the data in the following format: - * - * { - * input : {String}, - * form : {Object} - * } - * - * The data key must be a numeric weight which will be used to determine which data - * ends up being used. Data with the highest numerical weight gets the priority. This - * allows plugins to set the final data regardless of their initialization order, which - * otherwise would be impossible. - * - * For example, the Tags and Autocomplete plugins have to work side by side and Tags - * plugin must get priority on setting the data. Therefore the Tags plugin sets data - * with the weight 200 where as the Autocomplete plugin sets data with the weight 100. - * - * Here's an example of a typical `getFormData` handler: - * - * TextExtPlugin.prototype.onGetFormData = function(e, data, keyCode) - * { - * data[100] = self.formDataObject('input value', 'form value'); - * }; - * - * Core also reacts to the `getFormData` and updates hidden input with data which will be - * submitted with the HTML form. - * - * @name getFormData - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.getFormData - */ - EVENT_GET_FORM_DATA = 'getFormData', - - /** - * Core triggers and reacts to the `setFormData` event to update the actual value in the - * hidden input that will be submitted with the HTML form. Second argument can be value - * of any type and by default it will be JSON serialized with `TextExt.serializeData()` - * function. - * - * @name setFormData - * @author agorbatchev - * @date 2011/08/22 - * @id TextExt.events.setFormData - */ - EVENT_SET_FORM_DATA = 'setFormData', - - /** - * Core triggers and reacts to the `setInputData` event to update the actual value in the - * text input that user is interacting with. Second argument must be of a `String` type - * the value of which will be set into the text input. - * - * @name setInputData - * @author agorbatchev - * @date 2011/08/22 - * @id TextExt.events.setInputData - */ - EVENT_SET_INPUT_DATA = 'setInputData', - - /** - * Core triggers `postInit` event to let plugins run code after all plugins have been - * created and initialized. This is a good place to set some kind of global values before - * somebody gets to use them. This is not the right place to expect all plugins to finish - * their initialization. - * - * @name postInit - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.postInit - */ - EVENT_POST_INIT = 'postInit', - - /** - * Core triggers `ready` event after all global configuration and prepearation has been - * done and the TextExt component is ready for use. Event handlers should expect all - * values to be set and the plugins to be in the final state. - * - * @name ready - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.ready - */ - EVENT_READY = 'ready', - - /** - * Core triggers `anyKeyUp` event for every key up event triggered within the component. - * - * @name anyKeyUp - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.anyKeyUp - */ - - /** - * Core triggers `anyKeyDown` event for every key down event triggered within the component. - * - * @name anyKeyDown - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.anyKeyDown - */ - - /** - * Core triggers `[name]KeyUp` event for every key specifid in the `keys` option that is - * triggered within the component. - * - * @name [name]KeyUp - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.[name]KeyUp - */ - - /** - * Core triggers `[name]KeyDown` event for every key specified in the `keys` option that is - * triggered within the component. - * - * @name [name]KeyDown - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.[name]KeyDown - */ - - /** - * Core triggers `[name]KeyPress` event for every key specified in the `keys` option that is - * triggered within the component. - * - * @name [name]KeyPress - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.events.[name]KeyPress - */ - - DEFAULT_OPTS = { - itemManager : ItemManager, - - plugins : [], - ext : {}, - - html : { - wrap : '
', - hidden : '' - }, - - keys : { - 8 : 'backspace', - 9 : 'tab', - 13 : 'enter!', - 27 : 'escape!', - 37 : 'left', - 38 : 'up!', - 39 : 'right', - 40 : 'down!', - 46 : 'delete', - 108 : 'numpadEnter' - } - } - ; - - // Freak out if there's no JSON.stringify function found - if(!stringify) - throw new Error('JSON.stringify() not found'); - - /** - * Returns object property by name where name is dot-separated and object is multiple levels deep. - * @param target Object Source object. - * @param name String Dot separated property name, ie `foo.bar.world` - * @id core.getProperty - */ - function getProperty(source, name) - { - if(typeof(name) === 'string') - name = name.split('.'); - - var fullCamelCaseName = name.join('.').replace(/\.(\w)/g, function(match, letter) { return letter.toUpperCase() }), - nestedName = name.shift(), - result - ; - - if(typeof(result = source[fullCamelCaseName]) != UNDEFINED) - result = result; - - else if(typeof(result = source[nestedName]) != UNDEFINED && name.length > 0) - result = getProperty(result, name); - - // name.length here should be zero - return result; - }; - - /** - * Hooks up specified events in the scope of the current object. - * @author agorbatchev - * @date 2011/08/09 - */ - function hookupEvents() - { - var args = slice.apply(arguments), - self = this, - target = args.length === 1 ? self : args.shift(), - event - ; - - args = args[0] || {}; - - function bind(event, handler) - { - target.bind(event, function() - { - // apply handler to our PLUGIN object, not the target - return handler.apply(self, arguments); - }); - } - - for(event in args) - bind(event, args[event]); - }; - - function formDataObject(input, form) - { - return { 'input' : input, 'form' : form }; - }; - - //-------------------------------------------------------------------------------- - // ItemManager core component - - p = ItemManager.prototype; - - /** - * Initialization method called by the core during instantiation. - * - * @signature ItemManager.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/19 - * @id ItemManager.init - */ - p.init = function(core) - { - }; - - /** - * Filters out items from the list that don't match the query and returns remaining items. Default - * implementation checks if the item starts with the query. - * - * @signature ItemManager.filter(list, query) - * - * @param list {Array} List of items. Default implementation works with strings. - * @param query {String} Query string. - * - * @author agorbatchev - * @date 2011/08/19 - * @id ItemManager.filter - */ - p.filter = function(list, query) - { - var result = [], - i, item - ; - - for(i = 0; i < list.length; i++) - { - item = list[i]; - if(this.itemContains(item, query)) - result.push(item); - } - - return result; - }; - - /** - * Returns `true` if specified item contains another string, `false` otherwise. In the default implementation - * `String.indexOf()` is used to check if item string begins with the needle string. - * - * @signature ItemManager.itemContains(item, needle) - * - * @param item {Object} Item to check. Default implementation works with strings. - * @param needle {String} Search string to be found within the item. - * - * @author agorbatchev - * @date 2011/08/19 - * @id ItemManager.itemContains - */ - p.itemContains = function(item, needle) - { - return this.itemToString(item).toLowerCase().indexOf(needle.toLowerCase()) == 0; - }; - - /** - * Converts specified string to item. Because default implemenation works with string, input string - * is simply returned back. To use custom objects, different implementation of this method could - * return something like `{ name : {String} }`. - * - * @signature ItemManager.stringToItem(str) - * - * @param str {String} Input string. - * - * @author agorbatchev - * @date 2011/08/19 - * @id ItemManager.stringToItem - */ - p.stringToItem = function(str) - { - return str; - }; - - /** - * Converts specified item to string. Because default implemenation works with string, input string - * is simply returned back. To use custom objects, different implementation of this method could - * for example return `name` field of `{ name : {String} }`. - * - * @signature ItemManager.itemToString(item) - * - * @param item {Object} Input item to be converted to string. - * - * @author agorbatchev - * @date 2011/08/19 - * @id ItemManager.itemToString - */ - p.itemToString = function(item) - { - return item; - }; - - /** - * Returns `true` if both items are equal, `false` otherwise. Because default implemenation works with - * string, input items are compared as strings. To use custom objects, different implementation of this - * method could for example compare `name` fields of `{ name : {String} }` type object. - * - * @signature ItemManager.compareItems(item1, item2) - * - * @param item1 {Object} First item. - * @param item2 {Object} Second item. - * - * @author agorbatchev - * @date 2011/08/19 - * @id ItemManager.compareItems - */ - p.compareItems = function(item1, item2) - { - return item1 == item2; - }; - - //-------------------------------------------------------------------------------- - // TextExt core component - - p = TextExt.prototype; - - /** - * Initializes current component instance with work with the supplied text input and options. - * - * @signature TextExt.init(input, opts) - * - * @param input {HTMLElement} Text input. - * @param opts {Object} Options. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.init - */ - p.init = function(input, opts) - { - var self = this, - hiddenInput, - itemManager, - container - ; - - self._defaults = $.extend({}, DEFAULT_OPTS); - self._opts = opts || {}; - self._plugins = {}; - self._itemManager = itemManager = new (self.opts(OPT_ITEM_MANAGER))(); - input = $(input); - container = $(self.opts(OPT_HTML_WRAP)); - hiddenInput = $(self.opts(OPT_HTML_HIDDEN)); - - input - .wrap(container) - .keydown(function(e) { return self.onKeyDown(e) }) - .keyup(function(e) { return self.onKeyUp(e) }) - .data('textext', self) - ; - - // keep references to html elements using jQuery.data() to avoid circular references - $(self).data({ - 'hiddenInput' : hiddenInput, - 'wrapElement' : input.parents('.text-wrap').first(), - 'input' : input - }); - - // set the name of the hidden input to the text input's name - hiddenInput.attr('name', input.attr('name')); - // remove name attribute from the text input - input.attr('name', null); - // add hidden input to the DOM - hiddenInput.insertAfter(input); - - $.extend(true, itemManager, self.opts(OPT_EXT + '.item.manager')); - $.extend(true, self, self.opts(OPT_EXT + '.*'), self.opts(OPT_EXT + '.core')); - - self.originalWidth = input.outerWidth(); - - self.invalidateBounds(); - - itemManager.init(self); - - self.initPatches(); - self.initPlugins(self.opts(OPT_PLUGINS), $.fn.textext.plugins); - - self.on({ - setFormData : self.onSetFormData, - getFormData : self.onGetFormData, - setInputData : self.onSetInputData, - anyKeyUp : self.onAnyKeyUp - }); - - self.trigger(EVENT_POST_INIT); - self.trigger(EVENT_READY); - - self.getFormData(0); - }; - - /** - * Initialized all installed patches against current instance. The patches are initialized based on their - * initialization priority which is returned by each patch's `initPriority()` method. Priority - * is a `Number` where patches with higher value gets their `init()` method called before patches - * with lower priority value. - * - * This facilitates initializing of patches in certain order to insure proper dependencies - * regardless of which order they are loaded. - * - * By default all patches have the same priority - zero, which means they will be initialized - * in rorder they are loaded, that is unless `initPriority()` is overriden. - * - * @signature TextExt.initPatches() - * - * @author agorbatchev - * @date 2011/10/11 - * @id TextExt.initPatches - */ - p.initPatches = function() - { - var list = [], - source = $.fn.textext.patches, - name - ; - - for(name in source) - list.push(name); - - this.initPlugins(list, source); - }; - - /** - * Creates and initializes all specified plugins. The plugins are initialized based on their - * initialization priority which is returned by each plugin's `initPriority()` method. Priority - * is a `Number` where plugins with higher value gets their `init()` method called before plugins - * with lower priority value. - * - * This facilitates initializing of plugins in certain order to insure proper dependencies - * regardless of which order user enters them in the `plugins` option field. - * - * By default all plugins have the same priority - zero, which means they will be initialized - * in the same order as entered by the user. - * - * @signature TextExt.initPlugins(plugins) - * - * @param plugins {Array} List of plugin names to initialize. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.initPlugins - */ - p.initPlugins = function(plugins, source) - { - var self = this, - ext, name, plugin, initList = [], i - ; - - if(typeof(plugins) == 'string') - plugins = plugins.split(/\s*,\s*|\s+/g); - - for(i = 0; i < plugins.length; i++) - { - name = plugins[i]; - plugin = source[name]; - - if(plugin) - { - self._plugins[name] = plugin = new plugin(); - self[name] = (function(plugin) { - return function(){ return plugin; } - })(plugin); - initList.push(plugin); - $.extend(true, plugin, self.opts(OPT_EXT + '.*'), self.opts(OPT_EXT + '.' + name)); - } - } - - // sort plugins based on their priority values - initList.sort(function(p1, p2) - { - p1 = p1.initPriority(); - p2 = p2.initPriority(); - - return p1 === p2 - ? 0 - : p1 < p2 ? 1 : -1 - ; - }); - - for(i = 0; i < initList.length; i++) - initList[i].init(self); - }; - - /** - * Returns true if specified plugin is was instantiated for the current instance of core. - * - * @signature TextExt.hasPlugin(name) - * - * @param name {String} Name of the plugin to check. - * - * @author agorbatchev - * @date 2011/12/28 - * @id TextExt.hasPlugin - * @version 1.1 - */ - p.hasPlugin = function(name) - { - return !!this._plugins[name]; - }; - - /** - * Allows to add multiple event handlers which will be execued in the scope of the current object. - * - * @signature TextExt.on([target], handlers) - * - * @param target {Object} **Optional**. Target object which has traditional `bind(event, handler)` method. - * Handler function will still be executed in the current object's scope. - * @param handlers {Object} Key/value pairs of event names and handlers, eg `{ event: handler }`. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.on - */ - p.on = hookupEvents; - - /** - * Binds an event handler to the input box that user interacts with. - * - * @signature TextExt.bind(event, handler) - * - * @param event {String} Event name. - * @param handler {Function} Event handler. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.bind - */ - p.bind = function(event, handler) - { - this.input().bind(event, handler); - }; - - /** - * Triggers an event on the input box that user interacts with. All core events are originated here. - * - * @signature TextExt.trigger(event, ...args) - * - * @param event {String} Name of the event to trigger. - * @param ...args All remaining arguments will be passed to the event handler. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.trigger - */ - p.trigger = function() - { - var args = arguments; - this.input().trigger(args[0], slice.call(args, 1)); - }; - - /** - * Returns instance of `itemManager` that is used by the component. - * - * @signature TextExt.itemManager() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.itemManager - */ - p.itemManager = function() - { - return this._itemManager; - }; - - /** - * Returns jQuery input element with which user is interacting with. - * - * @signature TextExt.input() - * - * @author agorbatchev - * @date 2011/08/10 - * @id TextExt.input - */ - p.input = function() - { - return $(this).data('input'); - }; - - /** - * Returns option value for the specified option by name. If the value isn't found in the user - * provided options, it will try looking for default value. - * - * @signature TextExt.opts(name) - * - * @param name {String} Option name as described in the options. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.opts - */ - p.opts = function(name) - { - var result = getProperty(this._opts, name); - return typeof(result) == 'undefined' ? getProperty(this._defaults, name) : result; - }; - - /** - * Returns HTML element that was created from the `html.wrap` option. This is the top level HTML - * container for the text input with which user is interacting with. - * - * @signature TextExt.wrapElement() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.wrapElement - */ - p.wrapElement = function() - { - return $(this).data('wrapElement'); - }; - - /** - * Updates container to match dimensions of the text input. Triggers `preInvalidate` and `postInvalidate` - * events. - * - * @signature TextExt.invalidateBounds() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.invalidateBounds - */ - p.invalidateBounds = function() - { - var self = this, - input = self.input(), - wrap = self.wrapElement(), - container = wrap.parent(), - width = self.originalWidth, - height - ; - - self.trigger(EVENT_PRE_INVALIDATE); - - height = input.outerHeight(); - - input.width(width); - wrap.width(width).height(height); - container.height(height); - - self.trigger(EVENT_POST_INVALIDATE); - }; - - /** - * Focuses user input on the text box. - * - * @signature TextExt.focusInput() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.focusInput - */ - p.focusInput = function() - { - this.input()[0].focus(); - }; - - /** - * Serializes data for to be set into the hidden input field and which will be submitted - * with the HTML form. - * - * By default simple JSON serialization is used. It's expected that `JSON.stringify` - * method would be available either through built in class in most modern browsers - * or through JSON2 library. - * - * @signature TextExt.serializeData(data) - * - * @param data {Object} Data to serialize. - * - * @author agorbatchev - * @date 2011/08/09 - * @id TextExt.serializeData - */ - p.serializeData = stringify; - - /** - * Returns the hidden input HTML element which will be submitted with the HTML form. - * - * @signature TextExt.hiddenInput() - * - * @author agorbatchev - * @date 2011/08/09 - * @id TextExt.hiddenInput - */ - p.hiddenInput = function(value) - { - return $(this).data('hiddenInput'); - }; - - /** - * Abstracted functionality to trigger an event and get the data with maximum weight set by all - * the event handlers. This functionality is used for the `getFormData` event. - * - * @signature TextExt.getWeightedEventResponse(event, args) - * - * @param event {String} Event name. - * @param args {Object} Argument to be passed with the event. - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExt.getWeightedEventResponse - */ - p.getWeightedEventResponse = function(event, args) - { - var self = this, - data = {}, - maxWeight = 0 - ; - - self.trigger(event, data, args); - - for(var weight in data) - maxWeight = Math.max(maxWeight, weight); - - return data[maxWeight]; - }; - - /** - * Triggers the `getFormData` event to get all the plugins to return their data. - * - * After the data is returned, triggers `setFormData` and `setInputData` to update appopriate values. - * - * @signature TextExt.getFormData(keyCode) - * - * @param keyCode {Number} Key code number which has triggered this update. It's impotant to pass - * this value to the plugins because they might return different values based on the key that was - * pressed. For example, the Tags plugin returns an empty string for the `input` value if the enter - * key was pressed, otherwise it returns whatever is currently in the text input. - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExt.getFormData - */ - p.getFormData = function(keyCode) - { - var self = this, - data = self.getWeightedEventResponse(EVENT_GET_FORM_DATA, keyCode || 0) - ; - - self.trigger(EVENT_SET_FORM_DATA , data['form']); - self.trigger(EVENT_SET_INPUT_DATA , data['input']); - }; - - //-------------------------------------------------------------------------------- - // Event handlers - - /** - * Reacts to the `anyKeyUp` event and triggers the `getFormData` to change data that will be submitted - * with the form. Default behaviour is that everything that is typed in will be JSON serialized, so - * the end result will be a JSON string. - * - * @signature TextExt.onAnyKeyUp(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.onAnyKeyUp - */ - p.onAnyKeyUp = function(e, keyCode) - { - this.getFormData(keyCode); - }; - - /** - * Reacts to the `setInputData` event and populates the input text field that user is currently - * interacting with. - * - * @signature TextExt.onSetInputData(e, data) - * - * @param e {Event} jQuery event. - * @param data {String} Value to be set. - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExt.onSetInputData - */ - p.onSetInputData = function(e, data) - { - this.input().val(data); - }; - - /** - * Reacts to the `setFormData` event and populates the hidden input with will be submitted with - * the HTML form. The value will be serialized with `serializeData()` method. - * - * @signature TextExt.onSetFormData(e, data) - * - * @param e {Event} jQuery event. - * @param data {Object} Data that will be set. - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExt.onSetFormData - */ - p.onSetFormData = function(e, data) - { - var self = this; - self.hiddenInput().val(self.serializeData(data)); - }; - - /** - * Reacts to `getFormData` event triggered by the core. At the bare minimum the core will tell - * itself to use the current value in the text input as the data to be submitted with the HTML - * form. - * - * @signature TextExt.onGetFormData(e, data) - * - * @param e {Event} jQuery event. - * - * @author agorbatchev - * @date 2011/08/09 - * @id TextExt.onGetFormData - */ - p.onGetFormData = function(e, data) - { - var val = this.input().val(); - data[0] = formDataObject(val, val); - }; - - //-------------------------------------------------------------------------------- - // User mouse/keyboard input - - /** - * Triggers `[name]KeyUp` and `[name]KeyPress` for every keystroke as described in the events. - * - * @signature TextExt.onKeyUp(e) - * - * @param e {Object} jQuery event. - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.onKeyUp - */ - - /** - * Triggers `[name]KeyDown` for every keystroke as described in the events. - * - * @signature TextExt.onKeyDown(e) - * - * @param e {Object} jQuery event. - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.onKeyDown - */ - - $(['Down', 'Up']).each(function() - { - var type = this.toString(); - - p['onKey' + type] = function(e) - { - var self = this, - keyName = self.opts(OPT_KEYS)[e.keyCode], - defaultResult = true - ; - - if(keyName) - { - defaultResult = keyName.substr(-1) != '!'; - keyName = keyName.replace('!', ''); - - self.trigger(keyName + 'Key' + type); - - // manual *KeyPress event fimplementation for the function keys like Enter, Backspace, etc. - if(type == 'Up' && self._lastKeyDown == e.keyCode) - { - self._lastKeyDown = null; - self.trigger(keyName + 'KeyPress'); - } - - if(type == 'Down') - self._lastKeyDown = e.keyCode; - } - - self.trigger('anyKey' + type, e.keyCode); - - return defaultResult; - }; - }); - - //-------------------------------------------------------------------------------- - // Plugin Base - - p = TextExtPlugin.prototype; - - /** - * Allows to add multiple event handlers which will be execued in the scope of the current object. - * - * @signature TextExt.on([target], handlers) - * - * @param target {Object} **Optional**. Target object which has traditional `bind(event, handler)` method. - * Handler function will still be executed in the current object's scope. - * @param handlers {Object} Key/value pairs of event names and handlers, eg `{ event: handler }`. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.on - */ - p.on = hookupEvents; - - /** - * Returns the hash object that `getFormData` triggered by the core expects. - * - * @signature TextExtPlugin.formDataObject(input, form) - * - * @param input {String} Value that will go into the text input that user is interacting with. - * @param form {Object} Value that will be serialized and put into the hidden that will be submitted - * with the HTML form. - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtPlugin.formDataObject - */ - p.formDataObject = formDataObject; - - /** - * Initialization method called by the core during plugin instantiation. This method must be implemented - * by each plugin individually. - * - * @signature TextExtPlugin.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.init - */ - p.init = function(core) { throw new Error('Not implemented') }; - - /** - * Initialization method wich should be called by the plugin during the `init()` call. - * - * @signature TextExtPlugin.baseInit(core, defaults) - * - * @param core {TextExt} Instance of the TextExt core class. - * @param defaults {Object} Default plugin options. These will be checked if desired value wasn't - * found in the options supplied by the user. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.baseInit - */ - p.baseInit = function(core, defaults) - { - var self = this; - - core._defaults = $.extend(true, core._defaults, defaults); - self._core = core; - self._timers = {}; - }; - - /** - * Allows starting of multiple timeout calls. Each time this method is called with the same - * timer name, the timer is reset. This functionality is useful in cases where an action needs - * to occur only after a certain period of inactivity. For example, making an AJAX call after - * user stoped typing for 1 second. - * - * @signature TextExtPlugin.startTimer(name, delay, callback) - * - * @param name {String} Timer name. - * @param delay {Number} Delay in seconds. - * @param callback {Function} Callback function. - * - * @author agorbatchev - * @date 2011/08/25 - * @id TextExtPlugin.startTimer - */ - p.startTimer = function(name, delay, callback) - { - var self = this; - - self.stopTimer(name); - - self._timers[name] = setTimeout( - function() - { - delete self._timers[name]; - callback.apply(self); - }, - delay * 1000 - ); - }; - - /** - * Stops the timer by name without resetting it. - * - * @signature TextExtPlugin.stopTimer(name) - * - * @param name {String} Timer name. - * - * @author agorbatchev - * @date 2011/08/25 - * @id TextExtPlugin.stopTimer - */ - p.stopTimer = function(name) - { - clearTimeout(this._timers[name]); - }; - - /** - * Returns instance of the `TextExt` to which current instance of the plugin is attached to. - * - * @signature TextExtPlugin.core() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.core - */ - p.core = function() - { - return this._core; - }; - - /** - * Shortcut to the core's `opts()` method. Returns option value. - * - * @signature TextExtPlugin.opts(name) - * - * @param name {String} Option name as described in the options. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.opts - */ - p.opts = function(name) - { - return this.core().opts(name); - }; - - /** - * Shortcut to the core's `itemManager()` method. Returns instance of the `ItemManger` that is - * currently in use. - * - * @signature TextExtPlugin.itemManager() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.itemManager - */ - p.itemManager = function() - { - return this.core().itemManager(); - }; - - /** - * Shortcut to the core's `input()` method. Returns instance of the HTML element that represents - * current text input. - * - * @signature TextExtPlugin.input() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.input - */ - p.input = function() - { - return this.core().input(); - }; - - /** - * Shortcut to the commonly used `this.input().val()` call to get or set value of the text input. - * - * @signature TextExtPlugin.val(value) - * - * @param value {String} Optional value. If specified, the value will be set, otherwise it will be - * returned. - * - * @author agorbatchev - * @date 2011/08/20 - * @id TextExtPlugin.val - */ - p.val = function(value) - { - var input = this.input(); - - if(typeof(value) === UNDEFINED) - return input.val(); - else - input.val(value); - }; - - /** - * Shortcut to the core's `trigger()` method. Triggers specified event with arguments on the - * component core. - * - * @signature TextExtPlugin.trigger(event, ...args) - * - * @param event {String} Name of the event to trigger. - * @param ...args All remaining arguments will be passed to the event handler. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtPlugin.trigger - */ - p.trigger = function() - { - var core = this.core(); - core.trigger.apply(core, arguments); - }; - - /** - * Shortcut to the core's `bind()` method. Binds specified handler to the event. - * - * @signature TextExtPlugin.bind(event, handler) - * - * @param event {String} Event name. - * @param handler {Function} Event handler. - * - * @author agorbatchev - * @date 2011/08/20 - * @id TextExtPlugin.bind - */ - p.bind = function(event, handler) - { - this.core().bind(event, handler); - }; - - /** - * Returns initialization priority for this plugin. If current plugin depends upon some other plugin - * to be initialized before or after, priority needs to be adjusted accordingly. Plugins with higher - * priority initialize before plugins with lower priority. - * - * Default initialization priority is `0`. - * - * @signature TextExtPlugin.initPriority() - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtPlugin.initPriority - */ - p.initPriority = function() - { - return 0; - }; - - //-------------------------------------------------------------------------------- - // jQuery Integration - - /** - * TextExt integrates as a jQuery plugin available through the `$(selector).textext(opts)` call. If - * `opts` argument is passed, then a new instance of `TextExt` will be created for all the inputs - * that match the `selector`. If `opts` wasn't passed and TextExt was already intantiated for - * inputs that match the `selector`, array of `TextExt` instances will be returned instead. - * - * // will create a new instance of `TextExt` for all elements that match `.sample` - * $('.sample').textext({ ... }); - * - * // will return array of all `TextExt` instances - * var list = $('.sample').textext(); - * - * The following properties are also exposed through the jQuery `$.fn.textext`: - * - * * `TextExt` -- `TextExt` class. - * * `TextExtPlugin` -- `TextExtPlugin` class. - * * `ItemManager` -- `ItemManager` class. - * * `plugins` -- Key/value table of all registered plugins. - * * `addPlugin(name, constructor)` -- All plugins should register themselves using this function. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExt.jquery - */ - - var cssInjected = false; - - var textext = $.fn.textext = function(opts) - { - var css; - - if(!cssInjected && (css = $.fn.textext.css) != null) - { - $('head').append(''); - cssInjected = true; - } - - return this.map(function() - { - var self = $(this); - - if(opts == null) - return self.data('textext'); - - var instance = new TextExt(); - - instance.init(self, opts); - self.data('textext', instance); - - return instance.input()[0]; - }); - }; - - /** - * This static function registers a new plugin which makes it available through the `plugins` option - * to the end user. The name specified here is the name the end user would put in the `plugins` option - * to add this plugin to a new instance of TextExt. - * - * @signature $.fn.textext.addPlugin(name, constructor) - * - * @param name {String} Name of the plugin. - * @param constructor {Function} Plugin constructor. - * - * @author agorbatchev - * @date 2011/10/11 - * @id TextExt.addPlugin - */ - textext.addPlugin = function(name, constructor) - { - textext.plugins[name] = constructor; - constructor.prototype = new textext.TextExtPlugin(); - }; - - /** - * This static function registers a new patch which is added to each instance of TextExt. If you are - * adding a new patch, make sure to call this method. - * - * @signature $.fn.textext.addPatch(name, constructor) - * - * @param name {String} Name of the patch. - * @param constructor {Function} Patch constructor. - * - * @author agorbatchev - * @date 2011/10/11 - * @id TextExt.addPatch - */ - textext.addPatch = function(name, constructor) - { - textext.patches[name] = constructor; - constructor.prototype = new textext.TextExtPlugin(); - }; - - textext.TextExt = TextExt; - textext.TextExtPlugin = TextExtPlugin; - textext.ItemManager = ItemManager; - textext.plugins = {}; - textext.patches = {}; -})(jQuery); - -(function($) -{ - function TextExtIE9Patches() {}; - - $.fn.textext.TextExtIE9Patches = TextExtIE9Patches; - $.fn.textext.addPatch('ie9',TextExtIE9Patches); - - var p = TextExtIE9Patches.prototype; - - p.init = function(core) - { - if(navigator.userAgent.indexOf('MSIE 9') == -1) - return; - - var self = this; - - core.on({ postInvalidate : self.onPostInvalidate }); - }; - - p.onPostInvalidate = function() - { - var self = this, - input = self.input(), - val = input.val() - ; - - // agorbatchev :: IE9 doesn't seem to update the padding if box-sizing is on until the - // text box value changes, so forcing this change seems to do the trick of updating - // IE's padding visually. - input.val(Math.random()); - input.val(val); - }; -})(jQuery); - -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * AJAX plugin is very useful if you want to load list of items from a data point and pass it - * to the Autocomplete or Filter plugins. - * - * Because it meant to be as a helper method for either Autocomplete or Filter plugin, without - * either of these two present AJAX plugin won't do anything. - * - * @author agorbatchev - * @date 2011/08/16 - * @id TextExtAjax - */ - function TextExtAjax() {}; - - $.fn.textext.TextExtAjax = TextExtAjax; - $.fn.textext.addPlugin('ajax', TextExtAjax); - - var p = TextExtAjax.prototype, - - /** - * AJAX plugin options are grouped under `ajax` when passed to the `$().textext()` function. Be - * mindful that the whole `ajax` object is also passed to jQuery `$.ajax` call which means that - * you can change all jQuery options as well. Please refer to the jQuery documentation on how - * to set url and all other parameters. For example: - * - * $('textarea').textext({ - * plugins: 'ajax', - * ajax: { - * url: 'http://...' - * } - * }) - * - * **Important**: Because it's necessary to pass options to `jQuery.ajax()` in a single object, - * all jQuery related AJAX options like `url`, `dataType`, etc **must** be within the `ajax` object. - * This is the exception to general rule that TextExt options can be specified in dot or camel case - * notation. - * - * @author agorbatchev - * @date 2011/08/16 - * @id TextExtAjax.options - */ - - /** - * By default, when user starts typing into the text input, AJAX plugin will start making requests - * to the `url` that you have specified and will pass whatever user has typed so far as a parameter - * named `q`, eg `?q=foo`. - * - * If you wish to change this behaviour, you can pass a function as a value for this option which - * takes one argument (the user input) and should return a key/value object that will be converted - * to the request parameters. For example: - * - * 'dataCallback' : function(query) - * { - * return { 'search' : query }; - * } - * - * @name ajax.data.callback - * @default null - * @author agorbatchev - * @date 2011/08/16 - * @id TextExtAjax.options.data.callback - */ - OPT_DATA_CALLBACK = 'ajax.data.callback', - - /** - * By default, the server end point is constantly being reloaded whenever user changes the value - * in the text input. If you'd rather have the client do result filtering, you can return all - * possible results from the server and cache them on the client by setting this option to `true`. - * - * In such a case, only one call to the server will be made and filtering will be performed on - * the client side using `ItemManager` attached to the core. - * - * @name ajax.data.results - * @default false - * @author agorbatchev - * @date 2011/08/16 - * @id TextExtAjax.options.cache.results - */ - OPT_CACHE_RESULTS = 'ajax.cache.results', - - /** - * The loading message delay is set in seconds and will specify how long it would take before - * user sees the message. If you don't want user to ever see this message, set the option value - * to `Number.MAX_VALUE`. - * - * @name ajax.loading.delay - * @default 0.5 - * @author agorbatchev - * @date 2011/08/16 - * @id TextExtAjax.options.loading.delay - */ - OPT_LOADING_DELAY = 'ajax.loading.delay', - - /** - * Whenever an AJAX request is made and the server takes more than the number of seconds specified - * in `ajax.loading.delay` to respond, the message specified in this option will appear in the drop - * down. - * - * @name ajax.loading.message - * @default "Loading..." - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAjax.options.loading.message - */ - OPT_LOADING_MESSAGE = 'ajax.loading.message', - - /** - * When user is typing in or otherwise changing the value of the text input, it's undesirable to make - * an AJAX request for every keystroke. Instead it's more conservative to send a request every number - * of seconds while user is typing the value. This number of seconds is specified by the `ajax.type.delay` - * option. - * - * @name ajax.type.delay - * @default 0.5 - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAjax.options.type.delay - */ - OPT_TYPE_DELAY = 'ajax.type.delay', - - /** - * AJAX plugin dispatches or reacts to the following events. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAjax.events - */ - - /** - * AJAX plugin reacts to the `getSuggestions` event dispatched by the Autocomplete plugin. - * - * @name getSuggestions - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAjax.events.getSuggestions - */ - - /** - * In the event of successful AJAX request, the AJAX coponent dispatches the `setSuggestions` - * event meant to be recieved by the Autocomplete plugin. - * - * @name setSuggestions - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAjax.events.setSuggestions - */ - EVENT_SET_SUGGESTION = 'setSuggestions', - - /** - * AJAX plugin dispatches the `showDropdown` event which Autocomplete plugin is expecting. - * This is used to temporarily show the loading message if the AJAX request is taking longer - * than expected. - * - * @name showDropdown - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAjax.events.showDropdown - */ - EVENT_SHOW_DROPDOWN = 'showDropdown', - - TIMER_LOADING = 'loading', - - DEFAULT_OPTS = { - ajax : { - typeDelay : 0.5, - loadingMessage : 'Loading...', - loadingDelay : 0.5, - cacheResults : false, - dataCallback : null - } - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtAjax.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAjax.init - */ - p.init = function(core) - { - var self = this; - - self.baseInit(core, DEFAULT_OPTS); - - self.on({ - getSuggestions : self.onGetSuggestions - }); - - self._suggestions = null; - }; - - /** - * Performas an async AJAX with specified options. - * - * @signature TextExtAjax.load(query) - * - * @param query {String} Value that user has typed into the text area which is - * presumably the query. - * - * @author agorbatchev - * @date 2011/08/14 - * @id TextExtAjax.load - */ - p.load = function(query) - { - var self = this, - dataCallback = self.opts(OPT_DATA_CALLBACK) || function(query) { return { q : query } }, - opts - ; - - opts = $.extend(true, - { - data : dataCallback(query), - success : function(data) { self.onComplete(data, query) }, - error : function(jqXHR, message) { console.error(message, query) } - }, - self.opts('ajax') - ); - - $.ajax(opts); - }; - - /** - * Successful call AJAX handler. Takes the data that came back from AJAX and the - * original query that was used to make the call. - * - * @signature TextExtAjax.onComplete(data, query) - * - * @param data {Object} Data loaded from the server, should be an Array of strings - * by default or whatever data structure your custom `ItemManager` implements. - * - * @param query {String} Query string, ie whatever user has typed in. - * - * @author agorbatchev - * @date 2011/08/14 - * @id TextExtAjax.onComplete - */ - p.onComplete = function(data, query) - { - var self = this, - result = data - ; - - self.dontShowLoading(); - - // If results are expected to be cached, then we store the original - // data set and return the filtered one based on the original query. - // That means we do filtering on the client side, instead of the - // server side. - if(self.opts(OPT_CACHE_RESULTS) == true) - { - self._suggestions = data; - result = self.itemManager().filter(data, query); - } - - self.trigger(EVENT_SET_SUGGESTION, { result : result }); - }; - - /** - * If show loading message timer was started, calling this function disables it, - * otherwise nothing else happens. - * - * @signature TextExtAjax.dontShowLoading() - * - * @author agorbatchev - * @date 2011/08/16 - * @id TextExtAjax.dontShowLoading - */ - p.dontShowLoading = function() - { - this.stopTimer(TIMER_LOADING); - }; - - /** - * Shows message specified in `ajax.loading.message` if loading data takes more than - * number of seconds specified in `ajax.loading.delay`. - * - * @signature TextExtAjax.showLoading() - * - * @author agorbatchev - * @date 2011/08/15 - * @id TextExtAjax.showLoading - */ - p.showLoading = function() - { - var self = this; - - self.dontShowLoading(); - self.startTimer( - TIMER_LOADING, - self.opts(OPT_LOADING_DELAY), - function() - { - self.trigger(EVENT_SHOW_DROPDOWN, function(autocomplete) - { - autocomplete.clearItems(); - var node = autocomplete.addDropdownItem(self.opts(OPT_LOADING_MESSAGE)); - node.addClass('text-loading'); - }); - } - ); - }; - - /** - * Reacts to the `getSuggestions` event and begin loading suggestions. If - * `ajax.cache.results` is specified, all calls after the first one will use - * cached data and filter it with the `core.itemManager.filter()`. - * - * @signature TextExtAjax.onGetSuggestions(e, data) - * - * @param e {Object} jQuery event. - * @param data {Object} Data structure passed with the `getSuggestions` event - * which contains the user query, eg `{ query : "..." }`. - * - * @author agorbatchev - * @date 2011/08/15 - * @id TextExtAjax.onGetSuggestions - */ - p.onGetSuggestions = function(e, data) - { - var self = this, - suggestions = self._suggestions, - query = (data || {}).query || '' - ; - - if(suggestions && self.opts(OPT_CACHE_RESULTS) === true) - return self.onComplete(suggestions, query); - - self.startTimer( - 'ajax', - self.opts(OPT_TYPE_DELAY), - function() - { - self.showLoading(); - self.load(query); - } - ); - }; -})(jQuery); -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * Displays a dropdown style arrow button. The `TextExtArrow` works together with the - * `TextExtAutocomplete` plugin and whenever clicked tells the autocomplete plugin to - * display its suggestions. - * - * @author agorbatchev - * @date 2011/12/27 - * @id TextExtArrow - */ - function TextExtArrow() {}; - - $.fn.textext.TextExtArrow = TextExtArrow; - $.fn.textext.addPlugin('arrow', TextExtArrow); - - var p = TextExtArrow.prototype, - /** - * Arrow plugin only has one option and that is its HTML template. It could be - * changed when passed to the `$().textext()` function. For example: - * - * $('textarea').textext({ - * plugins: 'arrow', - * html: { - * arrow: "" - * } - * }) - * - * @author agorbatchev - * @date 2011/12/27 - * @id TextExtArrow.options - */ - - /** - * HTML source that is used to generate markup required for the arrow. - * - * @name html.arrow - * @default '
' - * @author agorbatchev - * @date 2011/12/27 - * @id TextExtArrow.options.html.arrow - */ - OPT_HTML_ARROW = 'html.arrow', - - DEFAULT_OPTS = { - html : { - arrow : '
' - } - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtArrow.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/12/27 - * @id TextExtArrow.init - */ - p.init = function(core) - { - var self = this, - arrow - ; - - self.baseInit(core, DEFAULT_OPTS); - - self._arrow = arrow = $(self.opts(OPT_HTML_ARROW)); - self.core().wrapElement().append(arrow); - arrow.bind('click', function(e) { self.onArrowClick(e); }); - }; - - //-------------------------------------------------------------------------------- - // Event handlers - - /** - * Reacts to the `click` event whenever user clicks the arrow. - * - * @signature TextExtArrow.onArrowClick(e) - * - * @param e {Object} jQuery event. - * @author agorbatchev - * @date 2011/12/27 - * @id TextExtArrow.onArrowClick - */ - p.onArrowClick = function(e) - { - this.trigger('toggleDropdown'); - this.core().focusInput(); - }; - - //-------------------------------------------------------------------------------- - // Core functionality - -})(jQuery); -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * Autocomplete plugin brings the classic autocomplete functionality to the TextExt echosystem. - * The gist of functionality is when user starts typing in, for example a term or a tag, a - * dropdown would be presented with possible suggestions to complete the input quicker. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete - */ - function TextExtAutocomplete() {}; - - $.fn.textext.TextExtAutocomplete = TextExtAutocomplete; - $.fn.textext.addPlugin('autocomplete', TextExtAutocomplete); - - var p = TextExtAutocomplete.prototype, - - CSS_DOT = '.', - CSS_SELECTED = 'text-selected', - CSS_DOT_SELECTED = CSS_DOT + CSS_SELECTED, - CSS_SUGGESTION = 'text-suggestion', - CSS_DOT_SUGGESTION = CSS_DOT + CSS_SUGGESTION, - CSS_LABEL = 'text-label', - CSS_DOT_LABEL = CSS_DOT + CSS_LABEL, - - /** - * Autocomplete plugin options are grouped under `autocomplete` when passed to the - * `$().textext()` function. For example: - * - * $('textarea').textext({ - * plugins: 'autocomplete', - * autocomplete: { - * dropdownPosition: 'above' - * } - * }) - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.options - */ - - /** - * This is a toggle switch to enable or disable the Autucomplete plugin. The value is checked - * each time at the top level which allows you to toggle this setting on the fly. - * - * @name autocomplete.enabled - * @default true - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.options.autocomplete.enabled - */ - OPT_ENABLED = 'autocomplete.enabled', - - /** - * This option allows to specify position of the dropdown. The two possible values - * are `above` and `below`. - * - * @name autocomplete.dropdown.position - * @default "below" - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.options.autocomplete.dropdown.position - */ - OPT_POSITION = 'autocomplete.dropdown.position', - - /** - * This option allows to specify maximum height of the dropdown. Value is taken directly, so - * if desired height is 200 pixels, value must be `200px`. - * - * @name autocomplete.dropdown.maxHeight - * @default "100px" - * @author agorbatchev - * @date 2011/12/29 - * @id TextExtAutocomplete.options.autocomplete.dropdown.maxHeight - * @version 1.1 - */ - OPT_MAX_HEIGHT = 'autocomplete.dropdown.maxHeight', - - /** - * This option allows to override how a suggestion item is rendered. The value should be - * a function, the first argument of which is suggestion to be rendered and `this` context - * is the current instance of `TextExtAutocomplete`. - * - * [Click here](/manual/examples/autocomplete-with-custom-render.html) to see a demo. - * - * For example: - * - * $('textarea').textext({ - * plugins: 'autocomplete', - * autocomplete: { - * render: function(suggestion) - * { - * return '' + suggestion + ''; - * } - * } - * }) - * - * @name autocomplete.render - * @default null - * @author agorbatchev - * @date 2011/12/23 - * @id TextExtAutocomplete.options.autocomplete.render - * @version 1.1 - */ - OPT_RENDER = 'autocomplete.render', - - /** - * HTML source that is used to generate the dropdown. - * - * @name html.dropdown - * @default '
' - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.options.html.dropdown - */ - OPT_HTML_DROPDOWN = 'html.dropdown', - - /** - * HTML source that is used to generate each suggestion. - * - * @name html.suggestion - * @default '
' - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.options.html.suggestion - */ - OPT_HTML_SUGGESTION = 'html.suggestion', - - /** - * Autocomplete plugin triggers or reacts to the following events. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.events - */ - - /** - * Autocomplete plugin triggers and reacts to the `hideDropdown` to hide the dropdown if it's - * already visible. - * - * @name hideDropdown - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.events.hideDropdown - */ - EVENT_HIDE_DROPDOWN = 'hideDropdown', - - /** - * Autocomplete plugin triggers and reacts to the `showDropdown` to show the dropdown if it's - * not already visible. - * - * It's possible to pass a render callback function which will be called instead of the - * default `TextExtAutocomplete.renderSuggestions()`. - * - * Here's how another plugin should trigger this event with the optional render callback: - * - * this.trigger('showDropdown', function(autocomplete) - * { - * autocomplete.clearItems(); - * var node = autocomplete.addDropdownItem('Item'); - * node.addClass('new-look'); - * }); - * - * @name showDropdown - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.events.showDropdown - */ - EVENT_SHOW_DROPDOWN = 'showDropdown', - - /** - * Autocomplete plugin reacts to the `setSuggestions` event triggered by other plugins which - * wish to populate the suggestion items. Suggestions should be passed as event argument in the - * following format: `{ data : [ ... ] }`. - * - * Here's how another plugin should trigger this event: - * - * this.trigger('setSuggestions', { data : [ "item1", "item2" ] }); - * - * @name setSuggestions - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.events.setSuggestions - */ - - /** - * Autocomplete plugin triggers the `getSuggestions` event and expects to get results by listening for - * the `setSuggestions` event. - * - * @name getSuggestions - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.events.getSuggestions - */ - EVENT_GET_SUGGESTIONS = 'getSuggestions', - - /** - * Autocomplete plugin triggers `getFormData` event with the current suggestion so that the the core - * will be updated with serialized data to be submitted with the HTML form. - * - * @name getFormData - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtAutocomplete.events.getFormData - */ - EVENT_GET_FORM_DATA = 'getFormData', - - /** - * Autocomplete plugin reacts to `toggleDropdown` event and either shows or hides the dropdown - * depending if it's currently hidden or visible. - * - * @name toggleDropdown - * @author agorbatchev - * @date 2011/12/27 - * @id TextExtAutocomplete.events.toggleDropdown - * @version 1.1 - */ - EVENT_TOGGLE_DROPDOWN = 'toggleDropdown', - - POSITION_ABOVE = 'above', - POSITION_BELOW = 'below', - - DATA_MOUSEDOWN_ON_AUTOCOMPLETE = 'mousedownOnAutocomplete', - - DEFAULT_OPTS = { - autocomplete : { - enabled : true, - dropdown : { - position : POSITION_BELOW, - maxHeight : '100px' - } - }, - - html : { - dropdown : '
', - suggestion : '
' - } - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtAutocomplete.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.init - */ - p.init = function(core) - { - var self = this; - - self.baseInit(core, DEFAULT_OPTS); - - var input = self.input(), - container - ; - - if(self.opts(OPT_ENABLED) === true) - { - self.on({ - blur : self.onBlur, - anyKeyUp : self.onAnyKeyUp, - deleteKeyUp : self.onAnyKeyUp, - backspaceKeyPress : self.onBackspaceKeyPress, - enterKeyPress : self.onEnterKeyPress, - escapeKeyPress : self.onEscapeKeyPress, - setSuggestions : self.onSetSuggestions, - showDropdown : self.onShowDropdown, - hideDropdown : self.onHideDropdown, - toggleDropdown : self.onToggleDropdown, - postInvalidate : self.positionDropdown, - getFormData : self.onGetFormData, - - // using keyDown for up/down keys so that repeat events are - // captured and user can scroll up/down by holding the keys - downKeyDown : self.onDownKeyDown, - upKeyDown : self.onUpKeyDown - }); - - container = $(self.opts(OPT_HTML_DROPDOWN)); - container.insertAfter(input); - - self.on(container, { - mouseover : self.onMouseOver, - mousedown : self.onMouseDown, - click : self.onClick - }); - - container - .css('maxHeight', self.opts(OPT_MAX_HEIGHT)) - .addClass('text-position-' + self.opts(OPT_POSITION)) - ; - - $(self).data('container', container); - - $(document.body).click(function(e) - { - if (self.isDropdownVisible() && !self.withinWrapElement(e.target)) - self.trigger(EVENT_HIDE_DROPDOWN); - }); - - self.positionDropdown(); - } - }; - - /** - * Returns top level dropdown container HTML element. - * - * @signature TextExtAutocomplete.containerElement() - * - * @author agorbatchev - * @date 2011/08/15 - * @id TextExtAutocomplete.containerElement - */ - p.containerElement = function() - { - return $(this).data('container'); - }; - - //-------------------------------------------------------------------------------- - // User mouse/keyboard input - - /** - * Reacts to the `mouseOver` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onMouseOver(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onMouseOver - */ - p.onMouseOver = function(e) - { - var self = this, - target = $(e.target) - ; - - if(target.is(CSS_DOT_SUGGESTION)) - { - self.clearSelected(); - target.addClass(CSS_SELECTED); - } - }; - - /** - * Reacts to the `mouseDown` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onMouseDown(e) - * - * @param e {Object} jQuery event. - * - * @author adamayres - * @date 2012/01/13 - * @id TextExtAutocomplete.onMouseDown - */ - p.onMouseDown = function(e) - { - this.containerElement().data(DATA_MOUSEDOWN_ON_AUTOCOMPLETE, true); - }; - - /** - * Reacts to the `click` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onClick(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onClick - */ - p.onClick = function(e) - { - var self = this, - target = $(e.target) - ; - - if($(CSS_DOT_SUGGESTION).has(target[0]) || $(CSS_DOT_LABEL).has(target[0])) - self.trigger('enterKeyPress'); - - if (self.core().hasPlugin('tags')) - self.val(''); - }; - - /** - * Reacts to the `blur` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onBlur(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onBlur - */ - p.onBlur = function(e) - { - var self = this, - container = self.containerElement(), - isBlurByMousedown = container.data(DATA_MOUSEDOWN_ON_AUTOCOMPLETE) === true - ; - - // only trigger a close event if the blur event was - // not triggered by a mousedown event on the autocomplete - // otherwise set focus back back on the input - if(self.isDropdownVisible()) - isBlurByMousedown ? self.core().focusInput() : self.trigger(EVENT_HIDE_DROPDOWN); - - container.removeData(DATA_MOUSEDOWN_ON_AUTOCOMPLETE); - }; - - /** - * Reacts to the `backspaceKeyPress` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onBackspaceKeyPress(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onBackspaceKeyPress - */ - p.onBackspaceKeyPress = function(e) - { - var self = this, - isEmpty = self.val().length > 0 - ; - - if(isEmpty || self.isDropdownVisible()) - self.getSuggestions(); - }; - - /** - * Reacts to the `anyKeyUp` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onAnyKeyUp(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onAnyKeyUp - */ - p.onAnyKeyUp = function(e, keyCode) - { - var self = this, - isFunctionKey = self.opts('keys.' + keyCode) != null - ; - - if(self.val().length > 0 && !isFunctionKey) - self.getSuggestions(); - }; - - /** - * Reacts to the `downKeyDown` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onDownKeyDown(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onDownKeyDown - */ - p.onDownKeyDown = function(e) - { - var self = this; - - self.isDropdownVisible() - ? self.toggleNextSuggestion() - : self.getSuggestions() - ; - }; - - /** - * Reacts to the `upKeyDown` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onUpKeyDown(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onUpKeyDown - */ - p.onUpKeyDown = function(e) - { - this.togglePreviousSuggestion(); - }; - - /** - * Reacts to the `enterKeyPress` event triggered by the TextExt core. - * - * @signature TextExtAutocomplete.onEnterKeyPress(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onEnterKeyPress - */ - p.onEnterKeyPress = function(e) - { - var self = this; - - if(self.isDropdownVisible()) - self.selectFromDropdown(); - }; - - /** - * Reacts to the `escapeKeyPress` event triggered by the TextExt core. Hides the dropdown - * if it's currently visible. - * - * @signature TextExtAutocomplete.onEscapeKeyPress(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onEscapeKeyPress - */ - p.onEscapeKeyPress = function(e) - { - var self = this; - - if(self.isDropdownVisible()) - self.trigger(EVENT_HIDE_DROPDOWN); - }; - - //-------------------------------------------------------------------------------- - // Core functionality - - /** - * Positions dropdown either below or above the input based on the `autocomplete.dropdown.position` - * option specified, which could be either `above` or `below`. - * - * @signature TextExtAutocomplete.positionDropdown() - * - * @author agorbatchev - * @date 2011/08/15 - * @id TextExtAutocomplete.positionDropdown - */ - p.positionDropdown = function() - { - var self = this, - container = self.containerElement(), - direction = self.opts(OPT_POSITION), - height = self.core().wrapElement().outerHeight(), - css = {} - ; - - css[direction === POSITION_ABOVE ? 'bottom' : 'top'] = height + 'px'; - container.css(css); - }; - - /** - * Returns list of all the suggestion HTML elements in the dropdown. - * - * @signature TextExtAutocomplete.suggestionElements() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.suggestionElements - */ - p.suggestionElements = function() - { - return this.containerElement().find(CSS_DOT_SUGGESTION); - }; - - - /** - * Highlights specified suggestion as selected in the dropdown. - * - * @signature TextExtAutocomplete.setSelectedSuggestion(suggestion) - * - * @param suggestion {Object} Suggestion object. With the default `ItemManager` this - * is expected to be a string, anything else with custom implementations. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.setSelectedSuggestion - */ - p.setSelectedSuggestion = function(suggestion) - { - if(!suggestion) - return; - - var self = this, - all = self.suggestionElements(), - target = all.first(), - item, i - ; - - self.clearSelected(); - - for(i = 0; i < all.length; i++) - { - item = $(all[i]); - - if(self.itemManager().compareItems(item.data(CSS_SUGGESTION), suggestion)) - { - target = item.addClass(CSS_SELECTED); - break; - } - } - - target.addClass(CSS_SELECTED); - self.scrollSuggestionIntoView(target); - }; - - /** - * Returns the first suggestion HTML element from the dropdown that is highlighted as selected. - * - * @signature TextExtAutocomplete.selectedSuggestionElement() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.selectedSuggestionElement - */ - p.selectedSuggestionElement = function() - { - return this.suggestionElements().filter(CSS_DOT_SELECTED).first(); - }; - - /** - * Returns `true` if dropdown is currently visible, `false` otherwise. - * - * @signature TextExtAutocomplete.isDropdownVisible() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.isDropdownVisible - */ - p.isDropdownVisible = function() - { - return this.containerElement().is(':visible') === true; - }; - - /** - * Reacts to the `getFormData` event triggered by the core. Returns data with the - * weight of 100 to be *less than the Tags plugin* data weight. The weights system is - * covered in greater detail in the [`getFormData`][1] event documentation. - * - * [1]: /manual/textext.html#getformdata - * - * @signature TextExtAutocomplete.onGetFormData(e, data, keyCode) - * - * @param e {Object} jQuery event. - * @param data {Object} Data object to be populated. - * @param keyCode {Number} Key code that triggered the original update request. - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtAutocomplete.onGetFormData - */ - p.onGetFormData = function(e, data, keyCode) - { - var self = this, - val = self.val(), - inputValue = val, - formValue = val - ; - data[100] = self.formDataObject(inputValue, formValue); - }; - - /** - * Returns initialization priority of the Autocomplete plugin which is expected to be - * *greater than the Tags plugin* because of the dependencies. The value is 200. - * - * @signature TextExtAutocomplete.initPriority() - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtAutocomplete.initPriority - */ - p.initPriority = function() - { - return 200; - }; - - /** - * Reacts to the `hideDropdown` event and hides the dropdown if it's already visible. - * - * @signature TextExtAutocomplete.onHideDropdown(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onHideDropdown - */ - p.onHideDropdown = function(e) - { - this.hideDropdown(); - }; - - /** - * Reacts to the 'toggleDropdown` event and shows or hides the dropdown depending if - * it's currently hidden or visible. - * - * @signature TextExtAutocomplete.onToggleDropdown(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/12/27 - * @id TextExtAutocomplete.onToggleDropdown - * @version 1.1.0 - */ - p.onToggleDropdown = function(e) - { - var self = this; - self.trigger(self.containerElement().is(':visible') ? EVENT_HIDE_DROPDOWN : EVENT_SHOW_DROPDOWN); - }; - - /** - * Reacts to the `showDropdown` event and shows the dropdown if it's not already visible. - * It's possible to pass a render callback function which will be called instead of the - * default `TextExtAutocomplete.renderSuggestions()`. - * - * If no suggestion were previously loaded, it will fire `getSuggestions` event and exit. - * - * Here's how another plugin should trigger this event with the optional render callback: - * - * this.trigger('showDropdown', function(autocomplete) - * { - * autocomplete.clearItems(); - * var node = autocomplete.addDropdownItem('Item'); - * node.addClass('new-look'); - * }); - * - * @signature TextExtAutocomplete.onShowDropdown(e, renderCallback) - * - * @param e {Object} jQuery event. - * @param renderCallback {Function} Optional callback function which would be used to - * render dropdown items. As a first argument, reference to the current instance of - * Autocomplete plugin will be supplied. It's assumed, that if this callback is provided - * rendering will be handled completely manually. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onShowDropdown - */ - p.onShowDropdown = function(e, renderCallback) - { - var self = this, - current = self.selectedSuggestionElement().data(CSS_SUGGESTION), - suggestions = self._suggestions - ; - - if(!suggestions) - return self.trigger(EVENT_GET_SUGGESTIONS); - - if($.isFunction(renderCallback)) - { - renderCallback(self); - } - else - { - self.renderSuggestions(self._suggestions); - self.toggleNextSuggestion(); - } - - self.showDropdown(self.containerElement()); - self.setSelectedSuggestion(current); - }; - - /** - * Reacts to the `setSuggestions` event. Expects to recieve the payload as the second argument - * in the following structure: - * - * { - * result : [ "item1", "item2" ], - * showHideDropdown : false - * } - * - * Notice the optional `showHideDropdown` option. By default, ie without the `showHideDropdown` - * value the method will trigger either `showDropdown` or `hideDropdown` depending if there are - * suggestions. If set to `false`, no event is triggered. - * - * @signature TextExtAutocomplete.onSetSuggestions(e, data) - * - * @param data {Object} Data payload. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.onSetSuggestions - */ - p.onSetSuggestions = function(e, data) - { - var self = this, - suggestions = self._suggestions = data.result - ; - - if(data.showHideDropdown !== false) - self.trigger(suggestions === null || suggestions.length === 0 ? EVENT_HIDE_DROPDOWN : EVENT_SHOW_DROPDOWN); - }; - - /** - * Prepears for and triggers the `getSuggestions` event with the `{ query : {String} }` as second - * argument. - * - * @signature TextExtAutocomplete.getSuggestions() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.getSuggestions - */ - p.getSuggestions = function() - { - var self = this, - val = self.val() - ; - - if(self._previousInputValue == val) - return; - - // if user clears input, then we want to select first suggestion - // instead of the last one - if(val == '') - current = null; - - self._previousInputValue = val; - self.trigger(EVENT_GET_SUGGESTIONS, { query : val }); - }; - - /** - * Removes all HTML suggestion items from the dropdown. - * - * @signature TextExtAutocomplete.clearItems() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.clearItems - */ - p.clearItems = function() - { - this.containerElement().find('.text-list').children().remove(); - }; - - /** - * Clears all and renders passed suggestions. - * - * @signature TextExtAutocomplete.renderSuggestions(suggestions) - * - * @param suggestions {Array} List of suggestions to render. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.renderSuggestions - */ - p.renderSuggestions = function(suggestions) - { - var self = this; - - self.clearItems(); - - $.each(suggestions || [], function(index, item) - { - self.addSuggestion(item); - }); - }; - - /** - * Shows the dropdown. - * - * @signature TextExtAutocomplete.showDropdown() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.showDropdown - */ - p.showDropdown = function() - { - this.containerElement().show(); - }; - - /** - * Hides the dropdown. - * - * @signature TextExtAutocomplete.hideDropdown() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.hideDropdown - */ - p.hideDropdown = function() - { - var self = this, - dropdown = self.containerElement() - ; - - self._previousInputValue = null; - dropdown.hide(); - }; - - /** - * Adds single suggestion to the bottom of the dropdown. Uses `ItemManager.itemToString()` to - * serialize provided suggestion to string. - * - * @signature TextExtAutocomplete.addSuggestion(suggestion) - * - * @param suggestion {Object} Suggestion item. By default expected to be a string. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.addSuggestion - */ - p.addSuggestion = function(suggestion) - { - var self = this, - renderer = self.opts(OPT_RENDER), - node = self.addDropdownItem(renderer ? renderer.call(self, suggestion) : self.itemManager().itemToString(suggestion)) - ; - - node.data(CSS_SUGGESTION, suggestion); - }; - - /** - * Adds and returns HTML node to the bottom of the dropdown. - * - * @signature TextExtAutocomplete.addDropdownItem(html) - * - * @param html {String} HTML to be inserted into the item. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.addDropdownItem - */ - p.addDropdownItem = function(html) - { - var self = this, - container = self.containerElement().find('.text-list'), - node = $(self.opts(OPT_HTML_SUGGESTION)) - ; - - node.find('.text-label').html(html); - container.append(node); - return node; - }; - - /** - * Removes selection highlight from all suggestion elements. - * - * @signature TextExtAutocomplete.clearSelected() - * - * @author agorbatchev - * @date 2011/08/02 - * @id TextExtAutocomplete.clearSelected - */ - p.clearSelected = function() - { - this.suggestionElements().removeClass(CSS_SELECTED); - }; - - /** - * Selects next suggestion relative to the current one. If there's no - * currently selected suggestion, it will select the first one. Selected - * suggestion will always be scrolled into view. - * - * @signature TextExtAutocomplete.toggleNextSuggestion() - * - * @author agorbatchev - * @date 2011/08/02 - * @id TextExtAutocomplete.toggleNextSuggestion - */ - p.toggleNextSuggestion = function() - { - var self = this, - selected = self.selectedSuggestionElement(), - next - ; - - if(selected.length > 0) - { - next = selected.next(); - - if(next.length > 0) - selected.removeClass(CSS_SELECTED); - } - else - { - next = self.suggestionElements().first(); - } - - next.addClass(CSS_SELECTED); - self.scrollSuggestionIntoView(next); - }; - - /** - * Selects previous suggestion relative to the current one. Selected - * suggestion will always be scrolled into view. - * - * @signature TextExtAutocomplete.togglePreviousSuggestion() - * - * @author agorbatchev - * @date 2011/08/02 - * @id TextExtAutocomplete.togglePreviousSuggestion - */ - p.togglePreviousSuggestion = function() - { - var self = this, - selected = self.selectedSuggestionElement(), - prev = selected.prev() - ; - - if(prev.length == 0) - return; - - self.clearSelected(); - prev.addClass(CSS_SELECTED); - self.scrollSuggestionIntoView(prev); - }; - - /** - * Scrolls specified HTML suggestion element into the view. - * - * @signature TextExtAutocomplete.scrollSuggestionIntoView(item) - * - * @param item {HTMLElement} jQuery HTML suggestion element which needs to - * scrolled into view. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.scrollSuggestionIntoView - */ - p.scrollSuggestionIntoView = function(item) - { - var itemHeight = item.outerHeight(), - dropdown = this.containerElement(), - dropdownHeight = dropdown.innerHeight(), - scrollPos = dropdown.scrollTop(), - itemTop = (item.position() || {}).top, - scrollTo = null, - paddingTop = parseInt(dropdown.css('paddingTop')) - ; - - if(itemTop == null) - return; - - // if scrolling down and item is below the bottom fold - if(itemTop + itemHeight > dropdownHeight) - scrollTo = itemTop + scrollPos + itemHeight - dropdownHeight + paddingTop; - - // if scrolling up and item is above the top fold - if(itemTop < 0) - scrollTo = itemTop + scrollPos - paddingTop; - - if(scrollTo != null) - dropdown.scrollTop(scrollTo); - }; - - /** - * Uses the value from the text input to finish autocomplete action. Currently selected - * suggestion from the dropdown will be used to complete the action. Triggers `hideDropdown` - * event. - * - * @signature TextExtAutocomplete.selectFromDropdown() - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtAutocomplete.selectFromDropdown - */ - p.selectFromDropdown = function() - { - var self = this, - suggestion = self.selectedSuggestionElement().data(CSS_SUGGESTION) - ; - - if(suggestion) - { - self.val(self.itemManager().itemToString(suggestion)); - self.core().getFormData(); - } - - self.trigger(EVENT_HIDE_DROPDOWN); - }; - - /** - * Determines if the specified HTML element is within the TextExt core wrap HTML element. - * - * @signature TextExtAutocomplete.withinWrapElement(element) - * - * @param element {HTMLElement} element to check if contained by wrap element - * - * @author adamayres - * @version 1.3.0 - * @date 2012/01/15 - * @id TextExtAutocomplete.withinWrapElement - */ - p.withinWrapElement = function(element) - { - return this.core().wrapElement().find(element).size() > 0; - } -})(jQuery); -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * The Filter plugin introduces ability to limit input that the text field - * will accept. If the Tags plugin is used, Filter plugin will limit which - * tags it's possible to add. - * - * The list of allowed items can be either specified through the - * options, can come from the Suggestions plugin or be loaded by the Ajax - * plugin. All these plugins have one thing in common -- they - * trigger `setSuggestions` event which the Filter plugin is expecting. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter - */ - function TextExtFilter() {}; - - $.fn.textext.TextExtFilter = TextExtFilter; - $.fn.textext.addPlugin('filter', TextExtFilter); - - var p = TextExtFilter.prototype, - - /** - * Filter plugin options are grouped under `filter` when passed to the - * `$().textext()` function. For example: - * - * $('textarea').textext({ - * plugins: 'filter', - * filter: { - * items: [ "item1", "item2" ] - * } - * }) - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.options - */ - - /** - * This is a toggle switch to enable or disable the Filter plugin. The value is checked - * each time at the top level which allows you to toggle this setting on the fly. - * - * @name filter.enabled - * @default true - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.options.enabled - */ - OPT_ENABLED = 'filter.enabled', - - /** - * Arra of items that the Filter plugin will allow the Tag plugin to add to the list of - * its resut tags. Each item by default is expected to be a string which default `ItemManager` - * can work with. You can change the item type by supplying custom `ItemManager`. - * - * @name filter.items - * @default null - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.options.items - */ - OPT_ITEMS = 'filter.items', - - /** - * Filter plugin dispatches and reacts to the following events. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.events - */ - - /** - * Filter plugin reacts to the `isTagAllowed` event triggered by the Tags plugin before - * adding a new tag to the list. If the new tag is among the `items` specified in options, - * then the new tag will be allowed. - * - * @name isTagAllowed - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.events.isTagAllowed - */ - - /** - * Filter plugin reacts to the `setSuggestions` event triggered by other plugins like - * Suggestions and Ajax. - * - * However, event if this event is handled and items are passed with it and stored, if `items` - * option was supplied, it will always take precedense. - * - * @name setSuggestions - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.events.setSuggestions - */ - - DEFAULT_OPTS = { - filter : { - enabled : true, - items : null - } - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtFilter.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.init - */ - p.init = function(core) - { - var self = this; - self.baseInit(core, DEFAULT_OPTS); - - self.on({ - getFormData : self.onGetFormData, - isTagAllowed : self.onIsTagAllowed, - setSuggestions : self.onSetSuggestions - }); - - self._suggestions = null; - }; - - //-------------------------------------------------------------------------------- - // Core functionality - - /** - * Reacts to the [`getFormData`][1] event triggered by the core. Returns data with the - * weight of 200 to be *greater than the Autocomplete plugins* data weights. - * The weights system is covered in greater detail in the [`getFormData`][1] event - * documentation. - * - * This method does nothing if Tags tag is also present. - * - * [1]: /manual/textext.html#getformdata - * - * @signature TextExtFilter.onGetFormData(e, data, keyCode) - * - * @param e {Object} jQuery event. - * @param data {Object} Data object to be populated. - * @param keyCode {Number} Key code that triggered the original update request. - * - * @author agorbatchev - * @date 2011/12/28 - * @id TextExtFilter.onGetFormData - * @version 1.1 - */ - p.onGetFormData = function(e, data, keyCode) - { - var self = this, - val = self.val(), - inputValue = val, - formValue = '' - ; - - if(!self.core().hasPlugin('tags')) - { - if(self.isValueAllowed(inputValue)) - formValue = val; - - data[300] = self.formDataObject(inputValue, formValue); - } - }; - - /** - * Checks given value if it's present in `filterItems` or was loaded for the Autocomplete - * or by the Suggestions plugins. `value` is compared to each item using `ItemManager.compareItems` - * method which is currently attached to the core. Returns `true` if value is known or - * Filter plugin is disabled. - * - * @signature TextExtFilter.isValueAllowed(value) - * - * @param value {Object} Value to check. - * - * @author agorbatchev - * @date 2011/12/28 - * @id TextExtFilter.isValueAllowed - * @version 1.1 - */ - p.isValueAllowed = function(value) - { - var self = this, - list = self.opts('filterItems') || self._suggestions || [], - itemManager = self.itemManager(), - result = !self.opts(OPT_ENABLED), // if disabled, should just return true - i - ; - - for(i = 0; i < list.length && !result; i++) - if(itemManager.compareItems(value, list[i])) - result = true; - - return result; - }; - - /** - * Handles `isTagAllowed` event dispatched by the Tags plugin. If supplied tag is not - * in the `items` list, method sets `result` on the `data` argument to `false`. - * - * @signature TextExtFilter.onIsTagAllowed(e, data) - * - * @param e {Object} jQuery event. - * @param data {Object} Payload in the following format : `{ tag : {Object}, result : {Boolean} }`. - * @author agorbatchev - * @date 2011/08/04 - * @id TextExtFilter.onIsTagAllowed - */ - p.onIsTagAllowed = function(e, data) - { - data.result = this.isValueAllowed(data.tag); - }; - - /** - * Reacts to the `setSuggestions` events and stores supplied suggestions for future use. - * - * @signature TextExtFilter.onSetSuggestions(e, data) - * - * @param e {Object} jQuery event. - * @param data {Object} Payload in the following format : `{ result : {Array} } }`. - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFilter.onSetSuggestions - */ - p.onSetSuggestions = function(e, data) - { - this._suggestions = data.result; - }; -})(jQuery); -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * Focus plugin displays a visual effect whenever user sets focus - * into the text area. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFocus - */ - function TextExtFocus() {}; - - $.fn.textext.TextExtFocus = TextExtFocus; - $.fn.textext.addPlugin('focus', TextExtFocus); - - var p = TextExtFocus.prototype, - /** - * Focus plugin only has one option and that is its HTML template. It could be - * changed when passed to the `$().textext()` function. For example: - * - * $('textarea').textext({ - * plugins: 'focus', - * html: { - * focus: "" - * } - * }) - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFocus.options - */ - - /** - * HTML source that is used to generate markup required for the focus effect. - * - * @name html.focus - * @default '
' - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFocus.options.html.focus - */ - OPT_HTML_FOCUS = 'html.focus', - - /** - * Focus plugin dispatches or reacts to the following events. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtFocus.events - */ - - /** - * Focus plugin reacts to the `focus` event and shows the markup generated from - * the `html.focus` option. - * - * @name focus - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFocus.events.focus - */ - - /** - * Focus plugin reacts to the `blur` event and hides the effect. - * - * @name blur - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFocus.events.blur - */ - - DEFAULT_OPTS = { - html : { - focus : '
' - } - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtFocus.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtFocus.init - */ - p.init = function(core) - { - var self = this; - - self.baseInit(core, DEFAULT_OPTS); - self.core().wrapElement().append(self.opts(OPT_HTML_FOCUS)); - self.on({ - blur : self.onBlur, - focus : self.onFocus - }); - - self._timeoutId = 0; - }; - - //-------------------------------------------------------------------------------- - // Event handlers - - /** - * Reacts to the `blur` event and hides the focus effect with a slight delay which - * allows quick refocusing without effect blinking in and out. - * - * @signature TextExtFocus.onBlur(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtFocus.onBlur - */ - p.onBlur = function(e) - { - var self = this; - - clearTimeout(self._timeoutId); - - self._timeoutId = setTimeout(function() - { - self.getFocus().hide(); - }, - 100); - }; - - /** - * Reacts to the `focus` event and shows the focus effect. - * - * @signature TextExtFocus.onFocus - * - * @param e {Object} jQuery event. - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtFocus.onFocus - */ - p.onFocus = function(e) - { - var self = this; - - clearTimeout(self._timeoutId); - - self.getFocus().show(); - }; - - //-------------------------------------------------------------------------------- - // Core functionality - - /** - * Returns focus effect HTML element. - * - * @signature TextExtFocus.getFocus() - * - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtFocus.getFocus - */ - p.getFocus = function() - { - return this.core().wrapElement().find('.text-focus'); - }; -})(jQuery); -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * Prompt plugin displays a visual user propmpt in the text input area. If user focuses - * on the input, the propt is hidden and only shown again when user focuses on another - * element and text input doesn't have a value. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt - */ - function TextExtPrompt() {}; - - $.fn.textext.TextExtPrompt = TextExtPrompt; - $.fn.textext.addPlugin('prompt', TextExtPrompt); - - var p = TextExtPrompt.prototype, - - CSS_HIDE_PROMPT = 'text-hide-prompt', - - /** - * Prompt plugin has options to change the prompt label and its HTML template. The options - * could be changed when passed to the `$().textext()` function. For example: - * - * $('textarea').textext({ - * plugins: 'prompt', - * prompt: 'Your email address' - * }) - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt.options - */ - - /** - * Prompt message that is displayed to the user whenever there's no value in the input. - * - * @name prompt - * @default 'Awaiting input...' - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt.options.prompt - */ - OPT_PROMPT = 'prompt', - - /** - * HTML source that is used to generate markup required for the prompt effect. - * - * @name html.prompt - * @default '
' - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt.options.html.prompt - */ - OPT_HTML_PROMPT = 'html.prompt', - - /** - * Prompt plugin dispatches or reacts to the following events. - * @id TextExtPrompt.events - */ - - /** - * Prompt plugin reacts to the `focus` event and hides the markup generated from - * the `html.prompt` option. - * - * @name focus - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt.events.focus - */ - - /** - * Prompt plugin reacts to the `blur` event and shows the prompt back if user - * hasn't entered any value. - * - * @name blur - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt.events.blur - */ - - DEFAULT_OPTS = { - prompt : 'Awaiting input...', - - html : { - prompt : '
' - } - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtPrompt.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt.init - */ - p.init = function(core) - { - var self = this, - placeholderKey = 'placeholder', - container, - prompt - ; - - self.baseInit(core, DEFAULT_OPTS); - - container = $(self.opts(OPT_HTML_PROMPT)); - $(self).data('container', container); - - self.core().wrapElement().append(container); - self.setPrompt(self.opts(OPT_PROMPT)); - - prompt = core.input().attr(placeholderKey); - - if(!prompt) - prompt = self.opts(OPT_PROMPT); - - // clear placeholder attribute if set - core.input().attr(placeholderKey, ''); - - if(prompt) - self.setPrompt(prompt); - - if($.trim(self.val()).length > 0) - self.hidePrompt(); - - self.on({ - blur : self.onBlur, - focus : self.onFocus, - postInvalidate : self.onPostInvalidate, - postInit : self.onPostInit - }); - }; - - //-------------------------------------------------------------------------------- - // Event handlers - - /** - * Reacts to the `postInit` and configures the plugin for initial display. - * - * @signature TextExtPrompt.onPostInit(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/24 - * @id TextExtPrompt.onPostInit - */ - p.onPostInit = function(e) - { - this.invalidateBounds(); - }; - - /** - * Reacts to the `postInvalidate` and insures that prompt display remains correct. - * - * @signature TextExtPrompt.onPostInvalidate(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/24 - * @id TextExtPrompt.onPostInvalidate - */ - p.onPostInvalidate = function(e) - { - this.invalidateBounds(); - }; - - /** - * Repositions the prompt to make sure it's always at the same place as in the text input carret. - * - * @signature TextExtPrompt.invalidateBounds() - * - * @author agorbatchev - * @date 2011/08/24 - * @id TextExtPrompt.invalidateBounds - */ - p.invalidateBounds = function() - { - var self = this, - input = self.input() - ; - - self.containerElement().css({ - paddingLeft : input.css('paddingLeft'), - paddingTop : input.css('paddingTop') - }); - }; - - /** - * Reacts to the `blur` event and shows the prompt effect with a slight delay which - * allows quick refocusing without effect blinking in and out. - * - * The prompt is restored if the text box has no value. - * - * @signature TextExtPrompt.onBlur(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtPrompt.onBlur - */ - p.onBlur = function(e) - { - var self = this; - - self.startTimer('prompt', 0.1, function() - { - self.showPrompt(); - }); - }; - - /** - * Shows prompt HTML element. - * - * @signature TextExtPrompt.showPrompt() - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtPrompt.showPrompt - */ - p.showPrompt = function() - { - var self = this, - input = self.input() - ; - - if($.trim(self.val()).length === 0 && !input.is(':focus')) - self.containerElement().removeClass(CSS_HIDE_PROMPT); - }; - - /** - * Hides prompt HTML element. - * - * @signature TextExtPrompt.hidePrompt() - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtPrompt.hidePrompt - */ - p.hidePrompt = function() - { - this.stopTimer('prompt'); - this.containerElement().addClass(CSS_HIDE_PROMPT); - }; - - /** - * Reacts to the `focus` event and hides the prompt effect. - * - * @signature TextExtPrompt.onFocus - * - * @param e {Object} jQuery event. - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtPrompt.onFocus - */ - p.onFocus = function(e) - { - this.hidePrompt(); - }; - - //-------------------------------------------------------------------------------- - // Core functionality - - /** - * Sets the prompt display to the specified string. - * - * @signature TextExtPrompt.setPrompt(str) - * - * @oaram str {String} String that will be displayed in the prompt. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtPrompt.setPrompt - */ - p.setPrompt = function(str) - { - this.containerElement().text(str); - }; - - /** - * Returns prompt effect HTML element. - * - * @signature TextExtPrompt.containerElement() - * - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtPrompt.containerElement - */ - p.containerElement = function() - { - return $(this).data('container'); - }; -})(jQuery); -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * Suggestions plugin allows to easily specify the list of suggestion items that the - * Autocomplete plugin would present to the user. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtSuggestions - */ - function TextExtSuggestions() {}; - - $.fn.textext.TextExtSuggestions = TextExtSuggestions; - $.fn.textext.addPlugin('suggestions', TextExtSuggestions); - - var p = TextExtSuggestions.prototype, - /** - * Suggestions plugin only has one option and that is to set suggestion items. It could be - * changed when passed to the `$().textext()` function. For example: - * - * $('textarea').textext({ - * plugins: 'suggestions', - * suggestions: [ "item1", "item2" ] - * }) - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtSuggestions.options - */ - - /** - * List of items that Autocomplete plugin would display in the dropdown. - * - * @name suggestions - * @default null - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtSuggestions.options.suggestions - */ - OPT_SUGGESTIONS = 'suggestions', - - /** - * Suggestions plugin dispatches or reacts to the following events. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtSuggestions.events - */ - - /** - * Suggestions plugin reacts to the `getSuggestions` event and returns `suggestions` items - * from the options. - * - * @name getSuggestions - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtSuggestions.events.getSuggestions - */ - - /** - * Suggestions plugin triggers the `setSuggestions` event to pass its own list of `Suggestions` - * to the Autocomplete plugin. - * - * @name setSuggestions - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtSuggestions.events.setSuggestions - */ - - /** - * Suggestions plugin reacts to the `postInit` event to pass its list of `suggestions` to the - * Autocomplete right away. - * - * @name postInit - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtSuggestions.events.postInit - */ - - DEFAULT_OPTS = { - suggestions : null - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtSuggestions.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/18 - * @id TextExtSuggestions.init - */ - p.init = function(core) - { - var self = this; - - self.baseInit(core, DEFAULT_OPTS); - - self.on({ - getSuggestions : self.onGetSuggestions, - postInit : self.onPostInit - }); - }; - - /** - * Triggers `setSuggestions` and passes supplied suggestions to the Autocomplete plugin. - * - * @signature TextExtSuggestions.setSuggestions(suggestions, showHideDropdown) - * - * @param suggestions {Array} List of suggestions. With the default `ItemManager` it should - * be a list of strings. - * @param showHideDropdown {Boolean} If it's undesirable to show the dropdown right after - * suggestions are set, `false` should be passed for this argument. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtSuggestions.setSuggestions - */ - p.setSuggestions = function(suggestions, showHideDropdown) - { - this.trigger('setSuggestions', { result : suggestions, showHideDropdown : showHideDropdown != false }); - }; - - /** - * Reacts to the `postInit` event and triggers `setSuggestions` event to set suggestions list - * right after initialization. - * - * @signature TextExtSuggestions.onPostInit(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtSuggestions.onPostInit - */ - p.onPostInit = function(e) - { - var self = this; - self.setSuggestions(self.opts(OPT_SUGGESTIONS), false); - }; - - /** - * Reacts to the `getSuggestions` event and triggers `setSuggestions` event with the list - * of `suggestions` specified in the options. - * - * @signature TextExtSuggestions.onGetSuggestions(e, data) - * - * @param e {Object} jQuery event. - * @param data {Object} Payload from the `getSuggestions` event with the user query, eg `{ query: {String} }`. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtSuggestions.onGetSuggestions - */ - p.onGetSuggestions = function(e, data) - { - var self = this, - suggestions = self.opts(OPT_SUGGESTIONS) - ; - - suggestions.sort(); - self.setSuggestions(self.itemManager().filter(suggestions, data.query)); - }; -})(jQuery); -;/** - * jQuery TextExt Plugin - * http://textextjs.com - * - * @version 1.3.0 - * @copyright Copyright (C) 2011 Alex Gorbatchev. All rights reserved. - * @license MIT License - */ -(function($) -{ - /** - * Tags plugin brings in the traditional tag functionality where user can assemble and - * edit list of tags. Tags plugin works especially well together with Autocomplete, Filter, - * Suggestions and Ajax plugins to provide full spectrum of features. It can also work on - * its own and just do one thing -- tags. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags - */ - function TextExtTags() {}; - - $.fn.textext.TextExtTags = TextExtTags; - $.fn.textext.addPlugin('tags', TextExtTags); - - var p = TextExtTags.prototype, - - CSS_DOT = '.', - CSS_TAGS_ON_TOP = 'text-tags-on-top', - CSS_DOT_TAGS_ON_TOP = CSS_DOT + CSS_TAGS_ON_TOP, - CSS_TAG = 'text-tag', - CSS_DOT_TAG = CSS_DOT + CSS_TAG, - CSS_TAGS = 'text-tags', - CSS_DOT_TAGS = CSS_DOT + CSS_TAGS, - CSS_LABEL = 'text-label', - CSS_DOT_LABEL = CSS_DOT + CSS_LABEL, - CSS_REMOVE = 'text-remove', - CSS_DOT_REMOVE = CSS_DOT + CSS_REMOVE, - - /** - * Tags plugin options are grouped under `tags` when passed to the - * `$().textext()` function. For example: - * - * $('textarea').textext({ - * plugins: 'tags', - * tags: { - * items: [ "tag1", "tag2" ] - * } - * }) - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.options - */ - - /** - * This is a toggle switch to enable or disable the Tags plugin. The value is checked - * each time at the top level which allows you to toggle this setting on the fly. - * - * @name tags.enabled - * @default true - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.options.tags.enabled - */ - OPT_ENABLED = 'tags.enabled', - - /** - * Allows to specify tags which will be added to the input by default upon initialization. - * Each item in the array must be of the type that current `ItemManager` can understand. - * Default type is `String`. - * - * @name tags.items - * @default null - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.options.tags.items - */ - OPT_ITEMS = 'tags.items', - - /** - * HTML source that is used to generate a single tag. - * - * @name html.tag - * @default '
' - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.options.html.tag - */ - OPT_HTML_TAG = 'html.tag', - - /** - * HTML source that is used to generate container for the tags. - * - * @name html.tags - * @default '
' - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.options.html.tags - */ - OPT_HTML_TAGS = 'html.tags', - - /** - * Tags plugin dispatches or reacts to the following events. - * - * @author agorbatchev - * @date 2011/08/17 - * @id TextExtTags.events - */ - - /** - * Tags plugin triggers the `isTagAllowed` event before adding each tag to the tag list. Other plugins have - * an opportunity to interrupt this by setting `result` of the second argument to `false`. For example: - * - * $('textarea').textext({...}).bind('isTagAllowed', function(e, data) - * { - * if(data.tag === 'foo') - * data.result = false; - * }) - * - * The second argument `data` has the following format: `{ tag : {Object}, result : {Boolean} }`. `tag` - * property is in the format that the current `ItemManager` can understand. - * - * @name isTagAllowed - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.events.isTagAllowed - */ - EVENT_IS_TAG_ALLOWED = 'isTagAllowed', - - /** - * Tags plugin triggers the `tagClick` event when user clicks on one of the tags. This allows to process - * the click and potentially change the value of the tag (for example in case of user feedback). - * - * $('textarea').textext({...}).bind('tagClick', function(e, tag, value, callback) - * { - * var newValue = window.prompt('New value', value); - - * if(newValue) - * callback(newValue, true); - * }) - * - * Callback argument has the following signature: - * - * function(newValue, refocus) - * { - * ... - * } - * - * Please check out [example](/manual/examples/tags-changing.html). - * - * @name tagClick - * @version 1.3.0 - * @author s.stok - * @date 2011/01/23 - * @id TextExtTags.events.tagClick - */ - EVENT_TAG_CLICK = 'tagClick', - - DEFAULT_OPTS = { - tags : { - enabled : true, - items : null - }, - - html : { - tags : '
', - tag : '
' - } - } - ; - - /** - * Initialization method called by the core during plugin instantiation. - * - * @signature TextExtTags.init(core) - * - * @param core {TextExt} Instance of the TextExt core class. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.init - */ - p.init = function(core) - { - this.baseInit(core, DEFAULT_OPTS); - - var self = this, - input = self.input(), - container - ; - - if(self.opts(OPT_ENABLED)) - { - container = $(self.opts(OPT_HTML_TAGS)); - input.after(container); - - $(self).data('container', container); - - self.on({ - enterKeyPress : self.onEnterKeyPress, - backspaceKeyDown : self.onBackspaceKeyDown, - preInvalidate : self.onPreInvalidate, - postInit : self.onPostInit, - getFormData : self.onGetFormData - }); - - self.on(container, { - click : self.onClick, - mousemove : self.onContainerMouseMove - }); - - self.on(input, { - mousemove : self.onInputMouseMove - }); - } - - self._originalPadding = { - left : parseInt(input.css('paddingLeft') || 0), - top : parseInt(input.css('paddingTop') || 0) - }; - - self._paddingBox = { - left : 0, - top : 0 - }; - - self.updateFormCache(); - }; - - /** - * Returns HTML element in which all tag HTML elements are residing. - * - * @signature TextExtTags.containerElement() - * - * @author agorbatchev - * @date 2011/08/15 - * @id TextExtTags.containerElement - */ - p.containerElement = function() - { - return $(this).data('container'); - }; - - //-------------------------------------------------------------------------------- - // Event handlers - - /** - * Reacts to the `postInit` event triggered by the core and sets default tags - * if any were specified. - * - * @signature TextExtTags.onPostInit(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/09 - * @id TextExtTags.onPostInit - */ - p.onPostInit = function(e) - { - var self = this; - self.addTags(self.opts(OPT_ITEMS)); - }; - - /** - * Reacts to the [`getFormData`][1] event triggered by the core. Returns data with the - * weight of 200 to be *greater than the Autocomplete plugin* data weight. The weights - * system is covered in greater detail in the [`getFormData`][1] event documentation. - * - * [1]: /manual/textext.html#getformdata - * - * @signature TextExtTags.onGetFormData(e, data, keyCode) - * - * @param e {Object} jQuery event. - * @param data {Object} Data object to be populated. - * @param keyCode {Number} Key code that triggered the original update request. - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtTags.onGetFormData - */ - p.onGetFormData = function(e, data, keyCode) - { - var self = this, - inputValue = keyCode === 13 ? '' : self.val(), - formValue = self._formData - ; - - data[200] = self.formDataObject(inputValue, formValue); - }; - - /** - * Returns initialization priority of the Tags plugin which is expected to be - * *less than the Autocomplete plugin* because of the dependencies. The value is - * 100. - * - * @signature TextExtTags.initPriority() - * - * @author agorbatchev - * @date 2011/08/22 - * @id TextExtTags.initPriority - */ - p.initPriority = function() - { - return 100; - }; - - /** - * Reacts to user moving mouse over the text area when cursor is over the text - * and not over the tags. Whenever mouse cursor is over the area covered by - * tags, the tags container is flipped to be on top of the text area which - * makes all tags functional with the mouse. - * - * @signature TextExtTags.onInputMouseMove(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtTags.onInputMouseMove - */ - p.onInputMouseMove = function(e) - { - this.toggleZIndex(e); - }; - - /** - * Reacts to user moving mouse over the tags. Whenever the cursor moves out - * of the tags and back into where the text input is happening visually, - * the tags container is sent back under the text area which allows user - * to interact with the text using mouse cursor as expected. - * - * @signature TextExtTags.onContainerMouseMove(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtTags.onContainerMouseMove - */ - p.onContainerMouseMove = function(e) - { - this.toggleZIndex(e); - }; - - /** - * Reacts to the `backspaceKeyDown` event. When backspace key is pressed in an empty text field, - * deletes last tag from the list. - * - * @signature TextExtTags.onBackspaceKeyDown(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/02 - * @id TextExtTags.onBackspaceKeyDown - */ - p.onBackspaceKeyDown = function(e) - { - var self = this, - lastTag = self.tagElements().last() - ; - - if(self.val().length == 0) - self.removeTag(lastTag); - }; - - /** - * Reacts to the `preInvalidate` event and updates the input box to look like the tags are - * positioned inside it. - * - * @signature TextExtTags.onPreInvalidate(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.onPreInvalidate - */ - p.onPreInvalidate = function(e) - { - var self = this, - lastTag = self.tagElements().last(), - pos = lastTag.position() - ; - - if(lastTag.length > 0) - pos.left += lastTag.innerWidth(); - else - pos = self._originalPadding; - - self._paddingBox = pos; - - self.input().css({ - paddingLeft : pos.left, - paddingTop : pos.top - }); - }; - - /** - * Reacts to the mouse `click` event. - * - * @signature TextExtTags.onClick(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.onClick - */ - p.onClick = function(e) - { - var self = this, - core = self.core(), - source = $(e.target), - focus = 0, - tag - ; - - if(source.is(CSS_DOT_TAGS)) - { - focus = 1; - } - else if(source.is(CSS_DOT_REMOVE)) - { - self.removeTag(source.parents(CSS_DOT_TAG + ':first')); - focus = 1; - } - else if(source.is(CSS_DOT_LABEL)) - { - tag = source.parents(CSS_DOT_TAG + ':first'); - self.trigger(EVENT_TAG_CLICK, tag, tag.data(CSS_TAG), tagClickCallback); - } - - function tagClickCallback(newValue, refocus) - { - tag.data(CSS_TAG, newValue); - tag.find(CSS_DOT_LABEL).text(self.itemManager().itemToString(newValue)); - - self.updateFormCache(); - core.getFormData(); - core.invalidateBounds(); - - if(refocus) - core.focusInput(); - } - - if(focus) - core.focusInput(); - }; - - /** - * Reacts to the `enterKeyPress` event and adds whatever is currently in the text input - * as a new tag. Triggers `isTagAllowed` to check if the tag could be added first. - * - * @signature TextExtTags.onEnterKeyPress(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.onEnterKeyPress - */ - p.onEnterKeyPress = function(e) - { - var self = this, - val = self.val(), - tag = self.itemManager().stringToItem(val) - ; - - if(self.isTagAllowed(tag)) - { - self.addTags([ tag ]); - // refocus the textarea just in case it lost the focus - self.core().focusInput(); - } - }; - - //-------------------------------------------------------------------------------- - // Core functionality - - /** - * Creates a cache object with all the tags currently added which will be returned - * in the `onGetFormData` handler. - * - * @signature TextExtTags.updateFormCache() - * - * @author agorbatchev - * @date 2011/08/09 - * @id TextExtTags.updateFormCache - */ - p.updateFormCache = function() - { - var self = this, - result = [] - ; - - self.tagElements().each(function() - { - result.push($(this).data(CSS_TAG)); - }); - - // cache the results to be used in the onGetFormData - self._formData = result; - }; - - /** - * Toggles tag container to be on top of the text area or under based on where - * the mouse cursor is located. When cursor is above the text input and out of - * any of the tags, the tags container is sent under the text area. If cursor - * is over any of the tags, the tag container is brought to be over the text - * area. - * - * @signature TextExtTags.toggleZIndex(e) - * - * @param e {Object} jQuery event. - * - * @author agorbatchev - * @date 2011/08/08 - * @id TextExtTags.toggleZIndex - */ - p.toggleZIndex = function(e) - { - var self = this, - offset = self.input().offset(), - mouseX = e.clientX - offset.left, - mouseY = e.clientY - offset.top, - box = self._paddingBox, - container = self.containerElement(), - isOnTop = container.is(CSS_DOT_TAGS_ON_TOP), - isMouseOverText = mouseX > box.left && mouseY > box.top - ; - - if(!isOnTop && !isMouseOverText || isOnTop && isMouseOverText) - container[(!isOnTop ? 'add' : 'remove') + 'Class'](CSS_TAGS_ON_TOP); - }; - - /** - * Returns all tag HTML elements. - * - * @signature TextExtTags.tagElements() - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.tagElements - */ - p.tagElements = function() - { - return this.containerElement().find(CSS_DOT_TAG); - }; - - /** - * Wrapper around the `isTagAllowed` event which triggers it and returns `true` - * if `result` property of the second argument remains `true`. - * - * @signature TextExtTags.isTagAllowed(tag) - * - * @param tag {Object} Tag object that the current `ItemManager` can understand. - * Default is `String`. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.isTagAllowed - */ - p.isTagAllowed = function(tag) - { - var opts = { tag : tag, result : true }; - this.trigger(EVENT_IS_TAG_ALLOWED, opts); - return opts.result === true; - }; - - /** - * Adds specified tags to the tag list. Triggers `isTagAllowed` event for each tag - * to insure that it could be added. Calls `TextExt.getFormData()` to refresh the data. - * - * @signature TextExtTags.addTags(tags) - * - * @param tags {Array} List of tags that current `ItemManager` can understand. Default - * is `String`. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.addTags - */ - p.addTags = function(tags) - { - if(!tags || tags.length == 0) - return; - - var self = this, - core = self.core(), - container = self.containerElement(), - i, tag - ; - - for(i = 0; i < tags.length; i++) - { - tag = tags[i]; - - if(tag && self.isTagAllowed(tag)) - container.append(self.renderTag(tag)); - } - - self.updateFormCache(); - core.getFormData(); - core.invalidateBounds(); - }; - - /** - * Returns HTML element for the specified tag. - * - * @signature TextExtTags.getTagElement(tag) - * - * @param tag {Object} Tag object in the format that current `ItemManager` can understand. - * Default is `String`. - - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.getTagElement - */ - p.getTagElement = function(tag) - { - var self = this, - list = self.tagElements(), - i, item - ; - - for(i = 0; i < list.length, item = $(list[i]); i++) - if(self.itemManager().compareItems(item.data(CSS_TAG), tag)) - return item; - }; - - /** - * Removes specified tag from the list. Calls `TextExt.getFormData()` to refresh the data. - * - * @signature TextExtTags.removeTag(tag) - * - * @param tag {Object} Tag object in the format that current `ItemManager` can understand. - * Default is `String`. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.removeTag - */ - p.removeTag = function(tag) - { - var self = this, - core = self.core(), - element - ; - - if(tag instanceof $) - { - element = tag; - tag = tag.data(CSS_TAG); - } - else - { - element = self.getTagElement(tag); - } - - element.remove(); - self.updateFormCache(); - core.getFormData(); - core.invalidateBounds(); - }; - - /** - * Creates and returns new HTML element from the source code specified in the `html.tag` option. - * - * @signature TextExtTags.renderTag(tag) - * - * @param tag {Object} Tag object in the format that current `ItemManager` can understand. - * Default is `String`. - * - * @author agorbatchev - * @date 2011/08/19 - * @id TextExtTags.renderTag - */ - p.renderTag = function(tag) - { - var self = this, - node = $(self.opts(OPT_HTML_TAG)) - ; - - node.find('.text-label').text(self.itemManager().itemToString(tag)); - node.data(CSS_TAG, tag); - return node; - }; -})(jQuery); diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 282d259d973..2813acd5933 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -75,9 +75,6 @@ - - - diff --git a/addons/website_forum/views/website_forum.xml b/addons/website_forum/views/website_forum.xml index f03ceac4865..1f78a069988 100644 --- a/addons/website_forum/views/website_forum.xml +++ b/addons/website_forum/views/website_forum.xml @@ -12,12 +12,10 @@