/** * @summary SelectPage * @desc Simple and powerful selection plugin * @file selectpage.js * @version 2.20 * @author TerryZeng * @contact https://terryz.github.io/ * @license MIT License * */ ;(function ($) { "use strict"; /** * Default options */ var defaults = { /** * Data source * @type {string|Object} * * string:server side request url address * Object:JSON array,format:[{a:1,b:2,c:3},{...}] */ data: undefined, /** * Language ('cn', 'en') * @type string * @default 'cn' */ lang: 'cn', /** * Multiple select mode(tags) * @type boolean * @default false */ multiple: false, /** * pagination or not * @type boolean * @default true */ pagination: true, /** * Show up menu button * @type boolean * @default true */ dropButton: true, /** * Result list visible size in pagination bar close * @type number * @default 10 */ listSize: 10, /** * Show control bar in multiple select mode * @type boolean * @default true */ multipleControlbar: true, /** * Max selected item limited in multiple select mode * @type number * @default 0(unlimited) */ maxSelectLimit: 0, /** * Select result item to close list, work on multiple select mode * @type boolean * @default false */ selectToCloseList: false, /** * Init selected item key, the result will match to option.keyField option * @type string */ initRecord: undefined, /** * The table parameter in server side mode * @type string */ dbTable: 'tbl', /** * The value field, the value will fill to hidden element * @type string * @default 'id' */ keyField: 'id', /** * The show text field, the text will show to input element or tags(multiple mode) * @type string * @default 'name' */ showField: 'name', /** * Actually used to search field * @type string */ searchField: undefined, /** * Search type ('AND' or 'OR') * @type string * @default 'AND' */ andOr: 'OR', /** * Used to separate search content * @see SelectPage.prototype.suggest() */ separator: ',', /** * Result sort type * @type array|boolean - if not set, will default used showField field * @example * orderBy : ['id desc'] */ orderBy: undefined, /** * Page size * @type number * @default 10 */ pageSize: 10, /** * Server side request parameters * @type function * @return object * @example params : function(){return {'name':'aa','sex':1};} */ params: undefined, /** * Custom result list item show text * @type function * @param data {object} row data * @return string */ formatItem: undefined, /** * Have some highlight item and lost focus, auto select the highlight item * @type boolean * @default false */ autoFillResult: false, /** * Auto select first item in show up result list or search result * depend on `autoFillResult` option set to true * @type boolean * @default false */ autoSelectFirst: false, /** * Whether clear input element text when enter some keywords to search and no result return * @type boolean * @default true */ noResultClean: true, /** * Select only mode * @type boolean */ selectOnly: false, /** * Input to search delay time, work on ajax data source * @type number * @default 0.5 */ inputDelay: 0.5, /** * -----------------------------------------Callback-------------------------------------------- */ /** * Result list item selected callback * @type function * @param object - selected item json data * @param self - plugin object */ eSelect: undefined, /** * Before result list show up callback, you can do anything prepared * @param self - plugin object */ eOpen: undefined, /** * Server side return data convert callback * @type function * @param data {object} server side return data * @param self {object} plugin object * @return {object} return data format: * @example * { * list : [{name:'aa',sex:1},{name:'bb',sex:1}...], * totalRow : 100 * } */ eAjaxSuccess: undefined, /** * Close selected item tag callback (multiple mode) * @type function * @param removeCount {number} remove item count * @param self {object} plugin object */ eTagRemove: undefined, /** * Clear selected item callback(single select mode) * @type function * @param self {object} plugin object */ eClear: undefined }; /** * SelectPage class definition * @constructor * @param {Object} input - input element * @param {Object} option */ var SelectPage = function (input, option) { //特殊字段处理 $.each({data: 'source', keyField: 'primaryKey', showField: 'field', pageSize: 'perPage'}, function (i, j) { if (typeof option[j] !== 'undefined') { option[i] = option[j]; delete option[j]; } }); this.setOption(option); this.setLanguage(); this.setCssClass(); this.setProp(); this.setElem(input); this.setButtonAttrDefault(); this.setInitRecord(); this.eDropdownButton(); this.eInput(); this.eWhole(); }; /** * Plugin version number */ SelectPage.version = '2.19'; /** * Plugin object cache key */ SelectPage.dataKey = 'selectPageObject'; /** * Options set * @param {Object} option */ SelectPage.prototype.setOption = function (option) { //use showField to default option.searchField = option.searchField || option.showField; option.andOr = option.andOr.toUpperCase(); if (option.andOr !== 'AND' && option.andOr !== 'OR') option.andOr = 'AND'; //support multiple field set var arr = ['searchField']; for (var i = 0; i < arr.length; i++) { option[arr[i]] = this.strToArray(option[arr[i]]); } //set default order field option.orderBy = option.orderBy || option.showField; //set multiple order field //example: [ ['id', 'ASC'], ['name', 'DESC'] ] if (option.orderBy !== false) option.orderBy = this.setOrderbyOption(option.orderBy, option.showField); //close auto fill result and auto select first in multiple mode and select item not close list if (option.multiple && !option.selectToCloseList) { option.autoFillResult = false; option.autoSelectFirst = false; } //show all item when pagination bar close, limited 200 if (!option.pagination) option.pageSize = 200; if ($.type(option.listSize) !== 'number' || option.listSize < 0) option.listSize = 10; if (typeof option.formatItem === 'string') { var _formatItem = option.formatItem; option.formatItem = function (row) { if (typeof Template === 'function' && _formatItem.match(/\#([a-zA-Z0-9_\-]+)$/)) { return Template(_formatItem.substring(1), row); } else { return _formatItem.replace(/\{(.*?)\}/gi, function (matched) { matched = matched.substring(1, matched.length - 1); return typeof row[matched] !== 'undefined' ? row[matched] : ''; }); } }; } this.option = option; }; /** * String convert to array * @param str {string} * @return {Array} */ SelectPage.prototype.strToArray = function (str) { return str ? str.replace(/[\s ]+/g, '').split(',') : ''; }; /** * Set order field * @param {Array} arg_order * @param {string} arg_field - default sort field * @return {Array} */ SelectPage.prototype.setOrderbyOption = function (arg_order, arg_field) { var arr = [], orders = []; if (typeof arg_order === 'object') { for (var i = 0; i < arg_order.length; i++) { orders = $.trim(arg_order[i]).split(' '); if (orders.length) arr.push((orders.length === 2) ? orders.concat() : [orders[0], 'ASC']); } } else { orders = $.trim(arg_order).split(' '); arr[0] = (orders.length === 2) ? orders.concat() : (orders[0].toUpperCase().match(/^(ASC|DESC)$/i)) ? [arg_field, orders[0].toUpperCase()] : [orders[0], 'ASC']; } return arr; }; /** * i18n */ SelectPage.prototype.setLanguage = function () { var message, p = this.option; switch (p.lang) { // English case 'en': message = { add_btn: 'Add button', add_title: 'add a box', del_btn: 'Del button', del_title: 'delete a box', next: 'Next', next_title: 'Next' + p.pageSize + ' (Right key)', prev: 'Prev', prev_title: 'Prev' + p.pageSize + ' (Left key)', first_title: 'First (Shift + Left key)', last_title: 'Last (Shift + Right key)', get_all_btn: 'Get All (Down key)', get_all_alt: '(button)', close_btn: 'Close (Tab key)', close_alt: '(button)', loading: 'loading...', loading_alt: '(loading)', page_info: 'page_num of page_count', select_ng: 'Attention : Please choose from among the list.', select_ok: 'OK : Correctly selected.', not_found: 'not found', ajax_error: 'An error occurred while connecting to server.', clear: 'Clear content', select_all: 'Select current page', unselect_all: 'Clear current page', clear_all: 'Clear all selected', max_selected: 'You can only select up to max_selected_limit items' }; break; // 中文 case 'cn': default: message = { add_btn: '添加按钮', add_title: '添加区域', del_btn: '删除按钮', del_title: '删除区域', next: '下一页', next_title: '下' + p.pageSize + ' (→)', prev: '上一页', prev_title: '上' + p.pageSize + ' (←)', first_title: '首页 (Shift + ←)', last_title: '尾页 (Shift + →)', get_all_btn: '获得全部 (↓)', get_all_alt: '(按钮)', close_btn: '关闭 (Tab键)', close_alt: '(按钮)', loading: '读取中...', loading_alt: '(读取中)', page_info: '第 page_num 页(共page_count页)', select_ng: '请注意:请从列表中选择.', select_ok: 'OK : 已经选择.', not_found: '无查询结果', ajax_error: '连接到服务器时发生错误!', clear: '清除内容', select_all: '选择当前页项目', unselect_all: '取消选择当前页项目', clear_all: '清除全部已选择项目', max_selected: '最多只能选择 max_selected_limit 个项目' }; break; } this.message = message; }; /** * Css classname defined */ SelectPage.prototype.setCssClass = function () { var css_class = { container: 'sp_container', container_open: 'sp_container_open', re_area: 'sp_result_area', result_open: 'sp_result_area_open', control_box: 'sp_control_box', //multiple select mode element_box: 'sp_element_box', navi: 'sp_navi', //result list results: 'sp_results', re_off: 'sp_results_off', select: 'sp_over', select_ok: 'sp_select_ok', select_ng: 'sp_select_ng', selected: 'sp_selected', input_off: 'sp_input_off', message_box: 'sp_message_box', disabled: 'sp_disabled', button: 'sp_button', caret_open: 'sp_caret_open', btn_on: 'sp_btn_on', btn_out: 'sp_btn_out', input: 'sp_input', clear_btn: 'sp_clear_btn', align_right: 'sp_align_right' }; this.css_class = css_class; }; /** * Plugin inner properties */ SelectPage.prototype.setProp = function () { this.prop = { //input disabled status disabled: false, current_page: 1, //total page max_page: 1, //ajax data loading status is_loading: false, xhr: false, key_paging: false, key_select: false, //last selected item value prev_value: '', //last selected item text selected_text: '', last_input_time: undefined, init_set: false }; this.template = { tag: { content: '
'); elem.control.append(elem.control_text); elem.result_area.prepend(elem.control); } elem.container.addClass('sp_container_combo'); elem.combo_input.addClass('sp_combo_input').before(elem.element_box); var li = $('