- 浏览: 54040 次
最新评论
懒了, 只翻译几个目前用到的属性,其实英文写的很明白的,需要花时间看而已。
注意, 标记overridable的方法都是可以重写的,如何重写见 “aui-autocomplete [ 一 ]”
注意, 标记overridable的方法都是可以重写的,如何重写见 “aui-autocomplete [ 一 ]”
AUI.add('aui-autocomplete', function(A) { /** * The AutoComplete Utility * * @module aui-autocomplete */ var Lang = A.Lang, isArray = Lang.isArray, isString = Lang.isString, isNull = Lang.isNull, isFunction = Lang.isFunction, getClassName = A.ClassNameManager.getClassName, ALERT = 'alert', CONTENT = 'content', HELPER = 'helper', HIDDEN = 'hidden', ICON = 'icon', ITEM = 'item', LIST = 'list', LOADING = 'loading', NAME = 'autocomplete', RESET = 'reset', RESULTS = 'results', SELECTED = 'selected', ICON_DEFAULT = 'circle-triangle-b', ICON_ERROR = ALERT, ICON_LOADING = LOADING, CSS_HIGLIGHT = getClassName(NAME, SELECTED), CSS_HIDDEN = getClassName(HELPER, HIDDEN), CSS_LIST_ITEM = getClassName(NAME, LIST, ITEM), CSS_RESULTS_LIST = getClassName(HELPER, RESET), CSS_RESULTS_OVERLAY = getClassName(NAME, RESULTS), CSS_RESULTS_OVERLAY_CONTENT = getClassName(NAME, RESULTS, CONTENT), KEY_BACKSPACE = 8, KEY_TAB = 9, KEY_ENTER = 13, KEY_SHIFT = 16, KEY_CTRL = 17, KEY_ALT = 18, KEY_CAPS_LOCK = 20, KEY_ESC = 27, KEY_PAGEUP = 33, KEY_END = 35, KEY_HOME = 36, KEY_UP = 38, KEY_DOWN = 40, KEY_RIGHT = 39, KEY_LEFT = 37, KEY_PRINT_SCREEN = 44, KEY_INSERT = 44, KEY_KOREAN_IME = 229, OVERLAY_ALIGN = { node: null, points: ['tl', 'bl'] }, BOUNDING_BOX = 'boundingBox', CONTENT_BOX = 'contentBox'; /** * <p><img src="assets/images/aui-autocomplete/main.png"/></p> * * A base class for AutoComplete, providing: * <ul> * <li>Widget Lifecycle (initializer, renderUI, bindUI, syncUI, destructor)</li> * <li>Presenting users choices based on their input</li> * <li>Separating selected items</li> * <li>Keyboard interaction for selecting items</li> * </ul> * * Quick Example:<br/> * * <pre><code>var instance = new A.AutoComplete({ * dataSource: [['AL', 'Alabama', 'The Heart of Dixie'], * ['AK', 'Alaska', 'The Land of the Midnight Sun'], * ['AZ', 'Arizona', 'The Grand Canyon State']], * schema: { * resultFields: ['key', 'name', 'description'] * }, * matchKey: 'name', * delimChar: ',', * typeAhead: true, * contentBox: '#myAutoComplete' * }).render(); * </code></pre> * * Check the list of <a href="AutoComplete.html#configattributes">Configuration Attributes</a> available for * AutoComplete. * * @param config {Object} Object literal specifying widget configuration properties. * * @class AutoComplete * @constructor * @extends Component */ var AutoComplete = A.Component.create( { /** * Static property provides a string to identify the class. * * @property AutoComplete.NAME * @type String * @static */ NAME: NAME, /** * Static property used to define the default attribute * configuration for the AutoComplete. * * @property AutoComplete.ATTRS * @type Object * @static */ ATTRS: { /** * Always show the results container, instead of only showing when the * user is requesting them. * * @attribute alwaysShowContainer * @default false * @type Boolean */ alwaysShowContainer: { value: false }, /** * 结果集显示时高亮第一个item * Automatically highlight the first item in the list when the results are * made visible. * * @attribute autoHighlight * @default true * @type Boolean */ autoHighlight: { value: true }, /** * If set to true, the <a href="AutoComplete.html#method_filterResults">filterResults</a> * method will be run on the response from the data source. * * @attribute applyLocalFilter * @default true * @type Boolean */ applyLocalFilter: { value: null }, /** * To use a button 是否需要右侧的button * * @attribute button * @default true * @type Boolean * @deprecated */ button: { value: true }, /** * The data source that results will be read from. This can either be * an existing <a href="DataSource.html">DataSource</a> object, or it can be a * value that would be passed to <a href="DataSource.html">DataSource</a>. * * @attribute dataSource * @default null * @type Object | String | Function | Array */ dataSource: { value: null }, /** * The type of the data source passed into <a href="AutoComplete.html#config_dataSource">dataSource</a>. * This can be used to explicitly declare what kind of <a href="DataSource.html">DataSource</a> object will * be created. * * @attribute dataSourceType * @default null * @type String */ dataSourceType: { value: null }, /** * 不设置,单选; 设置此项可多选,input框中多个选中值用delimChar分隔,如aa,bb,cc * The character used to indicate the beginning or ending of a new value. Most commonly used * is a ",". * * @attribute delimChar * @default null * @type String */ delimChar: { value: null, setter: function(value) { if (isString(value) && (value.length > 0)) { value = [value]; } else if (!isArray(value)) { value = A.Attribute.INVALID_VALUE; } return value; } }, /** * The input field which will recieve the users input. * * @attribute input * @default null * @type String | Node */ input: { value: null }, /** * 用schema中的哪一项匹配输入值, input默认显示选中项的matchKey字段 * The key or numeric index in the schema to match the result against. * * @attribute matchKey * @default 0 * @type String | Number */ matchKey: { value: 0 }, /** * The maximum number of results to display. 结果集最大条数 * * * @attribute maxResultsDisplayed * @default 10 * @type Number */ maxResultsDisplayed: { value: 10 }, /** * The minimum number of characters required to query the data source. 最少要输入多少个字符才会显示匹配结果集合 * * @attribute minQueryLength * @default 1 * @type Number */ minQueryLength: { value: 1 }, /** * The amount of time in seconds to delay before submitting the query. * * @attribute queryDelay * @default 0.2 * @type Number */ queryDelay: { value: 0.2, getter: function(value) { return value * 1000; } }, /** * When IME usage is detected or interval detection is explicitly enabled, * AutoComplete will detect the input value at the given interval and send a * query if the value has changed. * * @attribute queryInterval * @default 0.5 * @type Number */ queryInterval: { value: 0.5, getter: function(value) { return value * 1000; } }, /** * 匹配结果集时是否大小写敏感 * When <a href="AutoComplete.html#config_applyLocalFilter">applyLocalFilter</a> is true, * setting this to true will match only results with the same case. * * @attribute queryMatchCase * @default false * @type Boolean */ queryMatchCase: { value: false }, /** * false,从第一个字符开始匹配; true, 结果集中的item, 任意位置的字符与输入字符相同即匹配。 * When <a href="AutoComplete.html#config_applyLocalFilter">applyLocalFilter</a> is true, * setting this to true will match results which contain the query anywhere in the text, * instead of just matching just items that start with the query. * * @attribute queryMatchContains * @default false * @type Boolean */ queryMatchContains: { value: false }, /** * For IO DataSources, AutoComplete will automatically insert a "?" between the server URI and * the encoded query string. To prevent this behavior, you can * set this value to false. If you need to customize this even further, you * can override the <a href="AutoComplete.html#method_generateRequest">generateRequest</a> method. * * @attribute queryQuestionMark * @default true * @type Boolean */ queryQuestionMark: { value: true }, /** * A valid configuration object for any of <a href="module_datasource.html">DataSource</a> schema plugins. * * @attribute schema * @default null * @type Object */ schema: { value: null }, /** * A valid type of <a href="module_datasource.html">DataSource</a> schema plugin, such as array, json, xml, etc. * * @attribute schemaType * @default array * @type String */ schemaType: { value: '', validator: isString }, /** * Whether or not the input field should be updated with selections. * * @attribute suppressInputUpdate * @default false * @type Boolean */ suppressInputUpdate: { value: false }, /** * autoHighlight = true时有效 * true, 自动选中第一个匹配结果,即使用户未输入完整, 同时更新值到input框中。 * If <a href="AutoComplete.html#config_autoHighlight">autoHighlight</a> is enabled, whether or not the * input field should be automatically updated with the first result as the user types, * automatically selecting the portion of the text the user has not typed yet. * * @attribute typeAhead * @default false * @type Boolean */ typeAhead: { value: false }, /** * If <a href="AutoComplete.html#config_typeAhead">typeAhead</a> is true, number of seconds * to delay before updating the input. In order to prevent certain race conditions, this value must * always be greater than the <a href="AutoComplete.html#config_queryDelay">queryDelay</a>. * * @attribute typeAheadDelay * @default 0.2 * @type Number */ typeAheadDelay: { value: 0.2, getter: function(value) { return value * 1000; } }, /** * 还没研究出来怎么用 * The unique ID of the input element. * * @attribute uniqueName * @default null * @type String */ uniqueName: { value: null } }, prototype: { /** * Construction logic executed during AutoComplete instantiation. Lifecycle. * * @method initializer * @protected */ initializer: function(config) { var instance = this; instance._overlayAlign = A.mix({}, OVERLAY_ALIGN); instance._createDataSource(); }, /** * Create the DOM structure for the AutoComplete. Lifecycle. * * @method renderUI * @protected */ renderUI: function() { var instance = this; instance._renderInput(); instance._renderOverlay(); }, /** * Bind the events on the AutoComplete UI. Lifecycle. * * @method bindUI * @protected */ bindUI: function() { var instance = this; var button = instance.button; var inputNode = instance.inputNode; instance.dataSource.on('request', A.bind(button.set, button, ICON, ICON_LOADING)); inputNode.on('blur', instance._onTextboxBlur, instance); inputNode.on('focus', instance._onTextboxFocus, instance); inputNode.on('keydown', instance._onTextboxKeyDown, instance); inputNode.on('keypress', instance._onTextboxKeyPress, instance); inputNode.on('keyup', instance._onTextboxKeyUp, instance); var overlayBoundingBox = instance.overlay.get(BOUNDING_BOX); overlayBoundingBox.on('click', instance._onContainerClick, instance); overlayBoundingBox.on('mouseout', instance._onContainerMouseout, instance); overlayBoundingBox.on('mouseover', instance._onContainerMouseover, instance); overlayBoundingBox.on('scroll', instance._onContainerScroll, instance); /** * Handles the containerCollapse event. Fired when the container is hidden. * * @event containerCollapse * @param {Event.Facade} event The containerCollapse event. */ instance.publish('containerCollapse'); /** * Handles the containerExpand event. Fired when the container is shown. * * @event containerExpand * @param {Event.Facade} event The containerExpand event. */ instance.publish('containerExpand'); /** * Handles the containerPopulate event. Fired when the container is populated. * * @event containerPopulate * @param {Event.Facade} event The containerPopulate event. */ instance.publish('containerPopulate'); /** * Handles the dataError event. Fired when there is an error accessing the data. * * @event dataError * @param {Event.Facade} event The dataError event. */ instance.publish('dataError'); /** * Handles the dataRequest event. Fired when ever a query is sent to the data source. * * @event dataRequest * @param {Event.Facade} event The dataRequest event. */ instance.publish('dataRequest'); /** * Handles the dataReturn event. Fired when data successfully comes back from the data request. * * @event dataReturn * @param {Event.Facade} event The dataReturn event. */ instance.publish('dataReturn'); /** * Handles the itemArrowFrom event. Fired when the user navigates via the keyboard away from * a selected item. * * @event itemArrowFrom * @param {Event.Facade} event The itemArrowFrom event. */ instance.publish('itemArrowFrom'); /** * Handles the itemArrowTo event. Fired when the user navigates via the keyboard to a selected item. * * @event itemArrowTo * @param {Event.Facade} event The itemArrowTo event. */ instance.publish('itemArrowTo'); /** * Handles the itemMouseOut event. Fired when the user mouses away from an item. * * @event itemMouseOut * @param {Event.Facade} event The itemMouseOut event. */ instance.publish('itemMouseOut'); /** * Handles the itemMouseOver event. Fired when the user mouses over an item. * * @event itemMouseOver * @param {Event.Facade} event The itemMouseOver event. */ instance.publish('itemMouseOver'); /** * Handles the itemSelect event. Fired when an item in the list is selected. * * @event itemSelect * @param {Event.Facade} event The itemSelect event. */ instance.publish('itemSelect'); /** * Handles the selectionEnforce event. Fired if <a href="Autocomplete.html#config_forceSelection">forceSelection</a> * is enabled and the users input element has been cleared because it did not match one of the results. * * @event selectionEnforce * @param {Event.Facade} event The selectionEnforce event. */ instance.publish('selectionEnforce'); /** * Handles the textboxBlur event. Fired when the user leaves the input element. * * @event textboxBlur * @param {Event.Facade} event The textboxBlur event. */ instance.publish('textboxBlur'); /** * Handles the textboxChange event. Fired when the value in the input element is changed. * * @event textboxChange * @param {Event.Facade} event The textboxChange event. */ instance.publish('textboxChange'); /** * Handles the textboxFocus event. Fired when user moves focus to the input element. * * @event textboxFocus * @param {Event.Facade} event The textboxFocus event. */ instance.publish('textboxFocus'); /** * Handles the textboxKey event. Fired when the input element receives key input. * * @event textboxKey * @param {Event.Facade} event The textboxKey event. */ instance.publish('textboxKey'); /** * Handles the typeAhead event. Fired when the input element has been pre-filled by the type-ahead feature. * * @event typeAhead * @param {Event.Facade} event The typeAhead event. */ instance.publish('typeAhead'); /** * Handles the unmatchedItemSelect event. Fired when a user selects something that does * not match any of the displayed results. * * @event unmatchedItemSelect * @param {Event.Facade} event The unmatchedItemSelect event. */ instance.publish('unmatchedItemSelect'); instance.overlay.after('visibleChange', instance._realignContainer, instance); }, /** * Sync the AutoComplete UI. Lifecycle. * * @method syncUI * @protected */ syncUI: function() { var instance = this; instance.inputNode.setAttribute('autocomplete', 'off'); }, /** * An overridable method that is executed before the result container is shown. * The method can return false to prevent the container from being shown. * * @method doBeforeExpandContainer * @param {String} query The query that was submitted to the data source * @param {Object} allResults The parsed results * @return {Boolean} */ doBeforeExpandContainer: function() { return true; }, /** * An overridable method that is executed before the result overlay is loaded with results. * * @method doBeforeLoadData * @param {EventFacade} event * @return {Boolean} */ doBeforeLoadData: function(event) { return true; }, /** * Executed by the data source as a mechanism to do simple client-side * filtering of the results. * * @method filterResults * @param {EventFacade} event * @return {Object} Filtered response object */ filterResults: function(event) { var instance = this; var callback = event.callback; var query = event.request; var response = event.response; if (callback && callback.argument && callback.argument.query) { query = callback.argument.query; } if (query) { var dataSource = instance.dataSource; var allResults = response.results; var filteredResults = []; var matchFound = false; var matchKey = instance.get('matchKey'); var matchCase = instance.get('queryMatchCase'); var matchContains = instance.get('queryMatchContains'); var showAll = (query == '*'); var fields = instance.get('schema.resultFields'); for (var i = allResults.length - 1; i >= 0; i--){ var result = allResults[i]; var strResult = null; if (isString(result)) { strResult = result; } else if (isArray(result)) { strResult = result[0]; } else if (fields) { strResult = result[matchKey || fields[0]]; } if (isString(strResult)) { var keyIndex = -1; if (matchCase) { keyIndex = strResult.indexOf(decodeURIComponent(query)); } else { keyIndex = strResult.toLowerCase().indexOf(decodeURIComponent(query).toLowerCase()); } if ( (showAll) || (!matchContains && (keyIndex === 0)) || (matchContains && (keyIndex > -1) ) ) { filteredResults.unshift(result); } } } response.results = filteredResults; } return response; }, /** * An overridable method for formatting the result of the query before it's displayed in the overlay. * * @method formatResult * @param {Object} result The result data object * @param {String} request The current query string * @param {String} resultMatch The string from the results that matches the query * @return {String} */ formatResult: function(result, request, resultMatch) { return resultMatch || ''; }, /** * An overridable method that creates an object to be passed to the sendRequest * method of the data source object. Useful to overwrite if you wish to create * a custom request object before it's sent. * * @method generateRequest * @param {String} query The string currently being entered * @return {Object} */ generateRequest: function(query) { return { request: query }; }, /** * Handles the response for the display of the results. This is a callback method * that is fired by the sendRequest method so that results are ready to be accessed. * * @method handleResponse * @param {EventFacade} event */ handleResponse: function(event) { var instance = this; instance._populateList(event); var iconClass = ICON_DEFAULT; if (event.error) { iconClass = ICON_ERROR; } instance.button.set(ICON, iconClass); }, /** * Sends a query request to the data source object. * * @method sendQuery * @param {String} query Query string */ sendQuery: function(query) { var instance = this; instance.set('focused', null); var newQuery = query; if (instance.get('delimChar')) { query = instance.inputNode.get('value') + query; } instance._sendQuery(newQuery); }, /** * Clears the query interval * * @method _clearInterval * @private */ _clearInterval: function() { var instance = this; if (instance._queryIntervalId) { clearInterval(instance._queryIntervalId); instance._queryIntervalId = null; } }, /** * When <a href="Autocomplete.html#config_forceSelection">forceSelection</a> is true and * the user tries to leave the input element without selecting an item from the results, * the user selection is cleared. * * @method _clearSelection * @protected */ _clearSelection: function() { var instance = this; var delimChar = instance.get('delimChar'); var extraction = { previous: '', query: instance.inputNode.get('value') }; if (delimChar) { extraction = instance._extractQuery(instance.inputNode.get('value')); } instance.fire('selectionEnforce', extraction.query); }, /** * Creates the data source object using the passed in <a href="Autocomplete.html#config_dataSource">dataSource</a>, * and if it is a string, will use the <a href="Autocomplete.html#config_dataSourceType">dataSourceType</a> to * create a new <a href="module_datasource.html">DataSource</a> object. * * @method _createDataSource * @protected * @return {String} */ _createDataSource: function() { var instance = this; instance._queryTask = new A.DelayedTask(instance.sendQuery, instance); var dataSource = instance.get('dataSource'); var data = dataSource; var dataSourceType = instance.get('dataSourceType'); if (!(dataSource instanceof A.DataSource.Local)) { if (!dataSourceType) { dataSourceType = 'Local'; if (isFunction(data)) { dataSourceType = 'Function'; } else if (isString(data)) { dataSourceType = 'IO'; } } dataSource = new A.DataSource[dataSourceType]( { source: data } ); } dataSource.on('error', instance.handleResponse, instance); dataSource.after('response', instance.handleResponse, instance); dataSourceType = dataSource.name; if (dataSourceType == 'dataSourceLocal') { instance.set('applyLocalFilter', true); } instance.set('dataSource', dataSource); instance.set('dataSource', dataSourceType); instance.dataSource = dataSource; var schema = instance.get('schema'); if (schema) { if (schema.fn) { instance.dataSource.plug(schema); } else { var schemaType = instance.get('schemaType'); var schemaTypes = { array: A.Plugin.DataSourceArraySchema, json: A.Plugin.DataSourceJSONSchema, text: A.Plugin.DataSourceTextSchema, xml: A.Plugin.DataSourceXMLSchema }; schemaType = schemaType.toLowerCase() || 'array'; instance.dataSource.plug( { fn: schemaTypes[schemaType], cfg: { schema: schema } } ); } } instance.set('schema', schema); }, /** * Enables query interval detection for IME support. * * @method _enableIntervalDetection * @protected */ _enableIntervalDetection: function() { var instance = this; var queryInterval = instance.get('queryInterval'); if (!instance._queryIntervalId && queryInterval) { instance._queryInterval = setInterval(A.bind(instance._onInterval, instance), queryInterval); } }, /** * Extracts the right most query from the delimited string in the input. * * @method _extractQuery * @param {String} query String to parse * @protected * @return {String} */ _extractQuery: function(query) { var instance = this; var delimChar = instance.get('delimChar'); var delimIndex = -1; var i = delimChar.length - 1; var newIndex, queryStart, previous; for (; i >= 0; i--) { newIndex = query.lastIndexOf(delimChar[i]); if (newIndex > delimIndex) { delimIndex = newIndex; } } if (delimChar[i] == ' ') { for (var j = delimChar.length - 1; j >= 0; j--){ if (query[delimIndex - 1] == delimChar[j]) { delimIndex--; break; } } } if (delimIndex > -1) { queryStart = delimIndex + 1; while (query.charAt(queryStart) == ' ') { queryStart += 1; } previous = query.substring(0, queryStart); query = query.substring(queryStart); } else { previous = ''; } return { previous: previous, query: query }; }, /** * Focuses the input element. * * @method _focus * @protected */ _focus: function() { var instance = this; setTimeout( function() { instance.inputNode.focus(); }, 0 ); }, /** * Whether or not the pressed key triggers some functionality or if it should * be ignored. * * @method _isIgnoreKey * @param {keyCode} Number The numeric code of the key pressed * @protected * @return {String} */ _isIgnoreKey: function(keyCode) { var instance = this; if ( (keyCode == KEY_TAB) || (keyCode == KEY_ENTER) || (keyCode == KEY_SHIFT) || (keyCode == KEY_CTRL) || (keyCode >= KEY_ALT && keyCode <= KEY_CAPS_LOCK) || (keyCode == KEY_ESC) || (keyCode >= KEY_PAGEUP && keyCode <= KEY_END) || (keyCode >= KEY_HOME && keyCode <= KEY_DOWN) || (keyCode >= KEY_PRINT_SCREEN && keyCode <= KEY_INSERT) || (keyCode == KEY_KOREAN_IME) ) { return true; } return false; }, /** * If there is a currently selected item, the right arrow key will select * that item and jump to the end of the input element, otherwise the container is closed. * * @method _jumpSelection * @protected */ _jumpSelection: function() { var instance = this; if (instance._elCurListItem) { instance._selectItem(instance._elCurListItem); } else { instance._toggleContainer(false); } }, /** * Triggered by the up and down arrow keys, changes the currently selected list element item, and scrolls the * container if necessary. * * @method _moveSelection * @param {Number} keyCode The numeric code of the key pressed * @protected */ _moveSelection: function(keyCode) { var instance = this; if (instance.overlay.get('visible')) { var elCurListItem = instance._elCurListItem; var curItemIndex = -1; if (elCurListItem) { curItemIndex = Number(elCurListItem.getAttribute('data-listItemIndex')); } var newItemIndex = curItemIndex - 1; if (keyCode == KEY_DOWN) { newItemIndex = curItemIndex + 1; } if (newItemIndex == -1) { newItemIndex = instance._displayedItems - 1; } if (newItemIndex >= instance._displayedItems) { newItemIndex = 0; } if (newItemIndex < -2) { return; } if (elCurListItem) { instance._toggleHighlight(elCurListItem, 'from'); instance.fire('itemArrowFrom', elCurListItem); } if (newItemIndex == -1) { if (instance.get('delimChar')) { instance.inputNode.set('value', instance._pastSelections + instance._currentQuery); } else { instance.inputNode.set('value', instance._currentQuery); } return; } if (newItemIndex == -2) { instance._toggleContainer(false); return; } var elNewListItem = instance.resultList.get('childNodes').item(newItemIndex); var elContent = instance.overlay.get(CONTENT_BOX); var contentOverflow = elContent.getStyle('overflow'); var contentOverflowY = elContent.getStyle('overflowY'); var scrollOn = (contentOverflow == 'auto') || (contentOverflow == 'scroll') || (contentOverflowY == 'auto') || (contentOverflowY == 'scroll'); if (scrollOn && (newItemIndex > -1) && (newItemIndex < instance._displayedItems)) { var newScrollTop = -1; var liTop = elNewListItem.get('offsetTop'); var liBottom = liTop + elNewListItem.get('offsetHeight'); var contentHeight = elContent.get('offsetHeight'); var contentScrollTop = elContent.get('scrollTop'); var contentBottom = contentHeight + contentScrollTop; if (keyCode == KEY_DOWN) { if (liBottom > contentBottom) { newScrollTop = (liBottom - contentHeight); } else if (liBottom < contentScrollTop) { newScrollTop = liTop; } } else { if (liTop < contentHeight) { newScrollTop = liTop; } else if (liTop > contentBottom) { newScrollTop = (liBottom - contentHeight); } } if (newScrollTop > -1) { elContent.set('scrollTop', newScrollTop); } } instance._toggleHighlight(elNewListItem, 'to'); instance.fire('itemArrowTo', elNewListItem); if (instance.get('typeAhead')) { instance._updateValue(elNewListItem); } } }, /** * Called when the user mouses down on the button element in the combobox. * * @method _onButtonMouseDown * @param {EventFacade} event * @protected */ _onButtonMouseDown: function(event) { var instance = this; event.halt(); instance._focus(); instance._sendQuery(instance.inputNode.get('value') + '*'); }, /** * Handles when a user clicks on the container. * * @method _onContainerClick * @param {EventFacade} event * @protected */ _onContainerClick: function(event) { var instance = this; var target = event.target; var tagName = target.get('nodeName').toLowerCase(); event.halt(); while (target && (tagName != 'table')) { switch (tagName) { case 'body': return; case 'li': instance._toggleHighlight(target, 'to'); instance._selectItem(target); return; default: break; } target = target.get('parentNode'); if (target) { tagName.get('nodeName').toLowerCase(); } } }, /** * Handles when a user mouses out of the container. * * @method _onContainerMouseout * @param {EventFacade} event * @protected */ _onContainerMouseout: function(event) { var instance = this; var target = event.target; var tagName = target.get('nodeName').toLowerCase(); while (target && (tagName != 'table')) { switch (tagName) { case 'body': return; case 'li': instance._toggleHighlight(target, 'from'); instance.fire('itemMouseOut', target); break; case 'ul': instance._toggleHighlight(instance._elCurListItem, 'to'); break; case 'div': if (target.hasClass(CSS_RESULTS_OVERLAY)) { instance._overContainer = false; return; } break; default: break; } target = target.get('parentNode'); if (target) { tagName = target.get('nodeName').toLowerCase(); } } }, /** * Handles when a user mouses over the container. * * @method _onContainerMouseover * @param {EventFacade} event * @protected */ _onContainerMouseover: function(event) { var instance = this; var target = event.target; var tagName = target.get('nodeName').toLowerCase(); while (target && (tagName != 'table')) { switch (tagName) { case 'body': return; case 'li': instance._toggleHighlight(target, 'to'); instance.fire('itemMouseOut', target); break; case 'div': if (target.hasClass(CSS_RESULTS_OVERLAY)) { instance._overContainer = true; return; } break; default: break; } target = target.get('parentNode'); if (target) { tagName = target.get('nodeName').toLowerCase(); } } }, /** * Handles the container scroll events. * * @method _onContainerScroll * @param {EventFacade} event * @protected */ _onContainerScroll: function(event) { var instance = this; instance._focus(); }, /** * Enables the query to be triggered based on detecting text input via intervals instead of via * key events. * * @method _onInterval * @protected */ _onInterval: function() { var instance = this; var curValue = instance.inputNode.get('value'); var lastValue = instance._lastValue; if (curValue != lastValue) { instance._lastValue = curValue; instance._sendQuery(curValue); } }, /** * Handles the input element losing focus. * * @method _onTextboxBlur * @param {EventFacade} event * @protected */ _onTextboxBlur: function(event) { var instance = this; if (!instance._overContainer || (instance._keyCode == KEY_TAB)) { if (!instance._itemSelected) { var elMatchListItem = instance._textMatchesOption(); var overlayVisible = instance.overlay.get('visible'); if (!overlayVisible || (overlayVisible && isNull(elMatchListItem))) { if (instance.get('forceSelection')) { instance._clearSelection(); } else { instance.fire('unmatchedItemSelect', instance._currentQuery); } } else { if (instance.get('forceSelection')) { instance._selectItem(elMatchListItem); } } } instance._clearInterval(); instance.blur(); if (instance._initInputValue !== instance.inputNode.get('value')) { instance.fire('textboxChange'); } instance.fire('textboxBlur'); instance._toggleContainer(false); } else { instance._focus(); } }, /** * Handles the input element gaining focus. * * @method _onTextboxFocus * @param {EventFacade} event * @protected */ _onTextboxFocus: function(event) { var instance = this; if (!instance.get('focused')) { instance.inputNode.setAttribute('autocomplete', 'off'); instance.focus(); instance._initInputValue = instance.inputNode.get('value'); instance.fire('textboxFocus'); } }, /** * Handles the keydown events on the input element for functional keys. * * @method _onTextboxKeyDown * @param {EventFacade} event * @protected */ _onTextboxKeyDown: function(event) { var instance = this; var keyCode = event.keyCode; if (instance._typeAheadDelayId != -1) { clearTimeout(instance._typeAheadDelayId); } switch (keyCode) { case KEY_TAB: if (instance._elCurListItem) { if (instance.get('delimChar') && instance._keyCode != keyCode) { if (instance.overlay.get('visible')) { event.halt(); } } instance._selectItem(instance._elCurListItem); } else { instance._toggleContainer(false); } break; case KEY_ENTER: if (instance._elCurListItem) { if (instance._keyCode != keyCode) { if (instance.overlay.get('visible')) { event.halt(); } } instance._selectItem(instance._elCurListItem); } else { instance._toggleContainer(false); } break; case KEY_ESC: instance._toggleContainer(false); return; case KEY_UP: if (instance.overlay.get('visible')) { event.halt(); instance._moveSelection(keyCode); } break; case KEY_RIGHT: instance._jumpSelection(); break; case KEY_DOWN: if (instance.overlay.get('visible')) { event.halt(); instance._moveSelection(keyCode); } break; default: instance._itemSelected = false; instance._toggleHighlight(instance._elCurListItem, 'from'); instance.fire('textboxKey', keyCode); break; } if (keyCode == KEY_ALT) { instance._enableIntervalDetection(); } instance._keyCode = keyCode; }, /** * Handles the key press events of the input element. * * @method _onTextboxKeyPress * @param {EventFacade} event * @protected */ _onTextboxKeyPress: function(event) { var instance = this; var keyCode = event.keyCode; switch (keyCode) { case KEY_TAB: if (instance.overlay.get('visible')) { if (instance.get('delimChar')) { event.halt(); } if (instance._elCurListItem) { instance._selectItem(instance._elCurListItem); } else { instance._toggleContainer(false); } } break; case 13: if (instance.overlay.get('visible')) { event.halt(); if (instance._elCurListItem) { instance._selectItem(instance._elCurListItem); } else { instance._toggleContainer(false); } } break; default: break; } if (keyCode == KEY_KOREAN_IME) { instance._enableIntervalDetection(); } }, /** * Handles the keyup events of the input element. * * @method _onTextboxKeyUp * @param {EventFacade} event * @protected */ _onTextboxKeyUp: function(event) { var instance = this; var input = instance.inputNode; var value = input.get('value'); var keyCode = event.keyCode; if (instance._isIgnoreKey(keyCode)) { return; } instance._queryTask.delay(instance.get('queryDelay'), null, null, [value]); }, /** * Populates the container with list items of the query results. * * @method _populateList * @param {EventFacade} event * @protected */ _populateList: function(event) { var instance = this; if (instance._typeAheadDelayId != -1) { clearTimeout(instance._typeAheadDelayId); } var query = event.request; var response = event.response; var callback = event.callback; var showAll = (query == '*'); if (callback && callback.argument && callback.argument.query) { event.request = query = callback.argument.query; } var ok = instance.doBeforeLoadData(event); if (ok && !event.error) { instance.fire('dataReturn', event); var focused = instance.get('focused'); if (showAll || focused || focused === null) { var currentQuery = decodeURIComponent(query); instance._currentQuery = currentQuery; instance._itemSelected = false; var allResults = event.response.results; var itemsToShow = Math.min(allResults.length, instance.get('maxResultsDisplayed')); var fields = instance.get('schema.resultFields'); var matchKey = instance.get('matchKey'); if (!matchKey && fields) { matchKey = fields[0]; } else { matchKey = matchKey || 0; } if (itemsToShow > 0) { var allListItemEls = instance.resultList.get('childNodes'); allListItemEls.each( function(node, i, nodeList) { if (i < itemsToShow) { var result = allResults[i]; var resultMatch = ''; if (isString(result)) { resultMatch = result; } else if (isArray(result)) { resultMatch = result[0]; } else { resultMatch = result[matchKey]; } node._resultMatch = resultMatch; node._resultData = result; node.html(instance.formatResult(result, currentQuery, resultMatch)); node.removeClass(CSS_HIDDEN); } else { node.addClass(CSS_HIDDEN); } } ); instance._displayedItems = itemsToShow; instance.fire('containerPopulate', query, allResults); if (query != '*' && instance.get('autoHighlight')) { var elFirstListItem = instance.resultList.get('firstChild'); instance._toggleHighlight(elFirstListItem, 'to'); instance.fire('itemArrowTo', elFirstListItem); instance._typeAhead(elFirstListItem, query); } else { instance._toggleHighlight(instance._elCurListItem, 'from'); } ok = instance.doBeforeExpandContainer(query, allResults); instance._toggleContainer(ok); } else { instance._toggleContainer(false); } return; } } else { instance.fire('dataError', query); } }, /** * Realigns the container to the input element. * * @method _realignContainer * @param {EventFacade} event * @protected */ _realignContainer: function(event) { var instance = this; var overlayAlign = instance._overlayAlign; if (event.newVal) { instance.overlay._uiSetAlign(overlayAlign.node, overlayAlign.points); } }, /** * Handles the rendering of the input element. * * @method _renderInput * @protected */ _renderInput: function() { var instance = this; var contentBox = instance.get(CONTENT_BOX); var input = instance.get('input'); var comboConfig = { field: { labelText: false }, icons: [ { icon: 'circle-triangle-b', id: 'trigger', handler: { fn: instance._onButtonMouseDown, context: instance } } ] }; var inputReference = null; var inputParent = null; if (input) { input = A.one(input); comboConfig.field.node = input; inputReference = input.next(); inputParent = input.get('parentNode'); } var comboBox = new A.Combobox(comboConfig).render(contentBox); if (inputParent) { var comboBoundingBox = comboBox.get('boundingBox'); inputParent.insertBefore(comboBoundingBox, inputReference); } instance.inputNode = comboBox.get('node'); instance.button = comboBox.icons.item('trigger'); instance.set('uniqueName', A.stamp(instance.inputNode)); }, /** * Pre-populates the container with the * <a href="Autocomplete.html#config_maxResultsDisplayed">maxResultsDisplayed</a> * number of list items. * * @method _renderListElements * @protected */ _renderListElements: function() { var instance = this; var maxResultsDisplayed = instance.get('maxResultsDisplayed'); var resultList = instance.resultList; var listItems = []; while (maxResultsDisplayed--) { listItems[maxResultsDisplayed] = '<li class="' + CSS_HIDDEN + ' ' + CSS_LIST_ITEM + '" data-listItemIndex="' + maxResultsDisplayed + '"></li>'; } resultList.html(listItems.join('')); }, /** * Handles the creation of the overlay where the result list will be displayed. * * @method _renderOverlay * @protected */ _renderOverlay: function() { var instance = this; var overlayAlign = instance._overlayAlign; overlayAlign.node = instance.inputNode; var overlay = new A.OverlayBase( { align: overlayAlign, bodyContent: '<ul></ul>', visible: false, width: instance.inputNode.get('offsetWidth') } ); var contentBox = overlay.get(CONTENT_BOX); overlay.get(BOUNDING_BOX).addClass(CSS_RESULTS_OVERLAY); contentBox.addClass(CSS_RESULTS_OVERLAY_CONTENT); overlay.render(document.body); overlay.addTarget(instance); instance.overlay = overlay; instance.resultList = contentBox.one('ul'); instance.resultList.addClass(CSS_RESULTS_LIST); instance._renderListElements(); }, /** * Selects a list item from the query results. * * @method _selectItem * @param {Node} elListItem The list item to select * @protected */ _selectItem: function(elListItem) { var instance = this; instance._itemSelected = true; instance._updateValue(elListItem); instance._pastSelections = instance.inputNode.get('value'); instance._clearInterval(); instance.fire('itemSelect', elListItem, elListItem._resultData); instance._toggleContainer(false); }, /** * Makes a query request to the data source. * * @method _sendQuery * @param {String} query The query string * @protected */ _sendQuery: function(query) { var instance = this; if (instance.get('disabled')) { instance._toggleContainer(false); return; } var delimChar = instance.get('delimChar'); var minQueryLength = instance.get('minQueryLength'); if (delimChar) { var extraction = instance._extractQuery(query); query = extraction.query; instance._pastSelections = extraction.previous; } if ((query && (query.length < minQueryLength)) || (!query && minQueryLength > 0)) { instance._queryTask.cancel(); instance._toggleContainer(false); return; } query = encodeURIComponent(query); if (instance.get('applyLocalFilter')) { instance.dataSource.on('response', instance.filterResults, instance); } var request = instance.generateRequest(query); instance.fire('dataRequest', query, request); instance.dataSource.sendRequest(request); }, /** * Checks to see if the value typed by the user matches any of the * query results. * * @method _textMatchesOption * @protected */ _textMatchesOption: function() { var instance = this; var elMatch = null; var displayedItems = instance._displayedItems; var listItems = instance.resultList.get('childNodes'); for (var i=0; i < displayedItems.length; i++) { var elListItem = listItems.item(i); var match = ('' + elListItem._resultMatch).toLowerCase(); if (match == instance._currentQuery.toLowerCase()) { elMatch = elListItem; break; } } return elMatch; }, /** * Toggles the display of the results container. * * @method _toggleContainer * @param {Boolean} show Flag to force the showing or hiding of the container * @protected */ _toggleContainer: function(show) { var instance = this; var overlay = instance.overlay; if (instance.get('alwaysShowContainer') && overlay.get('visible')) { return; } if (!show) { instance._toggleHighlight(instance._elCurListItem, 'from'); instance._displayedItems = 0; instance._currentQuery = null; } if (show) { overlay.show(); instance.fire('containerExpand'); } else { overlay.hide(); instance.fire('containerCollapse'); } }, /** * Toggles the highlighting of a list item, and removes the highlighting from the previous item * * @method _toggleHighlight * @param {Node} elNewListItem The item to be highlighted * @param {String} action Whether we are moving to or from an item. Valid values are "to" or "from". * @protected */ _toggleHighlight: function(elNewListItem, action) { var instance = this; if (elNewListItem) { if (instance._elCurListItem) { instance._elCurListItem.removeClass(CSS_HIGLIGHT); instance._elCurListItem = null; } if (action == 'to') { elNewListItem.addClass(CSS_HIGLIGHT); instance._elCurListItem = elNewListItem; } } }, /** * Updates in the input element with the first result as the user types, * selecting the text the user has not typed yet. * * @method _typeAhead * @param {Node} elListItem The selected list item * @param {String} query The query string * @protected */ _typeAhead: function(elListItem, query) { var instance = this; if (!instance.get('typeAhead') || instance._keyCode == KEY_BACKSPACE) { return; } var inputEl = A.Node.getDOMNode(instance.inputNode); if (inputEl.setSelectionRange || inputEl.createTextRange) { instance._typeAheadDelayId = setTimeout( function() { var value = inputEl.value; var start = value.length; instance._updateValue(elListItem); var end = inputEl.value.length; instance.inputNode.selectText(start, end); var prefill = inputEl.value.substr(start, end); instance.fire('typeAhead', query, prefill); }, instance.get('typeAheadDelay') ); } }, /** * Updates the input element with the selected query result. If * <a href="Autocomplete.html#config_delimChar">delimChar</a> has been set, * then the value gets appended with the delimiter. * * @method _updateValue * @param {Node} elListItem The selected list item * @protected */ _updateValue: function(elListItem) { var instance = this; if (!instance.get('suppressInputUpdate')) { var input = instance.inputNode; var resultMatch = elListItem._resultMatch; var delimChar = instance.get('delimChar'); delimChar = (delimChar && delimChar[0]) || delimChar; var newValue = ''; if (delimChar) { newValue = instance._pastSelections; newValue += resultMatch + delimChar; if (delimChar != ' ') { newValue += ' '; } } else { newValue = resultMatch; } input.set('value', newValue); if (input.get('type') == 'textarea') { input.set('scrollTop', input.get('scrollHeight')); } var end = newValue.length; input.selectText(end, end); instance._elCurListItem = elListItem; } }, _currentQuery: null, _displayedItems: 0, _elCurListItem: null, _initInputValue: null, _itemSelected: false, _keyCode: null, _lastValue: null, _overContainer: false, _pastSelections: '', _typeAheadDelayId: -1 } } ); A.AutoComplete = AutoComplete; }, '1.0.1' ,{skinnable:true, requires:['aui-base','aui-overlay-base','datasource','dataschema','aui-form-combobox']});
发表评论
-
AOP
2017-02-28 13:14 482http://blog.csdn.net/moreev ... -
liferay 6.1 CE + LDAP 导入自定义字段
2013-12-21 16:06 898导入自定义字段时无论如何尝试都不成功,但是自定义字段的值导 ... -
liferay 6.1 CE LDAP
2013-12-14 14:20 2324goole了许多网页,讲的是五花八门,最后想起来去port ... -
research
2013-12-10 10:42 0<aui:select label="typ ... -
fetch 与 find 的区别
2013-11-11 09:55 909liferay中 findxxxx 与fetchxxx 方 ... -
liferay 一对多 多对多 关系 (model)
2013-11-07 11:24 713通过model层实现 例如 people 与 ad ... -
liferay 一对多 多对多 关系 (build-service)
2013-11-07 11:04 692通过配置service.xml 实现 说明:一对多 ... -
liferay Logical Architecture
2013-09-11 15:20 1186Logical Architecture 详 ... -
liferay 文件下载失败
2013-07-01 14:48 589现象: http://issues.liferay.com/ ... -
403
2013-06-05 16:41 0portal.properties auth.forward ... -
[转] Liferay多数据源配置及开发
2013-06-05 16:16 765http://www.chinasb.org/archives ... -
aui-autocomplete [ 二 ] 验证未通过保留输入值
2013-01-09 09:25 856<% long myUserId = ParamU ... -
aui-autocomplete [ 一 ] override
2013-01-08 13:58 862liferay aui-autocomplete 如: 数据 ... -
Liferay AutoFields 添加事件
2013-01-08 09:30 0new Liferay.AutoFields( ... -
web app timezone (view-business-db)
2013-01-07 11:50 1246目标:面向多区域用户 添加更新记录:用户输入本区域时间, 数据 ... -
liferay auto_filed
2012-12-03 14:51 810new Liferay.AutoFields( ... -
liferay at java.util.regex.Pattern$Curly.match0
2012-11-21 13:17 923build-service 出现liferay at java ... -
actionurl 参数顺序
2012-10-19 14:16 1509PortletURL editURL = renderResp ... -
java.lang.ClassCastException: java.math.BigInteger cannot be cast to java.lang.
2012-10-19 14:06 4055现象: liferay中查询数据,用到如下语句 select ... -
Unable to find required classes (javax.activation.DataHandler and javax.mail.int
2012-09-04 13:41 10982.1.8 错误原因: 需要mail.jar和activat ...
相关推荐
Aui-core是一个基于原生JavaScript的库,它旨在简化前端开发,提供了一些实用的工具和功能。在这个项目中,我们看到Aui-core与CSS3的`transform`属性相结合,来实现更丰富的视觉效果和动态交互。 `transform`属性是...
《aui-artDialog-6.0.2 requireJS 修改版:打造高效异步加载对话框体验》 在Web开发中,交互性与用户体验是至关重要的元素,而艺术对话框(artDialog)作为一款功能强大的JavaScript弹出对话框插件,广泛应用于各种...
##Aui-gridx 概述Aui gridx(angularUI-gridx) 是一个强大的基于 AngularJS 的网格小部件。 它是轻量级、易于配置、快速渲染和原生树支持。 目前,它为您提供了以下功能排序分页树单元格格式器和装饰器 此外,aui-...
本项目涉及的是一个使用Aui-core库实现的图片3D 360度旋转效果,它允许用户从各个角度查看图片,增强视觉体验。这种技术常用于产品展示、虚拟现实场景以及互动媒体设计等领域。 首先,我们要理解3D旋转的概念。在...
artDialog是一个轻巧且高度兼容的javascript对话框组件,可让你的网页交互拥有桌面软件般的用户体验。 功能: 支持锁定屏幕(遮罩)、模拟alert和confirm、多窗口弹出、静止定位、支持Ese键关闭对话框、定时关闭、...
<div class="aui-sale-time"> <div class="aui-sale-title">限时秒杀 <div class="aui-sale-second">FLASH DEALS <div class="aui-sale-icon-sd"> <div class="aui-sale-ends">本场距离结束还剩 ...
- **布局容器**:AUI提供了`.aui-content`、`.aui-card`等布局容器类,便于快速组织页面结构。 - `.aui-content`: 基础布局容器,默认背景色为白色。 - `.aui-card`: 圆角容器,自带10px外边距,适用于卡片式布局...
移动框架:aui的底部导航栏tab,关联内容footer_bar_frm以及完成选项卡的切换功能。在官网给出的例子基础上,增加关联内容,实现选项卡切换内容随之切换的功能。这是完整开发例子源码包,直接浏览器预览即可看到完整...
artDialog —— 经典、优雅的网页对话框控件。 支持普通与 12 方向气泡状对话框 完善的焦点处理,自动焦点附加与回退 支持 ARIA 标准 面向未来:基于 ... 很漂亮的弹出框,支持IE、FF、Chrome,附带了很多例子供学习。
"Aui-core-1.42-min.js"是一个压缩过的JavaScript库,很可能包含自定义的函数和方法,用于处理图片的3D变换、动画效果以及用户交互。在这个库中,开发者可能使用了WebGL或者CSS3的3D变换来实现3D效果。WebGL是一种...
进销存手机版管理系统是一款基于AUI和Vue.js技术构建的应用,专为移动设备设计,旨在高效管理企业的库存、采购和销售活动。系统采用AUI(可能是AlloyUI或其他以A开头的UI框架)作为前端界面组件库,结合Vue.js的响应...
$('.aui-content-main .aui-content-menu').hover(function(){ $(this).addClass('active').find('s').hide(); $(this).find('.aui-content-menu-dow').show(); },function(){ $(this).removeClass('active')....
树莓派-AUI v6.2 树莓派配置基本介绍 安装 Raspberry-Pi-AUI 的步骤: ...aui-oc 超频用户界面 aui-userm 用户管理界面 aui-util 实用程序管理器用户界面 如何贡献? 看看 笔记 获取错误。 执行: sudo
在"wordpress-aui-theme-master"这个压缩包中,你可能会找到以下文件和文件夹: - `style.css`:主题的主要样式文件,定义了页面的外观和布局。 - `functions.php`:包含主题的PHP函数,用于扩展WordPress的功能。 ...
源在Https://bitbucket.org/200ok/aui-debug上可用,与AUI 5.1相同的许可证,并且可能被叉。 ---- 使用AUI构建的接口调试工具。 功能包括: - 识别当前页面中的AUI组件 - idenfity问题,如弃用组件的使用,不正确的...
在`aui-master`这个压缩包文件中,通常会包含AUI框架的源码、文档、示例项目以及相关的配置文件。源码部分可能分为CSS、JavaScript和图片资源,开发者可以通过研究这些文件了解AUI的实现原理并进行定制化修改。文档...
代码片段: ... <span class="aui-icon aui-icon-arrow-fl" id="js_function-orbit-prev" title="上一个"> <span class="aui-icon aui-icon-arrow-fr" id="js_function-orbit-next" title="下一个">
【标题】"全套移动端_app_页面(商城)html-demo"所涵盖的知识点主要涉及移动应用开发,特别是前端设计和实现。... ... 2. **前端框架与库**:虽然在描述中未提及,但通常在创建复杂的移动端页面时,开发者可能会使用像...
input class="aui-radio" v-model="vo.is_select" v-if="api.systemType=='ios'" @touchstart.prevent="update_cart_selectss(index)" type="checkbox"> <input class="aui-radio" :checked="vo.is_select" v...