/** * @name 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', 'ja', 'es', 'pt-br') * @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: 'AND', /** * Result sort type * @type array|boolean * @example * orderBy : ['id desc'] */ orderBy: false, /** * 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) { 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.20' /** * Plugin object cache key */ SelectPage.dataKey = 'selectPageObject' /** * Options set * @param {Object} option */ SelectPage.prototype.setOption = function (option) { // use showField by 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 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 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) { // German case 'de': message = { add_btn: 'Hinzufügen-Button', add_title: 'Box hinzufügen', del_btn: 'Löschen-Button', del_title: 'Box löschen', next: 'Nächsten', next_title: 'Nächsten' + p.pageSize + ' (Pfeil-rechts)', prev: 'Vorherigen', prev_title: 'Vorherigen' + p.pageSize + ' (Pfeil-links)', first_title: 'Ersten (Umschalt + Pfeil-links)', last_title: 'Letzten (Umschalt + Pfeil-rechts)', get_all_btn: 'alle (Pfeil-runter)', get_all_alt: '(Button)', close_btn: 'Schließen (Tab)', close_alt: '(Button)', loading: 'lade...', loading_alt: '(lade)', page_info: 'page_num von page_count', select_ng: 'Achtung: Bitte wählen Sie aus der Liste aus.', select_ok: 'OK : Richtig ausgewählt.', not_found: 'nicht gefunden', ajax_error: 'Bei der Verbindung zum Server ist ein Fehler aufgetreten.', clear: 'Löschen Sie den Inhalt', select_all: 'Wähle diese Seite', unselect_all: 'Diese Seite entfernen', clear_all: 'Alles löschen', max_selected: 'Sie können nur bis zu max_selected_limit Elemente auswählen' } break // 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 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 // Spanish case 'es': message = { add_btn: 'Agregar boton', add_title: 'Agregar una opcion', del_btn: 'Borrar boton', del_title: 'Borrar una opcion', next: 'Siguiente', next_title: 'Proximas ' + p.pageSize + ' (tecla derecha)', prev: 'Anterior', prev_title: 'Anteriores ' + p.pageSize + ' (tecla izquierda)', first_title: 'Primera (Shift + Left)', last_title: 'Ultima (Shift + Right)', get_all_btn: 'Ver todos (tecla abajo)', get_all_alt: '(boton)', close_btn: 'Cerrar (tecla TAB)', close_alt: '(boton)', loading: 'Cargando...', loading_alt: '(Cargando)', page_info: 'page_num de page_count', select_ng: 'Atencion: Elija una opcion de la lista.', select_ok: 'OK: Correctamente seleccionado.', not_found: 'no encuentre', ajax_error: 'Un error ocurrió mientras conectando al servidor.', clear: 'Borrar el contenido', select_all: 'Elija esta página', unselect_all: 'Borrar esta página', clear_all: 'Borrar todo marcado', max_selected: 'Solo puedes seleccionar hasta max_selected_limit elementos' } break // Brazilian Portuguese case 'pt-br': message = { add_btn: 'Adicionar botão', add_title: 'Adicionar uma caixa', del_btn: 'Apagar botão', del_title: 'Apagar uma caixa', next: 'Próxima', next_title: 'Próxima ' + p.pageSize + ' (tecla direita)', prev: 'Anterior', prev_title: 'Anterior ' + p.pageSize + ' (tecla esquerda)', first_title: 'Primeira (Shift + Left)', last_title: 'Última (Shift + Right)', get_all_btn: 'Ver todos (Seta para baixo)', get_all_alt: '(botão)', close_btn: 'Fechar (tecla TAB)', close_alt: '(botão)', loading: 'Carregando...', loading_alt: '(Carregando)', page_info: 'page_num de page_count', select_ng: 'Atenção: Escolha uma opção da lista.', select_ok: 'OK: Selecionado Corretamente.', not_found: 'não encontrado', ajax_error: 'Um erro aconteceu enquanto conectando a servidor.', clear: 'Limpe o conteúdo', select_all: 'Selecione a página atual', unselect_all: 'Remova a página atual', clear_all: 'Limpar tudo', max_selected: 'Você só pode selecionar até max_selected_limit itens' } break // Japanese case 'ja': 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: '(0 件)', ajax_error: 'サーバとの通信でエラーが発生しました。', clear: 'コンテンツをクリアする', select_all: '当ページを選びます', unselect_all: '移して当ページを割ります', clear_all: '選択した項目をクリアする', max_selected: '最多で max_selected_limit のプロジェクトを選ぶことしかできません' } 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 = $('