fastadmin/public/assets/libs/selectpage/selectpage.js

2478 lines
98 KiB
JavaScript
Raw Blame History

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* @summary SelectPage
* @desc 基于jQuery及使用Bootstrap环境开发的下拉列表带输入快速查找及结果分页展示的多功能选择器
* @file selectpage.js
* @version 2.7
* @author TerryZeng
* @contact https://terryz.github.io/
* @license MIT License
*
* 插件的部分功能使用、借鉴了
* jQuery Plugin: jquery.ajax-combobox
* 作者Yuusaku Miyazaki <toumin.m7@gmail.com>(宮崎 雄策)
*
* 插件依赖:
* jQuery1.x
* font-awesome(图标库)
*
* 基本功能:
* 可实时搜索的下拉列表
* 对待选择的下拉项目可进行分页
* 可使用键盘快捷分页操作
* 使用标签的方式支持下拉项目多选
*
* 修改记录:
* 2016.04.20
* 增加参数autoSelectFirst(是否自动选择列表中的第一项内容)
* 解决下拉分页有初始化内容,并删除部分关键字时显示的结果集列表不足一页时,分页栏没有被生成的问题
* 增加参数autoFillResult(是否自动填充内容)
* 增加参数noResultClean(是否清空无匹配结果的输入关键字)
* 2016.06.29
* 修复分页栏鼠标点击时跳转的页数不正常的问题
* 2016.08.04
* 修复因宽度变化导致下拉触发按钮位置在出现下拉列表后发生偏移,原因是原控件的触发按钮是在输入框外部扩展,现已移入输入框内部
* 2016.08.10
* 弹出下拉列表时,若有已选中的项目,则将已选中的项目进行高亮,否则对第一行进行高亮
* 下拉列表展开时,鼠标点击列表区域外,若当前列表已有选中项目,则直接隐藏列表;若当前列表没有默认选中项目,则使用当前高亮项目的内容进行设置
* 2016.08.12
* 解决控件对于原始input设置的样式(bootstrap原生提供的宽度样式),宽度显示不正常的问题
* 增加若设置了formatItem格式函数则进行匹配的数据源从showField改为formatItem后的结果进行匹配
* 2016.10
* 增加光标进入输入框时,打开下拉列表的功能
* 2017.01.16
* 解决输入关键进行搜索并有匹配结果时,失去焦点后,没有自动选中第一项
* 2017.01.19
* 取消在输入状态时,判断到输入框里内容为空时,隐藏下拉列表的操作
* 在展示下拉列表时,判断默认与输入框左对齐的列表是否会超出屏幕边界,是则右对齐,否则默认左对齐
* 2017.01.20
* 增加下拉列表展示之前判断列表的面板是否会超出底部区域,若超出则将列表向上对齐展示
* 处理下拉列表显示一次操作显示多次的问题
* 增加控件已有选中值时,在显示下拉列表时,直接跳转到该项目所在的页
* 修复一些点击输入框出现下拉列表的Bug
* 2017.03.24
* 解决下拉分页插件向上浮动时位置不正确的问题
* 解决下拉分页插件在已有选中值时,再次点击输入框后,打开的列表分页栏翻页功能无效的问题
* 2017.04.21
* 解决打开noResultClean参数没有匹配输入关键词的项目时列表不隐藏的问题
* 2017.04.24
* 解决控件在设置disabled="disabled"禁用状态时,点击向下的三角尖也可以打开列表的问题
* 增加控件在已有选中项目时,直接删除输入框中的内容,作为清空控件内容的功能
* 修改失去焦点的范围从document.body到document
* 优化键盘输入捕捉的方式
* 原列表有多页的情况下,再输入关键字,没有匹配到任何项目时,分页条的下一页,最后一页为可点击的样式,且分页信息的内容也不正确
* 2017.05
* 代码重构
* 增加多项选择东西并以标签Tag的形式展现在输入框中
* 修正插件外框宽度问题
* 修改选中事件回调的入参从key,value改为选中行的原始数据对象以便更灵活的数据处理
* 2017.06
* 修复部分样式问题
* 2017.06.13
* 改名SelectPage
* 2017.06.24
* 增加Bootstrap3样式支持
* 2017.08.08
* 修复界面上排版内容较少时,列表会向上展示开的问题
* 增加多选模式下的控制按钮区域,功能:“全选本页”、“取消本页”、“清空全部”
* 修复最大宽度下超出父容器的宽度问题
* 修复ajax模式报错的问题
* 增加eAjaxSuccess请求成功后的数据处理回调
* 2017.08.13v2.0
* 代码重构
* 修改默认样式,使用更简洁的风格
* 增加maxSelectLimit参数设置多选模式下最大选择个数限制
* 增加eTagRemove回调函数在多选模式下移除标签时触发的回调
* 优化错误信息展示的交互方式
* 增加初始化选中项目时多选模式允许设置多个内容例如data-init="1,2,3,4"
* 修复键盘操作分页部分情况下会失效的问题
* 增加selectToCloseList参数用于设置在多选模式下选择项目后不关闭列表
* 修复selectToCloseList:false状态下键盘操作会失去焦点操作不连贯的问题
* 增加$.fn.selectPageClear的API用于清空控件所有已选中的项目
* 增加$.fn.selectPageText的API用于获得已选择的项目文本内容
* 增加$.fn.selectPageData的API用于动态修改插件数据源
* 增加$.fn.SelectedRefresh的API用于在使用.val()的方式修改了插件的选中项目后,刷新显示在输入框中的文本内容
* 优化控件内部对象缓存机制
* 去除快速使用脚本b.selectpage.js
* 初始化入口从原来的$('').bSelectPage({})修改为$('').selectPage({})
* 重新调整参数名称
* 修正Bootstrap3下控件宽度、高度应用的BUG
* 2017.08.19v2.2
* 增加为原始输入框的value属性设置初始化值以初始化插件选中项目
* 修复多选模式下关闭标签出错的问题
* 修复输入查询关键字后失去焦点,再次获得焦点时,插件没有根据已存在的关键进行过滤
* 增加inputDelay配置项目设置ajax数据源模式下延迟输入查询的时间避免在单位时间内连续输入发起的连续ajax查询单位默认值0.5
* 修正对数字类型的列进行排序时,仍然以字符串的方式进行排序
* 2017.08.23v2.3
* 修复在查询关键字状态下,分页数据没有被更新,导致分页按钮功能不正常问题
* 清理整理内部对象
* 修复多选模式下,若设置了最大选中项目个数,点击“全选本页”按钮时,仅选中指定的最大数量
* 增加selectpage.base.css兼容无UI框架的方案但建议要至少使用normalize.css
* 2017.08.26v2.4
* 增加pagination参数指定稿件是否使用分页加载数据以及显示分页栏
* 增加listSize参数指定了不使用分页的列表显示的高度单位为个选项个数默认显示10个项目的高度
* 设置selectOnly:true的情况下输入框为只读模式不允许输入查询过滤
* 修复多选模式下及设置了最大选中项目时,选中了项目再次点击“全选本页”按钮会在已选择的基础上增加最大选中项目个数的项目
* 调整下拉列表样式及位置
* 增加单选模式下,选中项目后,自动显示清空按钮
* 修复多选模式下,移除本页和清除所有两个按钮点击后,回调出错的问题
* 增加搜索无结果时显示提示信息
* 2017.09.07v2.5
* 修复多选模式下初始化项目的显示文本没有使用formatItem回调进行格式化
* 修复ajax数据源模式下输入查询关键字时翻页始终为第一页的问题
* 2017.09.07v2.6
* 修复单选模式下初始化项目的显示文本没有使用formatItem回调格式化的问题
* 修复单选模式存在初始化项目时,再打开下拉列表时,仅显示匹配的项目一条数据的问题
* 修复多选模式下动态修改选中值selectPageRefresh功能无效
* 2017.09.12v2.7
* 增加eClear回调单选模式下清除按钮的功能回调
* 单选,多选模式下,输入框禁用或只读状态,不显示清除按钮
* 2017.09.23v2.8
* 调整部分样式
* 修复可视区域高度较小时,列表始终会向上展开的问题
* 分离键盘事件处理,对键盘输入精准控制
* 优化区域外点击处理
* 优化数据展示渲染效率
* 优化列表位置定位的准确性
*/
;
(function (factory) {
if (typeof define === "function" && define.amd) {
// AMD模式
define(["jquery"], factory);
} else {
// 全局模式
factory(jQuery);
}
}(function ($) {
"use strict";
/**
* @desc 默认参数集
*/
var defaults = {
/**
* @desc 数据源(StringAjax查询的URL|ObjectJSON格式的数据源)
* @type {string|Object}
* @example
* string服务端请求的URL地址
* ObjectJSON格式数组推荐格式[{a:1,b:2,c:3},{...}]
*/
data: undefined,
/**
* @desc 插件显示语言 ('ja', 'en', 'es', 'pt-br'等)
* @type string 默认'cn'
*/
lang: 'cn',
/**
* @desc 是否为多选模式(标签模式)
* @type boolean 默认值false
*/
multiple: false,
/**
* @desc 是否分页
* @type boolean 默认值 true
*/
pagination: true,
/**
* @desc 关闭分页的状态下,列表显示的项目个数,其它的项目以滚动条滚动方式展现
* @type number 默认值 10
*/
listSize: 10,
/**
* @desc 是否启用多选模式的控制按钮区域
* 仅multiple: true模式下可用
* @type boolean 默认值true
*/
multipleControlbar: true,
/**
* @desc 多选模式下最大选择个数0为不限制
* @type number 默认0
*/
maxSelectLimit: 0,
/**
* @desc 选中项目后关闭列表
* 该设置仅在多选模式下multiple:true有效
* @type boolean 默认值true
*/
selectToCloseList: true,
/**
* @desc 插件初始值指定该值会与option.keyField字段进行匹配若匹配到则自动设置选中并高亮
* @type string
*/
initRecord: undefined,
/**
* @desc 使用ajax方式获取数据时使用该参数设置对应的数据表名
* @type string
*/
dbTable: 'tbl',
/**
* @desc 值字段,通常该字段的内容会自动保存在隐藏域中
* @type string 默认值为'id'
*/
keyField: 'id',
/**
* @desc 结果集中用于显示的属性名
* @type string 默认字段为'name'
*/
showField: 'name',
/**
* @desc 查询字段仅为使用URL(ajax)方式查询服务端时设置后端查询的字段不设置则默认使用showField设置的字段
* @type string
*/
searchField: undefined,
/**
* @desc 查询方式 ('AND' or 'OR')
* @type string 默认为'AND'
*/
andOr: 'AND',
/**
* @desc 数据排序方式
* @type array 若不设置则默认对showField指定的字段进行排序
* @example
* orderBy : ['id desc']//对ID字段进行降序排序
*/
orderBy: undefined,
/**
* @desc 每页显示的记录数
* @type number
*/
pageSize: 10,
/**
* @desc 使用URL进行AJAX查询时可传递查询参数
* @type function
* @return object
* @example params : function(){return {'name':'aa','sex':1};}
*/
params: undefined,
/**
* 列表项目显示内容格式化
* 参数类型function
* @type boolean
* @param data {object} 行数据object格式
* @return string
*/
formatItem: undefined,
/**
* 是否在输入框获得焦点时,展开下拉窗口
* @type boolean 默认值true
*/
focusDropList: true,
/**
* 是否自动选择列表中的第一项内容(输入关键字查询模式,直接使用鼠标下拉并不触发)
* @type boolean 默认值false
*/
autoSelectFirst: true,
/**
* 是否自动填充内容
* 若有列表项目被高亮显示,在焦点离开控件后,自动设置该项为选中内容
* @type boolean 默认值false
*/
autoFillResult: true,
/**
* 是否清空输入关键字
* 在输入框中输入内容进行查询,但没有匹配的内容返回,在焦点离开控件后,自动清空输入框输入的内容
* @type boolean 默认值false
*/
noResultClean: true,
/**
* @desc 只选择模式
* @type boolean
*/
selectOnly: false,
/**
* @desc 输入关键字查询延迟仅ajax数据源模式下可用
* @type number 默认值0.5秒
*/
inputDelay: 0.5,
/**
* -----------------------------------------事件回调--------------------------------------------
*/
/**
* @type function
* @param object
* @param dom
*/
eSelect: undefined,
/**
* ajax请求模式请求成功后的数据处理回调
* 回调的功能用于自定义处理服务端返回的数据
* @type function
* @param data {object} ajax服务端返回的json数据
* @return {object} 函数返回的数据结构如下:
* @example
* {
* list : [{name:'aa',sex:1},{name:'bb',sex:1}...],
* totalRow : 100
* }
*/
eAjaxSuccess: undefined,
/**
* 多选模式下,关闭标签是的回调函数
* @type function
* @param removeCount 被移除的个数
*/
eTagRemove: undefined,
/**
* 单选模式下,选中项目后的清除按钮功能回调
* @type function
*/
eClear: undefined
};
/**
* @constructor
* @classdesc 插件初始化
* @param {Object} input - 插件的初始化输入框元素。
* @param {Object} option - 初始化参数
*/
var SelectPage = function (input, option) {
var option = $.extend({}, option, $(input).data());
//特殊字段处理
$.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, option);
this.setButtonAttrDefault();
this.setInitRecord();
this.eDropdownButton();
this.eInput();
this.eWhole();
};
/**
* 插件版本号
*/
SelectPage.version = '2.7';
/**
* 插件缓存内部对象的KEY
*/
SelectPage.dataKey = 'selectPageObject';
/**
* 全局范围设置当前点击是否为插件自身的标识
*/
SelectPage.objStatusKey = 'selectPage-self-mark';
/**
* 全局范围设置当前点击的selectpage的索引下标
*/
SelectPage.objStatusIndex = 'selectPage-self-index';
/**
* @desc 参数初始化
* @param {Object} option - 参数集
*/
SelectPage.prototype.setOption = function (option) {
//若没有设置搜索字段,则使用显示字段作为搜索字段
option.searchField = (option.searchField === undefined) ? option.showField : option.searchField;
//统一大写
option.andOr = option.andOr.toUpperCase();
if (option.andOr !== 'AND' && option.andOr !== 'OR')
option.andOr = 'AND';
//将参数内容从使用","分隔的字符串转换为数组
var arr = ['searchField'];
for (var i = 0; i < arr.length; i++) {
option[arr[i]] = this.strToArray(option[arr[i]]);
}
//设置排序字段
option.orderBy = (option.orderBy === undefined) ? option.searchField : option.orderBy;
//设置多字段排序
//例: [ ['id', 'ASC'], ['name', 'DESC'] ]
option.orderBy = this.setOrderbyOption(option.orderBy, option.showField);
//多选模式下,若设置了选择项目不关闭列表功能,则强制关闭自动选择第一项功能和自动选中高亮的项目功能
//原因是打开了会总是莫明选择了第一项,体验不佳
if (option.multiple && !option.selectToCloseList) {
option.autoFillResult = false;
option.autoSelectFirst = false;
}
if ($.type(option.data) === 'string') {
option.autoSelectFirst = false;
}
//若不需要分页功能则将所有数据都显示出来上限200项
if (!option.pagination)
option.pageSize = 200;
if ($.type(option.listSize) !== 'number' || option.listSize < 0)
option.listSize = 10;
this.option = option;
};
/**
* @desc 字符串转换为数组
* @param str {string} - 字符串
* @return {Array} - 数组
*/
SelectPage.prototype.strToArray = function (str) {
if (!str)
return '';
return str.replace(/[\s ]+/g, '').split(',');
};
/**
* @desc 设置多字段排序
* @param {Array} arg_order - 排序顺序
* @param {string} arg_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(' ');
arr[i] = (orders.length == 2) ? orders : [orders[0], 'ASC'];
}
} else {
orders = $.trim(arg_order).split(' ');
arr[0] = (orders.length == 2) ? orders : (orders[0].match(/^(ASC|DESC)$/i)) ? [arg_field, orders[0]] : [orders[0], 'ASC'];
}
return arr;
};
/**
* @desc 界面文字国际化
*/
SelectPage.prototype.setLanguage = function () {
var message;
switch (this.option.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' + this.option.pageSize + ' (Pfeil-rechts)',
prev: 'Vorherigen',
prev_title: 'Vorherigen' + this.option.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: 'num_page_top - num_page_end von cnt_whole',
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.'
};
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' + this.option.pageSize + ' (Right key)',
prev: 'Prev',
prev_title: 'Prev' + this.option.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: 'num_page_top - num_page_end of cnt_whole',
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.'
};
break;
// 中文
case 'cn':
message = {
add_btn: '添加按钮',
add_title: '添加区域',
del_btn: '删除按钮',
del_title: '删除区域',
next: '下一页',
next_title: '下' + this.option.pageSize + ' (→)',
prev: '上一页',
prev_title: '上' + this.option.pageSize + ' (←)',
first_title: '首页 (Shift + ←)',
last_title: '尾页 (Shift + →)',
get_all_btn: '获得全部 (↓)',
get_all_alt: '(按钮)',
close_btn: '关闭 (Tab键)',
close_alt: '(按钮)',
loading: '读取中...',
loading_alt: '(读取中)',
page_info: 'num_page_top - num_page_end (共 cnt_whole)',
select_ng: '请注意:请从列表中选择.',
select_ok: 'OK : 已经选择.',
not_found: '无查询结果',
ajax_error: '连接到服务器时发生错误!'
};
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 ' + this.option.pageSize + ' (tecla derecha)',
prev: 'Anterior',
prev_title: 'Anteriores ' + this.option.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: 'num_page_top - num_page_end de cnt_whole',
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.'
};
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 ' + this.option.pageSize + ' (tecla direita)',
prev: 'Anterior',
prev_title: 'Anterior ' + this.option.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: 'num_page_top - num_page_end de cnt_whole',
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.'
};
break;
// Japanese
case 'ja':
message = {
add_btn: '追加ボタン',
add_title: '入力ボックスを追加します',
del_btn: '削除ボタン',
del_title: '入力ボックスを削除します',
next: '次へ',
next_title: '次の' + this.option.pageSize + '件 (右キー)',
prev: '前へ',
prev_title: '前の' + this.option.pageSize + '件 (左キー)',
first_title: '最初のページへ (Shift + 左キー)',
last_title: '最後のページへ (Shift + 右キー)',
get_all_btn: '全件取得 (下キー)',
get_all_alt: '画像:ボタン',
close_btn: '閉じる (Tabキー)',
close_alt: '画像:ボタン',
loading: '読み込み中...',
loading_alt: '画像:読み込み中...',
page_info: 'num_page_top - num_page_end 件 (全 cnt_whole 件)',
select_ng: '注意 : リストの中から選択してください',
select_ok: 'OK : 正しく選択されました。',
not_found: '(0 件)',
ajax_error: 'サーバとの通信でエラーが発生しました。'
};
break;
}
this.message = message;
};
/**
* @desc CSS样式表名称字义
*/
SelectPage.prototype.setCssClass = function () {
var css_class = {
container: 'sp_container',
// SelectPage最外层DIV的打开状态
container_open: 'sp_container_open',
re_area: 'sp_result_area',
control_box: 'sp_control_box',
//标签及输入框的
element_box: 'sp_element_box',
// 分页导航
navi: 'pagination',
// 下拉结果列表
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',
btn_on: 'sp_btn_on',
btn_out: 'sp_btn_out',
input: 'sp_input',
clear_btn: 'sp_clear_btn'
};
this.css_class = css_class;
};
/**
* @desc 设置属性默认值
*/
SelectPage.prototype.setProp = function () {
this.prop = {
//当前页
current_page: 1,
//总页数
max_page: 1,
//是否正在Ajax请求
is_loading: false,
xhr: false,
//使用键盘进行分页
key_paging: false,
//使用键盘进行选择
key_select: false,
//上一个选择的项目值
prev_value: '',
//选中项目的文本内容
selected_text: '',
//上一次键盘输入的时间
last_input_time: undefined
};
this.template = {
tag: {
content: '<li class="selected_tag" itemvalue="#item_value#">#item_text#<span class="tag_close">×</span></li>',
textKey: '#item_text#',
valueKey: '#item_value#'
}
};
};
/**
* @desc 插件HTML结构生成
* @param {Object} combo_input - 输入框源对象
* @param {Object} option - 插件参数
*/
SelectPage.prototype.setElem = function (combo_input, option) {
// 1. 生成、替换DOM对象
var elem = {};//本体
var orgWidth = $(combo_input).outerWidth();
elem.combo_input = $(combo_input).attr({'autocomplete': 'off'}).addClass(this.css_class.input).wrap('<div>');
//只选择模式设置输入框为只读状态
if (option.selectOnly)
$(elem.combo_input).prop('readonly', true);
elem.container = $(elem.combo_input).parent().addClass(this.css_class.container);
if ($(elem.combo_input).prop('disabled')) {
if (option.multiple)
$(elem.container).addClass(this.css_class.disabled);
else
$(elem.combo_input).addClass(this.css_class.input_off);
}
//$(elem.container).width(orgWidth);
elem.button = $('<div>').addClass(this.css_class.button);
//bootstrap风格的向下三角箭头
elem.dropdown = $('<span class="bs-caret"><span class="caret"></span></span>');
//单选模式下清除的按钮X
elem.clear_btn = $('<div>').append('×').addClass(this.css_class.clear_btn).attr('title', '清除内容');
//多选模式下带标签显示及文本输入的组合框
elem.element_box = $('<ul>').addClass(this.css_class.element_box);
if (option.multiple && option.multipleControlbar)
elem.control = $('<div>').addClass(this.css_class.control_box);
//结果集列表
elem.result_area = $('<div>').addClass(this.css_class.re_area);
//列表中的分页栏pagination
if (option.pagination)
elem.navi = $('<ul>').addClass(this.css_class.navi).addClass("hide");
elem.results = $('<ul>').addClass(this.css_class.results);
/**
* 将原输入框的Name交换到Hidden中因为具体需要保存传递到后端的是ID而非Title
*/
var namePrefix = '_text';
//将keyField的值放入"input:hidden"
var input_id = ($(elem.combo_input).attr('id') !== undefined) ? $(elem.combo_input).attr('id') : $(elem.combo_input).attr('name');
var input_name = ($(elem.combo_input).attr('name') !== undefined) ? $(elem.combo_input).attr('name') : 'selectPage';
var hidden_name = input_name,
hidden_id = input_id;
// CakePHP使用的措施 例:data[search][user] -> data[search][user_primary_key]
if (input_name.match(/\]$/))
input_name = input_name.replace(/\]?$/, namePrefix);
else
input_name += namePrefix;
if (input_id.match(/\]$/))
input_id = input_id.replace(/\]?$/, namePrefix);
else
input_id += namePrefix;
//将输入框的Name与Hidden的Name进行交换使得可以将项目的具体ID被保存到后端进行处理
elem.hidden = $('<input type="hidden" class="sp_hidden" />').attr({
name: hidden_name,
id: hidden_id
}).val('');
$(elem.combo_input).attr({
name: input_name,
id: input_id
});
// 2. DOM内容放置
$(elem.container).append(elem.button).append(elem.result_area).append(elem.hidden);
$(elem.button).append(elem.dropdown);
$(elem.result_area).append(elem.results);
if (option.pagination)
$(elem.result_area).append(elem.navi);
//多选模式下的特殊处理
if (option.multiple) {
if (option.multipleControlbar) {
$(elem.control).append('<button type="button" class="btn btn-default sp_select_all" ><i class="fa fa-check-square-o"></i> 全选本页</button>');
$(elem.control).append('<button type="button" class="btn btn-default sp_unselect_all" ><i class="fa fa-square-o"></i> 取消本页</button>');
$(elem.control).append('<button type="button" class="btn btn-default sp_clear_all" ><i class="fa fa-ban"></i> 清除全部</button>');
$(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 = $('<li>').addClass('input_box');
$(li).append($(elem.combo_input));
$(elem.element_box).append($(li));
if ($(elem.combo_input).attr('placeholder'))
$(elem.combo_input).attr('placeholder_bak', $(elem.combo_input).attr('placeholder'));
}
if ($(elem.container).parent().hasClass("input-group")) {
$(elem.container).height($(elem.container).parent().height());
}
this.elem = elem;
};
/**
* @desc 将控件的部分内容设置为默认状态
*/
SelectPage.prototype.setButtonAttrDefault = function () {
/*
if (this.option.selectOnly) {
if ($(this.elem.combo_input).val() !== '') {
if ($(this.elem.hidden).val() !== '') {
//选择条件
$(this.elem.combo_input).attr('title', this.message.select_ok).removeClass(this.css_class.select_ng).addClass(this.css_class.select_ok);
} else {
//输入方式
$(this.elem.combo_input).attr('title', this.message.select_ng).removeClass(this.css_class.select_ok).addClass(this.css_class.select_ng);
}
} else {
$(this.elem.hidden).val('');
$(this.elem.combo_input).removeAttr('title').removeClass(this.css_class.select_ng);
}
}
*/
$(this.elem.button).attr('title', this.message.get_all_btn);
//按钮的title属性修改
$(this.elem.button).attr('title', this.message.close_btn);
};
/**
* @desc 为插件设置初始化的选中值(若有指定的话),执行第一步,数据匹配
*/
SelectPage.prototype.setInitRecord = function (refresh) {
var self = this;
if ($.type($(self.elem.combo_input).data('init')) != 'undefined')
self.option.initRecord = String($(self.elem.combo_input).data('init'));
//若在输入框中放入了初始化值,则将它放到隐藏域中进行选中项目初始化
//若输入框设置了初始值同时又设置了data-init属性那么以data-init属性为优先选择
if (!self.option.initRecord)
if ($(self.elem.combo_input).val())
self.option.initRecord = $(self.elem.combo_input).val();
$(self.elem.combo_input).val('');
if ((refresh && $(self.elem.hidden).val()) || $.type(self.option.initRecord) === 'string') {
// 初始的KEY值放入隐藏域
if (!refresh)
$(self.elem.hidden).val(self.option.initRecord);
//将初始值放入控件
if (typeof self.option.data === 'object') {//json数据源模式
var data = new Array();
var keyarr = refresh ? $(self.elem.hidden).val().split(',') : self.option.initRecord.split(',');
$.each(keyarr, function (index, row) {
for (var i = 0; i < self.option.data.length; i++) {
if (self.option.data[i][self.option.keyField] == row) {
data.push(self.option.data[i]);
break;
}
}
});
//在单选模式下若使用了多选模式的初始化值“key1,key2,...”多选方式),则不进行初始化选中操作
if (!self.option.multiple && data.length > 1)
data = null;
self.afterInit(self, data);
} else {//ajax数据源模式
$.ajax({
dataType: 'json',
type: 'POST',
url: self.option.data,
data: {
searchTable: self.option.dbTable,
searchKey: self.option.keyField,
searchValue: refresh ? $(self.elem.hidden).val() : self.option.initRecord,
field: self.option.showField,
order_by: self.option.orderBy,
pkey_name: self.option.keyField,
pkey_value: refresh ? $(self.elem.hidden).val() : self.option.initRecord
},
success: function (returnData) {
var data;
if (self.option.eAjaxSuccess && $.isFunction(self.option.eAjaxSuccess)) {
data = self.option.eAjaxSuccess(returnData);
} else {
data = returnData;
}
self.afterInit(self, typeof data.rows !== 'undefined' ? data.rows : (typeof data.list !== 'undefined' ? data.list : []));
},
error: function (jqXHR, textStatus, errorThrown) {
self.ajaxErrorNotify(self, errorThrown);
}
});
}
}
};
/**
* @desc 匹配后的数据在插件中进行展示
* @param {Object} self - 插件的内部对象
* @param {Object} data - 列表数据
*/
SelectPage.prototype.afterInit = function (self, data) {
if (!data)
return;
if (!$.isArray(data))
data = [data];
if (data.length === 0)
return;
var getText = function (row) {
var text = row[self.option.showField];
if (self.option.formatItem && $.isFunction(self.option.formatItem)) {
try {
text = self.option.formatItem(row);
} catch (e) {
}
}
return text;
};
if (self.option.multiple) {//多选模式初始化
self.clearAll(self);
$.each(data, function (i, row) {
var item = {text: getText(row), value: row[self.option.keyField]};
if (!self.isAlreadySelected(self, item))
self.addNewTag(self, item);
});
self.tagValuesSet(self);
self.inputResize(self);
} else {//单选模式初始化
var row = data[0];
$(self.elem.combo_input).val(getText(row));
$(self.elem.hidden).val(row[self.option.keyField]);
self.prop.prev_value = getText(row);
self.prop.selected_text = getText(row);
if (self.option.selectOnly) {
$(self.elem.combo_input).attr('title', self.message.select_ok).removeClass(self.css_class.select_ng).addClass(self.css_class.select_ok);
}
self.putClearButton();
}
};
/**
* @desc 下拉按钮的事件处理
*/
SelectPage.prototype.eDropdownButton = function () {
var self = this;
$(self.elem.button).mouseup(function (ev) {
ev.stopPropagation();
if ($(self.elem.result_area).is(':hidden') && !$(self.elem.combo_input).prop('disabled')) {
$(self.elem.combo_input).focus();
} else
self.hideResults(self);
}).mouseout(); // default: mouseout
};
/**
* @desc 输入框的事件绑定
*/
SelectPage.prototype.eInput = function () {
var self = this;
var showList = function () {
self.prop.page_move = false;
self.suggest(self);
self.setCssFocusedInput(self);
};
$(self.elem.combo_input).keyup(function (e) {
self.processKey(self, e);
}).keydown(function (e) {
self.processControl(self, e);
}).focus(function (e) {
//增加输入框获得焦点后,显示数据列表
if ($(self.elem.result_area).is(':hidden')) {
e.stopPropagation();
self.prop.first_show = true;
showList();
}
});
$(self.elem.container).on('click.SelectPage', 'div.' + self.css_class.clear_btn, function (e) {
e.stopPropagation();
self.clearAll(self);
$(self.elem.clear_btn).remove();
if (self.option.eClear && $.isFunction(self.option.eClear))
self.option.eClear();
});
if (self.option.multiple) {
if (self.option.multipleControlbar) {
//全选本页按钮
$('.sp_select_all', self.elem.control).on('click.SelectPage', function (e) {
self.selectAllLine(self);
});
//取消全选本页按钮
$('.sp_unselect_all', self.elem.control).on('click.SelectPage', function (e) {
self.unselectAllLine(self);
});
//清除全部按钮
$('.sp_clear_all', self.elem.control).on('click.SelectPage', function (e) {
self.clearAll(self);
});
}
$(self.elem.element_box).on('click.SelectPage', function (e) {
var srcEl = e.target || e.srcElement;
if ($(srcEl).is('ul'))
$(self.elem.combo_input).focus();
});
//标签关闭操作
//关闭同时需要将该标签的key从已保存的隐藏域中删除
$(self.elem.element_box).on('click.SelectPage', 'span.tag_close', function () {
var li = $(this).closest('li');
self.removeTag(self, li);
showList();
if (self.option.eTagRemove && $.isFunction(self.option.eTagRemove))
self.option.eTagRemove(1);
});
self.inputResize(self);
}
};
/**
* 插件之外区域的事件处理
*/
SelectPage.prototype.eWhole = function () {
var self = this;
/*
//如果是点击了控件本身则不响应外部鼠标点击事件
$(self.elem.container).mousedown(function() {
var thisindex = $('div.sp_container').index(this);
var lastindex = $(document.body).data(SelectPage.objStatusIndex);
if(lastindex != undefined && thisindex != lastindex)
$(document.body).data(SelectPage.objStatusKey,false);
else
$(document.body).data(SelectPage.objStatusKey,true);
$(document.body).data(SelectPage.objStatusIndex,thisindex);
});
*/
//控件外部的鼠标点击事件处理
$(document).off('mousedown.selectPage').on('mousedown.selectPage', function (e) {
var ele = e.target || e.srcElement;
var sm = $(ele).closest('div.' + self.css_class.container);
//清除内容
var cleanContent = function (obj) {
$(obj.elem.combo_input).val('');
if (!obj.option.multiple)
$(obj.elem.hidden).val('');
obj.prop.selected_text = '';
};
//列表是打开的状态
$('div.' + self.css_class.container + '.' + self.css_class.container_open).each(function () {
if (this == sm[0])
return;
var d = $('input.' + self.css_class.input, this).data(SelectPage.dataKey);
//若控件已有选中的的项目,而文本输入框中清空了关键字,则清空控件已选中的项目
if (!$(d.elem.combo_input).val() && $(d.elem.hidden).val() && !d.option.multiple) {
d.prop.current_page = 1;//重置当前页为1
cleanContent(d);
d.hideResults(d);
return true;
}
//匹配项且高亮时,下拉分页控件失去焦点后,自动选择该项目
if ($('li', $(d.elem.results)).size() > 0) {
if (d.option.autoFillResult) {//打开自动内容填充功能
//若已有选中项目,则直接隐藏列表
if ($('li.sp_selected', $(d.elem.results)).size() > 0) {
d.hideResults(d);
} else if ($('li.sp_over', $(d.elem.results)).size() > 0) {
//若控件已有选中的值,则忽略高亮的项目
if ($(d.elem.hidden).val())
d.hideResults(d);
//若没有已选中的项目,且列表中有高亮项目时,选中当前高亮的行
else
d.selectCurrentLine(d, true);
} else if (d.option.autoSelectFirst) {
//若控件已有选中的值,则忽略自动选择第一项的功能
if ($(d.elem.hidden).val())
d.hideResults(d);
else {
//对于没有选中,没有高亮的情况,若插件设置了自动选中第一项时,则选中第一项
d.nextLine(d);
//self.nextLine(self);
d.selectCurrentLine(d, true);
}
} else
d.hideResults(d);
} else
d.hideResults(d);
} else {
//无匹配项目时,自动清空用户输入的关键词
if (d.option.noResultClean)
cleanContent(d);
else {
if (!d.option.multiple)
$(d.elem.hidden).val('');
}
d.hideResults(d);
}
});
/*
if ($(document.body).data(SelectPage.objStatusKey)) $(document.body).data(SelectPage.objStatusKey,false);
else {
//清除内容
var cleanContent = function(obj){
$(obj.elem.combo_input).val('');
if(!obj.option.multiple) $(obj.elem.hidden).val('');
obj.prop.selected_text = '';
};
//列表是打开的状态
$('div.' + self.css_class.container + '.' + self.css_class.container_open).each(function(){
var d = $('input.'+self.css_class.input,this).data(SelectPage.dataKey);
//若控件已有选中的的项目,而文本输入框中清空了关键字,则清空控件已选中的项目
if(!$(d.elem.combo_input).val() && $(d.elem.hidden).val() && !d.option.multiple){
d.prop.current_page = 1;//重置当前页为1
cleanContent(d);
d.hideResults(d);
return true;
}
//匹配项且高亮时,下拉分页控件失去焦点后,自动选择该项目
if ($('li', $(d.elem.results)).size() > 0) {
if(d.option.autoFillResult) {//打开自动内容填充功能
//若已有选中项目,则直接隐藏列表
if ($('li.sp_selected', $(d.elem.results)).size() > 0) {
d.hideResults(d);
}else if($('li.sp_over', $(d.elem.results)).size() > 0){
//若控件已有选中的值,则忽略高亮的项目
if($(d.elem.hidden).val()) d.hideResults(d);
//若没有已选中的项目,且列表中有高亮项目时,选中当前高亮的行
else d.selectCurrentLine(d, true);
}else if(d.option.autoSelectFirst){
//若控件已有选中的值,则忽略自动选择第一项的功能
if($(d.elem.hidden).val()) d.hideResults(d);
else{
//对于没有选中,没有高亮的情况,若插件设置了自动选中第一项时,则选中第一项
d.nextLine(d);
//self.nextLine(self);
d.selectCurrentLine(d, true);
}
}else d.hideResults(d);
}else d.hideResults(d);
} else {
//无匹配项目时,自动清空用户输入的关键词
if (d.option.noResultClean) cleanContent(d);
else{
if(!d.option.multiple) $(d.elem.hidden).val('');
}
d.hideResults(d);
}
});
}
*/
});
};
/**
* @desc 结果列表的事件处理
*/
SelectPage.prototype.eResultList = function () {
var self = this;
$(self.elem.results).children('li').mouseenter(function () {
if (self.prop.key_select) {
self.prop.key_select = false;
return;
}
if (!$(this).hasClass(self.css_class.selected) && !$(this).hasClass('sp_message_box')) {
$(this).addClass(self.css_class.select);
self.setCssFocusedResults(self);
}
}).mouseleave(function () {
$(this).removeClass(self.css_class.select);
}).click(function (e) {
if (self.prop.key_select) {
self.prop.key_select = false;
return;
}
e.preventDefault();
e.stopPropagation();
if (!$(this).hasClass(self.css_class.selected))
self.selectCurrentLine(self, false);
});
};
/**
* @desc 分页导航按钮的事件处理
*/
SelectPage.prototype.ehNaviPaging = function () {
var self = this;
if (!self.option.pagination)
return;
$('li.csFirstPage', $(self.elem.navi)).off('click').on('click', function (ev) {
//$(self.elem.combo_input).focus();
ev.preventDefault();
self.firstPage(self);
});
$('li.csPreviousPage', $(self.elem.navi)).off('click').on('click', function (ev) {
//$(self.elem.combo_input).focus();
ev.preventDefault();
self.prevPage(self);
});
$('li.csNextPage', $(self.elem.navi)).off('click').on('click', function (ev) {
//$(self.elem.combo_input).focus();
ev.preventDefault();
self.nextPage(self);
});
$('li.csLastPage', $(self.elem.navi)).off('click').on('click', function (ev) {
//$(self.elem.combo_input).focus();
ev.preventDefault();
self.lastPage(self);
});
};
/**
* @desc Ajax请求失败的处理
* @param {Object} self - 插件内部对象
* @param {string} errorThrown - Ajax的错误输出内容
*/
SelectPage.prototype.ajaxErrorNotify = function (self, errorThrown) {
self.showMessage(self.message.ajax_error);
};
/**
* @desc 交互消息显示
* @param {Object} self - 插件内部对象
* @param msg {string} 需要提示的文本
*/
SelectPage.prototype.showMessage = function (self, msg) {
if (!msg)
return;
var msgLi = '<li class="sp_message_box"><i class="fa fa-exclamation-triangle"></i> ' + msg + '</li>';
$(self.elem.results).empty().append(msgLi);
self.calcResultsSize(self);
$(self.elem.container).addClass(self.css_class.container_open);
$(self.elem.control).hide();
if (self.option.pagination)
$(self.elem.navi).hide();
};
/**
* @desc 窗口滚动处理
* @param {Object} self - 插件内部对象
* @param {boolean} enforce - 是否定位到输入框的位置
*/
SelectPage.prototype.scrollWindow = function (self, enforce) {
var current_result = self.getCurrentLine(self);
var target_top = (current_result && !enforce) ? current_result.offset().top : $(self.elem.container).offset().top;
var target_size;
self.prop.size_li = $(self.elem.results).children('li:first').outerHeight();
target_size = self.prop.size_li;
var client_height = $(window).height();
var scroll_top = $(window).scrollTop();
var scroll_bottom = scroll_top + client_height - target_size;
// 滚动处理
var gap;
if ($(current_result).length) {
if (target_top < scroll_top || target_size > client_height) {
//滚动到顶部
gap = target_top - scroll_top;
} else if (target_top > scroll_bottom) {
//向下滚动
gap = target_top - scroll_bottom;
} else
return; //不进行滚动
} else if (target_top < scroll_top)
gap = target_top - scroll_top;
window.scrollBy(0, gap);
};
/**
* @desc 输入框获得焦点的样式设置
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.setCssFocusedInput = function (self) {
//$(self.elem.results).addClass(self.css_class.re_off);
//$(self.elem.combo_input).removeClass(self.css_class.input_off);
};
/**
* @desc 设置结果列表高亮,输入框失去焦点
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.setCssFocusedResults = function (self) {
//$(self.elem.results).removeClass(self.css_class.re_off);
//$(self.elem.combo_input).addClass(self.css_class.input_off);
};
/**
* @desc 输入框输入值的变化监控
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.checkValue = function (self) {
var now_value = $(self.elem.combo_input).val();
if (now_value != self.prop.prev_value) {
self.prop.prev_value = now_value;
self.prop.first_show = false;
if (self.option.selectOnly)
self.setButtonAttrDefault();
if (!self.option.multiple && !now_value) {
self.clearAll(self);
$(self.elem.clear_btn).remove();
}
self.suggest(self);
}
};
/**
* @desc 文本输入框键盘事件处理(普通字符输入处理)
* @param {Object} self - 插件内部对象
* @param {Object} e - 事件event对象
*/
SelectPage.prototype.processKey = function (self, e) {
if ($.inArray(e.keyCode, [37, 38, 39, 40, 27, 9, 13]) === -1) {
if (e.keyCode != 16)
self.setCssFocusedInput(self); // except Shift(16)
self.inputResize(self);
if ($.type(self.option.data) === 'string') {
self.prop.last_input_time = e.timeStamp;
setTimeout(function () {
if ((e.timeStamp - self.prop.last_input_time) === 0)
self.checkValue(self);
}, self.option.inputDelay * 1000);
} else {
self.checkValue(self);
}
}
}
/**
* @desc 文本输入框键盘事件处理(控制键处理)
* @param {Object} self - 插件内部对象
* @param {Object} e - 事件event对象
*/
SelectPage.prototype.processControl = function (self, e) {
if (($.inArray(e.keyCode, [37, 38, 39, 40, 27, 9]) > -1 && $(self.elem.result_area).is(':visible')) ||
($.inArray(e.keyCode, [13, 9]) > -1 && self.getCurrentLine(self))) {
e.preventDefault();
e.stopPropagation();
e.cancelBubble = true;
e.returnValue = false;
switch (e.keyCode) {
case 37:
// left
if (e.shiftKey)
self.firstPage(self);
else
self.prevPage(self);
break;
case 38:
// up
self.prop.key_select = true;
self.prevLine(self);
break;
case 39:
// right
if (e.shiftKey)
self.lastPage(self);
else
self.nextPage(self);
break;
case 40:
// down
if ($(self.elem.results).children('li').length) {
self.prop.key_select = true;
self.nextLine(self);
} else
self.suggest(self);
break;
case 9:
// tab
self.prop.key_paging = true;
self.selectCurrentLine(self, true);
//self.hideResults(self);
break;
case 13:
// return
self.selectCurrentLine(self, true);
break;
case 27:
// escape
self.prop.key_paging = true;
self.hideResults(self);
break;
}
}
};
/**
* @desc 中断Ajax请求
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.abortAjax = function (self) {
if (self.prop.xhr) {
self.prop.xhr.abort();
self.prop.xhr = false;
}
};
/**
* @desc 数据查询
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.suggest = function (self) {
//搜索关键字
var q_word;
var val = $.trim($(self.elem.combo_input).val());
if (self.option.multiple)
q_word = val;
else {
if (val && val === self.prop.selected_text)
q_word = '';
else
q_word = val;
}
q_word = q_word.split(/[\s ]+/);
self.abortAjax(self);
self.setLoading(self);
var which_page_num = self.prop.current_page > 0 ? self.prop.current_page : 1;
// 数据查询
if (typeof self.option.data == 'object')
self.searchForJson(self, q_word, which_page_num);
else
self.searchForDb(self, q_word, which_page_num);
};
/**
* @private
* @desc 读取中状态显示
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.setLoading = function (self) {
//加载中的状态提示
if ($(self.elem.results).html() === '') {
//self.calcResultsSize(self);
$(self.elem.container).addClass(self.css_class.container_open);
}
};
/**
* @desc 服务端数据查询
* @param {Object} self - 插件内部对象
* @param {Array} q_word - 查询关键字
* @param {number} which_page_num - 目标页
*/
SelectPage.prototype.searchForDb = function (self, q_word, which_page_num) {
if (!self.option.eAjaxSuccess || !$.isFunction(self.option.eAjaxSuccess))
self.hideResults(self);
/**
* 增加自定义查询参数
*/
var _paramsFunc = self.option.params;
var _params = {};
//原始参数
var searchKey = self.option.searchField;
//若有查询关键字则重置当前页码为1
if (q_word.length > 0 && q_word[0] && q_word[0] !== self.prop.prev_value)
which_page_num = 1;
var _orgParams = {
q_word: q_word,
pageNumber: which_page_num,
pageSize: self.option.pageSize,
andOr: self.option.andOr,
orderBy: self.option.orderBy,
searchTable: self.option.dbTable,
page: which_page_num,
per_page: self.option.pageSize,
and_or: self.option.andOr,
order_by: self.option.orderBy,
field: self.option.showField,
pkey_name: self.option.keyField,
search_field: searchKey
};
_orgParams[searchKey] = q_word[0];
if (_paramsFunc) {
var result = $.isFunction(_paramsFunc) ? _paramsFunc() : _paramsFunc;
if (result && $.isPlainObject(result)) {
_params = $.extend({}, _orgParams, result);
} else {
_params = _orgParams;
}
} else {
_params = _orgParams;
}
//增加自定义查询参数End
self.prop.xhr = $.ajax({
dataType: 'json',
url: self.option.data,
type: 'POST',
data: _params,
success: function (returnData) {
if (!returnData || !$.isPlainObject(returnData)) {
self.hideResults(self);
self.ajaxErrorNotify(self);
return;
}
var data;
if (self.option.eAjaxSuccess && $.isFunction(self.option.eAjaxSuccess)) {
data = self.option.eAjaxSuccess(returnData);
} else {
data = returnData;
}
//数据结构处理
var json = {};
json.originalResult = typeof data.rows !== 'undefined' ? data.rows : (typeof data.list !== 'undefined' ? data.list : []);
json.cnt_whole = typeof data.total !== 'undefined' ? data.total : (typeof data.totalRow !== 'undefined' ? data.totalRow : data.list.length);
json.candidate = [];
json.keyField = [];
if (typeof json.originalResult != 'object') {
self.prop.xhr = null;
self.notFoundSearch(self);
return;
}
json.cnt_page = json.originalResult.length;
for (var i = 0; i < json.cnt_page; i++) {
for (var key in json.originalResult[i]) {
if (key == self.option.keyField) {
json.keyField.push(json.originalResult[i][key]);
}
if (key == self.option.showField) {
json.candidate.push(json.originalResult[i][key]);
}
}
}
self.prepareResults(self, json, q_word, which_page_num);
},
error: function (jqXHR, textStatus, errorThrown) {
if (textStatus != 'abort') {
self.hideResults(self);
self.ajaxErrorNotify(self, errorThrown);
}
},
complete: function () {
self.prop.xhr = null;
}
});
};
/**
* @desc 对JSON源数据进行搜索
* @param {Object} self - 插件内部对象
* @param {Array} q_word - 搜索关键字
* @param {number} which_page_num - 目标页数
*/
SelectPage.prototype.searchForJson = function (self, q_word, which_page_num) {
var matched = [];
var esc_q = [];
var sorted = [];
var json = {};
var i = 0;
var arr_reg = [];
//查询条件过滤
do {
//'/\W/g'正则代表全部不是字母,数字,下划线,汉字的字符
//将非法字符进行转义
esc_q[i] = q_word[i].replace(/\W/g, '\\$&').toString();
arr_reg[i] = new RegExp(esc_q[i], 'gi');
i++;
} while (i < q_word.length);
// SELECT * FROM data WHERE field LIKE q_word;
for (i = 0; i < self.option.data.length; i++) {
var flag = false;
var row = self.option.data[i];
for (var j = 0; j < arr_reg.length; j++) {
var itemText = row[self.option.showField];//默认获取showField字段的文本
if (self.option.formatItem && $.isFunction(self.option.formatItem))
itemText = self.option.formatItem(row);
if (itemText.match(arr_reg[j])) {
flag = true;
if (self.option.andOr == 'OR')
break;
} else {
flag = false;
if (self.option.andOr == 'AND')
break;
}
}
if (flag)
matched.push(row);
}
// (CASE WHEN ...) 然后 く order 指定列
var reg1 = new RegExp('^' + esc_q[0] + '$', 'gi');
var reg2 = new RegExp('^' + esc_q[0], 'gi');
var matched1 = [];
var matched2 = [];
var matched3 = [];
for (i = 0; i < matched.length; i++) {
var orderField = self.option.orderBy[0][0];
var orderValue = String(matched[i][orderField]);
if (orderValue.match(reg1)) {
matched1.push(matched[i]);
} else if (orderValue.match(reg2)) {
matched2.push(matched[i]);
} else {
matched3.push(matched[i]);
}
}
if (self.option.orderBy[0][1].match(/^asc$/i)) {
matched1 = self.sortAsc(self, matched1);
matched2 = self.sortAsc(self, matched2);
matched3 = self.sortAsc(self, matched3);
} else {
matched1 = self.sortDesc(self, matched1);
matched2 = self.sortDesc(self, matched2);
matched3 = self.sortDesc(self, matched3);
}
sorted = sorted.concat(matched1).concat(matched2).concat(matched3);
//若没有匹配项目,则结束搜索
/*
if (sorted.length === undefined || sorted.length === 0 ) {
self.notFoundSearch(self);
return;
}
*/
json.cnt_whole = sorted.length;
//page_move参数用于区别数据加载是在初始化列表还是在进行分页的翻页操作
if (!self.prop.page_move) {
//仅单选模式进行选中项目定位页功能
if (!self.option.multiple) {
//若控件当前已有选中值,则获得该项目所在的页数,并跳转到该页进行显示
var currentValue = $(self.elem.hidden).val();
if ($.type(currentValue) !== 'undefined' && $.trim(currentValue) !== '') {
var index = 0;
$.each(sorted, function (i, row) {
if (row[self.option.keyField] == currentValue) {
index = i + 1;
return false;
}
});
which_page_num = Math.ceil(index / self.option.pageSize);
if (which_page_num < 1)
which_page_num = 1;
self.prop.current_page = which_page_num;
}
}
} else {
//过滤后的数据个数不足一页显示的个数时,强制设置页码
if (sorted.length <= ((which_page_num - 1) * self.option.pageSize)) {
which_page_num = 1;
self.prop.current_page = 1;
}
}
// LIMIT xx OFFSET xx
var start = (which_page_num - 1) * self.option.pageSize;
var end = start + self.option.pageSize;
//储存原始行数据,包括所有属性
json.originalResult = [];
// 查询后的数据处理
for (i = start; i < end; i++) {
if (sorted[i] === undefined)
break;
json.originalResult.push(sorted[i]);
for (var key in sorted[i]) {
if (key == self.option.keyField) {
if (json.keyField === undefined)
json.keyField = [];
json.keyField.push(sorted[i][key]);
}
if (key == self.option.showField) {
if (json.candidate === undefined)
json.candidate = [];
json.candidate.push(sorted[i][key]);
}
}
}
if (json.candidate === undefined)
json.candidate = [];
json.cnt_page = json.candidate.length;
self.prepareResults(self, json, q_word, which_page_num);
};
/**
* @desc 升序排序
* @param {Object} self - 插件内部对象
* @param {Array} arr - 结果集数组
*/
SelectPage.prototype.sortAsc = function (self, arr) {
arr.sort(function (a, b) {
var valA = a[self.option.orderBy[0][0]];
var valB = b[self.option.orderBy[0][0]];
return $.type(valA) === 'number' ? valA - valB : String(valA).localeCompare(String(valB));
});
return arr;
};
/**
* @desc 降序排序
* @param {Object} self - 插件内部对象
* @param {Array} arr - 结果集数组
*/
SelectPage.prototype.sortDesc = function (self, arr) {
arr.sort(function (a, b) {
var valA = a[self.option.orderBy[0][0]];
var valB = b[self.option.orderBy[0][0]];
return $.type(valA) === 'number' ? valB - valA : String(valB).localeCompare(String(valA));
});
return arr;
};
/**
* @desc 查询无结果的处理
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.notFoundSearch = function (self) {
$(self.elem.results).empty();
self.calcResultsSize(self);
$(self.elem.container).addClass(self.css_class.container_open);
self.setCssFocusedInput(self);
};
/**
* @desc 查询结果处理
* @param {Object} self - 插件内部对象
* @param {Object} json - 数据结果
* @param {Array} q_word - 查询关键字
* @param {number} which_page_num - 目标页
*/
SelectPage.prototype.prepareResults = function (self, json, q_word, which_page_num) {
//处理分页栏
if (self.option.pagination)
self.setNavi(self, json.cnt_whole, json.cnt_page, which_page_num);
if (!json.keyField)
json.keyField = false;
//仅选择模式
if (self.option.selectOnly && json.candidate.length === 1 && json.candidate[0] == q_word[0]) {
$(self.elem.hidden).val(json.keyField[0]);
this.setButtonAttrDefault();
}
//是否是输入关键词进行查找
var is_query = false;
if (q_word && q_word.length > 0 && q_word[0])
is_query = true;
//显示结果列表
self.displayResults(self, json, is_query);
};
/**
* @desc 生成分页栏
* @param {Object} self - 插件内部对象
* @param {number} cnt_whole - 数据总条数
* @param {number} cnt_page - 页面显示记录数
* @param {number} page_num - 当前页数
*/
SelectPage.prototype.setNavi = function (self, cnt_whole, cnt_page, page_num) {
/**
* 生成分页条
*/
var buildPageNav = function (self, pagebar, page_num, last_page) {
if ($('li', $(pagebar)).size() == 0) {
$(pagebar).empty();
//处理当当前页码为1时首页和上一页按钮不允许点击
var btnclass = '', isNewFontAwesome = true;
//判断是否使用了font-awesome3.2.1
$.each(document.styleSheets, function (i, n) {
if (n && n.href && n.href.indexOf('font-awesome-3.2.1') != -1) {
isNewFontAwesome = false;
return false;
}
});
//为不同版本图标设置样式
var iconFist = 'fa fa-angle-double-left', iconPrev = 'fa fa-angle-left', iconNext = 'fa fa-angle-right', iconLast = 'fa fa-angle-double-right';
if (!isNewFontAwesome) {
iconFist = 'icon-step-backward';
iconPrev = 'icon-backward';
iconNext = 'icon-forward';
iconLast = 'icon-step-forward';
}
if (page_num == 1)
btnclass = ' disabled ';
//首页
$(pagebar).append('<li class="csFirstPage' + btnclass + '" title="' + self.message.first_title + '" ><a href="javascript:void(0);"> <i class="' + iconFist + '"></i> </a></li>');
//上一页
$(pagebar).append('<li class="csPreviousPage' + btnclass + '" title="' + self.message.prev_title + '" ><a href="javascript:void(0);"><i class="' + iconPrev + '"></i></a></li>');
var pageInfo = '第 ' + page_num + ' 页(共' + last_page + '页)';
//设置分页信息
$(pagebar).append('<li class="pageInfoBox"><a href="javascript:void(0);"> ' + pageInfo + ' </a></li>');
if (page_num == last_page)
btnclass = ' disabled ';
else
btnclass = '';
//首页
$(pagebar).append('<li class="csNextPage' + btnclass + '" title="' + self.message.next_title + '" ><a href="javascript:void(0);"><i class="' + iconNext + '"></i></a></li>');
//上一页
$(pagebar).append('<li class="csLastPage' + btnclass + '" title="' + self.message.last_title + '" ><a href="javascript:void(0);"> <i class="' + iconLast + '"></i> </a></li>');
}
};
var pagebar = $(self.elem.navi);
var last_page = Math.ceil(cnt_whole / self.option.pageSize); //计算总页数
if (last_page == 0)
page_num = 0;
else {
if (last_page < page_num)
page_num = last_page;
else if (page_num == 0)
page_num = 1;
}
self.prop.current_page = page_num;//更新当前页参数
self.prop.max_page = last_page;//更新总页数参数
buildPageNav(self, pagebar, page_num, last_page);
//刷新分页信息
var pageInfoBox = $('li.pageInfoBox', $(pagebar));
var pageInfo = '第 ' + page_num + ' 页(共' + last_page + '页)';
$(pageInfoBox).html('<a href="javascript:void(0);"> ' + pageInfo + ' </a>');
//更新分页样式
var dClass = 'disabled';
var first = $('li.csFirstPage', $(pagebar));
var previous = $('li.csPreviousPage', $(pagebar));
var next = $('li.csNextPage', $(pagebar));
var last = $('li.csLastPage', $(pagebar));
//处理首页,上一页按钮样式
if (page_num === 1 || page_num === 0) {
if (!$(first).hasClass(dClass))
$(first).addClass(dClass);
if (!$(previous).hasClass(dClass))
$(previous).addClass(dClass);
} else {
if ($(first).hasClass(dClass))
$(first).removeClass(dClass);
if ($(previous).hasClass(dClass))
$(previous).removeClass(dClass);
}
//处理下一页,最后一页按钮的样式
if (page_num == last_page || last_page == 0) {
if (!$(next).hasClass(dClass))
$(next).addClass(dClass);
if (!$(last).hasClass(dClass))
$(last).addClass(dClass);
} else {
if ($(next).hasClass(dClass))
$(next).removeClass(dClass);
if ($(last).hasClass(dClass))
$(last).removeClass(dClass);
}
if (last_page > 1)
self.ehNaviPaging(); //导航按钮的事件设置
};
/**
* @desc 显示结果集列表
* @param {Object} self - 插件内部对象
* @param {Object} json 源数据
* @param {boolean} is_query - 是否是通过关键字搜索(用于区分是鼠标点击下拉还是输入框输入关键字进行查找)
*/
SelectPage.prototype.displayResults = function (self, json, is_query) {
$(self.elem.results).empty();
if (self.option.multiple && $.type(self.option.maxSelectLimit) === 'number' && self.option.maxSelectLimit > 0) {
var selectedSize = $('li.selected_tag', self.elem.element_box).size();
if (selectedSize > 0 && selectedSize >= self.option.maxSelectLimit) {
self.showMessage(self, '最多只能选择 ' + self.option.maxSelectLimit + ' 个项目');
return;
}
}
if (json.candidate.length > 0) {
var arr_candidate = json.candidate;
var arr_primary_key = json.keyField;
var keystr = $(self.elem.hidden).val();
var keyArr = keystr ? keystr.split(',') : new Array();
for (var i = 0; i < arr_candidate.length; i++) {
var itemText = '';
if (self.option.formatItem && $.isFunction(self.option.formatItem)) {
try {
itemText = self.option.formatItem(json.originalResult[i]);
} catch (e) {
console.error('formatItem内容格式化函数内容设置不正确');
itemText = arr_candidate[i];
}
} else
itemText = arr_candidate[i];
//XSS対策
var list = $('<li>').html(itemText).attr({
pkey: arr_primary_key[i],
title: itemText
});
//选中项目设置高亮样式
if ($.inArray(arr_primary_key[i].toString(), keyArr) !== -1) {
$(list).addClass(self.css_class.selected);
}
//缓存原始行对象
$(list).data('dataObj', json.originalResult[i]);
$(self.elem.results).append(list);
}
} else {
var li = '<li class="sp_message_box"><i class="fa fa-exclamation-triangle"></i> ' + self.message.not_found + '</li>';
$(self.elem.results).append(li);
}
if (self.option.multiple && self.option.multipleControlbar)
$(self.elem.control).show();
if (self.option.pagination)
$(self.elem.navi).toggleClass("hide", json.cnt_whole <= json.cnt_page);
//显示结果集列表并调整位置
self.calcResultsSize(self);
$(self.elem.container).addClass(self.css_class.container_open);
//结果集列表事件绑定
self.eResultList();
//若是键盘输入关键字进行查询且有内容时,列表自动选中第一行(autoSelectFirst为true时)
if (is_query && json.candidate.length > 0 && self.option.autoSelectFirst)
self.nextLine(self);
};
/**
* @desc 处理结果列表尺寸及位置
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.calcResultsSize = function (self) {
var rePosition = function () {
if ($(self.elem.container).css('position') === 'static') {
// position: static
var offset = $(self.elem.combo_input).offset();
$(self.elem.result_area).css({
top: offset.top + $(self.elem.combo_input).outerHeight() + 'px',
left: offset.left + 'px'
});
} else {
if (!self.option.pagination) {
var itemHeight = $('li:first', self.elem.results).outerHeight(true);
var listHeight = itemHeight * self.option.listSize;
$(self.elem.results).css({
'max-height': listHeight,
'overflow-y': 'auto'
});
}
//在展示下拉列表时,判断默认与输入框左对齐的列表是否会超出屏幕边界,是则右对齐,否则默认左对齐
var docWidth = $(document).width();
var docHeight = $(document).height();//文档全部高度
var viewHeight = $(window).height();//可视区域高度
var offset = $(self.elem.container).offset();
var screenScrollTop = $(window).scrollTop();
var listWidth = $(self.elem.result_area).outerWidth();
//当前状态列表并未被显示数据未被填充列表并未展现最终高度所以只能使用默认一页显示10条数据的固定高度进行计算
var listHeight = $(self.elem.result_area).outerHeight();
//默认方向的坐标在多选模式下因为外框架是DIV所以需要向左靠一个像素
var defaultLeft = self.option.multiple ? -1 : 0;
//输入框高度
var inputHeight = $(self.elem.container).outerHeight();
var left = (offset.left + listWidth) > docWidth ? -(listWidth - $(self.elem.container).outerWidth()) : defaultLeft;
//控件在全文档范围中的实际TOP非当前可视区域中的相对TOP
var screenTop = offset.top;//$(self.elem.container).scrollTop();//offset.top - screenScrollTop;
var top = 0, dist = 5;//设置偏移量让列表与输入框有5px的间距
//列表展开后的坐标高度
var listBottom = screenTop + inputHeight + listHeight + dist;
var hasOverflow = docHeight > viewHeight;
if ((screenTop - screenScrollTop - dist > listHeight) &&
(hasOverflow && listBottom > (viewHeight + screenScrollTop)) ||
(!hasOverflow && listBottom > viewHeight)) {
//控件当前位置+控件高度+列表高度超过实际body高度
//列表则需要向上展示
top = -(listHeight + 1) - dist;
$(self.elem.result_area).removeClass('shadowUp shadowDown').addClass('shadowUp');
} else {
//列表正常向下展示
top = self.option.multiple ? $(self.elem.container).innerHeight() + 1 : $(self.elem.container).outerHeight();
$(self.elem.result_area).removeClass('shadowUp shadowDown').addClass('shadowDown');
top += dist;
}
/*
$(self.elem.result_area).css({
top : top + 'px',
left: left + 'px'
});
*/
return {
top: top + 'px',
left: left + 'px'
};
}
};
if ($(self.elem.result_area).is(':visible')) {
$(self.elem.result_area).css(rePosition());
} else {
$(self.elem.result_area).show(1, function () {
$(this).css(rePosition());
});
}
};
/**
* @desc 隐藏结果列表
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.hideResults = function (self) {
if (self.prop.key_paging) {
self.scrollWindow(self, true);
self.prop.key_paging = false;
}
self.setCssFocusedInput(self);
if (self.option.autoFillResult) {
//self.selectCurrentLine(self, true);
}
$(self.elem.results).empty();
$(self.elem.result_area).hide();
$(self.elem.container).removeClass(self.css_class.container_open);
self.abortAjax(self);
self.setButtonAttrDefault(); // 按钮title属性初期化
};
/**
* @desc 跳转到首页
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.firstPage = function (self) {
if (self.prop.current_page > 1) {
self.prop.current_page = 1;
self.prop.page_move = true;
self.suggest(self);
}
};
/**
* @desc 跳转到上一页
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.prevPage = function (self) {
if (self.prop.current_page > 1) {
self.prop.current_page--;
self.prop.page_move = true;
self.suggest(self);
}
};
/**
* @desc 跳转到下一页
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.nextPage = function (self) {
if (self.prop.current_page < self.prop.max_page) {
self.prop.current_page++;
self.prop.page_move = true;
self.suggest(self);
}
};
/**
* @desc 跳转到尾页
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.lastPage = function (self) {
if (self.prop.current_page < self.prop.max_page) {
self.prop.current_page = self.prop.max_page;
self.prop.page_move = true;
self.suggest(self);
}
};
/**
* @desc 跳转到指定页
* @param {Object} self
* @param {number} page 目标页数
*/
SelectPage.prototype.goPage = function (self, page) {
if (typeof (page) === 'undefined')
page = 1;
if (self.prop.current_page < self.prop.max_page) {
self.prop.current_page = page;
self.prop.page_move = true;
self.suggest(self);
}
};
/**
* @desc 操作结束后的一些收尾工作
*/
SelectPage.prototype.afterAction = function (self) {
self.inputResize(self);
$(self.elem.combo_input).trigger("change");
$(self.elem.hidden).trigger("change");
self.setCssFocusedInput(self);
if (self.option.multiple) {
if (self.option.selectToCloseList) {
self.hideResults(self);
$(self.elem.combo_input).blur();
} else {
self.suggest(self);
$(self.elem.combo_input).focus();
}
} else {
self.hideResults(self);
$(self.elem.combo_input).blur();
}
};
/**
* @desc 选择当前行
* @param {Object} self - 插件内部对象
* @param {boolean} is_enter_key - 是否为回车键
*/
SelectPage.prototype.selectCurrentLine = function (self, is_enter_key) {
self.scrollWindow(self, true);
var current = self.getCurrentLine(self);
if (current) {
if (!self.option.multiple) {
$(self.elem.combo_input).val($(current).text());
$(self.elem.hidden).val($(current).attr('pkey'));
} else {
//多选模式的项目选择处理
$(self.elem.combo_input).val('');
var item = {text: $(current).text(), value: $(current).attr('pkey')};
if (!self.isAlreadySelected(self, item)) {
self.addNewTag(self, item);
self.tagValuesSet(self);
}
}
if (self.option.selectOnly)
self.setButtonAttrDefault();
//项目选择回调函数触发
if (self.option.eSelect && $.isFunction(self.option.eSelect))
self.option.eSelect($(current).data('dataObj'));
self.prop.prev_value = $(self.elem.combo_input).val();
self.prop.selected_text = $(self.elem.combo_input).val();
self.putClearButton();
}
self.afterAction(self);
};
/**
* 单选模式下选中项目后,显示清空按钮
*/
SelectPage.prototype.putClearButton = function () {
if (!this.option.multiple && !$(this.elem.combo_input).prop('disabled'))
$(this.elem.container).append(this.elem.clear_btn);
};
/**
* @desc 全选当前页的行
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.selectAllLine = function (self) {
var jsonarr = new Array();
$('li', self.elem.results).each(function (i, row) {
var item = {text: $(row).text(), value: $(row).attr('pkey')};
if (!self.isAlreadySelected(self, item)) {
self.addNewTag(self, item);
self.tagValuesSet(self);
}
jsonarr.push($(row).data('dataObj'));
//若有最大选择数量限制,则添加最大个数后,不再添加
if ($.type(self.option.maxSelectLimit) === 'number' &&
self.option.maxSelectLimit > 0 &&
self.option.maxSelectLimit === $('li.selected_tag', self.elem.element_box).size()) {
return false;
}
});
if (self.option.eSelect && $.isFunction(self.option.eSelect))
self.option.eSelect(jsonarr);
self.afterAction(self);
};
/**
* @desc 取消选择本页全部项目
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.unselectAllLine = function (self) {
var size = $('li', self.elem.results).size();
$('li', self.elem.results).each(function (i, row) {
var key = $(row).attr('pkey');
var tag = $('li.selected_tag[itemvalue="' + key + '"]', self.elem.element_box);
self.removeTag(self, tag);
});
self.afterAction(self);
if (self.option.eTagRemove && $.isFunction(self.option.eTagRemove))
self.option.eTagRemove(size);
};
/**
* @desc 清除所有选中的项目
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.clearAll = function (self) {
var size = 0;
if (self.option.multiple) {
size = $('li.selected_tag', self.elem.element_box).size();
$('li.selected_tag', self.elem.element_box).remove();
}
$(self.elem.combo_input).val('');
$(self.elem.hidden).val('');
self.afterAction(self);
if (self.option.multiple) {
if (self.option.eTagRemove && $.isFunction(self.option.eTagRemove))
self.option.eTagRemove(size);
}
};
/**
* @desc 获得当前行对象
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.getCurrentLine = function (self) {
if ($(self.elem.result_area).is(':hidden'))
return false;
var obj = $('li.' + self.css_class.select, self.elem.results);
if ($(obj).size())
return obj;
else
return false;
};
/**
* @desc 多选模式下判断当前选中项目是否已经存在已选中列表中
* @param {Object} self - 插件内部对象
* @param {Object} item - 选中行对象
*/
SelectPage.prototype.isAlreadySelected = function (self, item) {
var isExist = false;
if (item.value) {
var keys = $(self.elem.hidden).val();
if (keys) {
var karr = keys.split(',');
if (karr && karr.length > 0 && $.inArray(item.value, karr) != -1)
isExist = true;
}
}
return isExist;
};
/**
* @desc 多选模式下增加一个标签
* @param {Object} self - 插件内部对象
* @param {Object} item - 选中行对象
*/
SelectPage.prototype.addNewTag = function (self, item) {
if (!self.option.multiple || !item)
return;
var tmp = self.template.tag.content, tag;
tmp = tmp.replace(self.template.tag.textKey, item.text);
tmp = tmp.replace(self.template.tag.valueKey, item.value);
tag = $(tmp);
if ($(self.elem.combo_input).prop('disabled'))
$('span.tag_close', tag).hide();
$(self.elem.combo_input).closest('li').before(tag);
};
/**
* @desc 多选模式下移除一个标签
* @param {Object} self - 插件内部对象
* @param {Object} item - 标签对象
*/
SelectPage.prototype.removeTag = function (self, item) {
var key = $(item).attr('itemvalue');
var keys = $(self.elem.hidden).val();
//从已保存的key列表中删除该标签对应的项目
if ($.type(key) != 'undefined' && keys) {
var keyarr = keys.split(',');
var index = $.inArray(key.toString(), keyarr);
if (index != -1) {
keyarr.splice(index, 1);
$(self.elem.hidden).val(keyarr.toString());
}
}
$(item).remove();
self.inputResize(self);
};
/**
* @desc 多选模式下标签结果值放入隐藏域
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.tagValuesSet = function (self) {
if (!self.option.multiple)
return;
var tags = $('li.selected_tag', $(self.elem.element_box));
if (tags && $(tags).size() > 0) {
var result = new Array();
$.each(tags, function (i, li) {
var v = $(li).attr('itemvalue');
if ($.type(v) !== 'undefined')
result.push(v);
});
if (result.length > 0) {
$(self.elem.hidden).val(result.join(','));
}
}
};
/**
* @desc 多选模式下输入框根据输入内容调整输入框宽度
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.inputResize = function (self) {
if (!self.option.multiple)
return;
var width = '';
var inputLi = self.elem.combo_input.closest('li');
//设置默认宽度
var setDefaultSize = function (self, inputLi) {
inputLi.removeClass('full_width');
var minimumWidth = self.elem.combo_input.val().length + 1;
var width = (minimumWidth * 0.75) + 'em';
self.elem.combo_input.css('width', width);
self.elem.combo_input.removeAttr('placeholder');
};
if ($('li.selected_tag', $(self.elem.element_box)).size() === 0) {
if (self.elem.combo_input.attr('placeholder_bak')) {
if (!inputLi.hasClass('full_width'))
inputLi.addClass('full_width');
self.elem.combo_input.attr('placeholder', self.elem.combo_input.attr('placeholder_bak'));
self.elem.combo_input.removeAttr('style');
} else
setDefaultSize(self, inputLi);
} else
setDefaultSize(self, inputLi);
};
/**
* @desc 选择下一行
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.nextLine = function (self) {
var obj = self.getCurrentLine(self);
var idx;
if (!obj)
idx = -1;
else {
idx = $(self.elem.results).children('li').index(obj);
$(obj).removeClass(self.css_class.select);
}
idx++;
if (idx < $(self.elem.results).children('li').length) {
var next = $(self.elem.results).children('li').eq(idx);
$(next).addClass(self.css_class.select);
self.setCssFocusedResults(self);
} else
self.setCssFocusedInput(self);
self.scrollWindow(self, false);
};
/**
* @desc 选择上一行
* @param {Object} self - 插件内部对象
*/
SelectPage.prototype.prevLine = function (self) {
var obj = self.getCurrentLine(self);
var idx;
if (!obj)
idx = $(self.elem.results).children('li').length;
else {
idx = $(self.elem.results).children('li').index(obj);
$(obj).removeClass(self.css_class.select);
}
idx--;
if (idx > -1) {
var prev = $(self.elem.results).children('li').eq(idx);
$(prev).addClass(self.css_class.select);
self.setCssFocusedResults(self);
} else
self.setCssFocusedInput(self);
self.scrollWindow(self, false);
};
/**
* @desc 下拉分页查询控件初始化入口
* @global
* @memberof jQuery,bootstrap2,bootstrap3
* @param option {Object} 初始化参数集
*/
function Plugin(option) {
return this.each(function () {
var $this = $(this),
data = $this.data(SelectPage.dataKey),
params = $.extend({}, defaults, $this.data(), data && data.option, typeof option === 'object' && option);
if (!data)
$this.data(SelectPage.dataKey, (data = new SelectPage(this, params)));
});
}
/**
* 获得稿件内部对象
* @param {object} obj
* @returns
*/
function getPlugin(obj) {
var container = $(obj).closest('div.sp_container');
return $('input.sp_input', container);
}
/**
* @desc 清除所有模式下选择的项目
*/
function ClearSelected() {
return this.each(function () {
var $this = getPlugin(this),
data = $this.data(SelectPage.dataKey);
if (data)
data.clearAll(data);
});
}
/**
* 刷新选中项目内容
* 使用场景:使用$().val('xxx')修改插件的选中项目ID此时需要刷新插件在输入框中的显示文本
*/
function SelectedRefresh() {
return this.each(function () {
var $this = getPlugin(this),
data = $this.data(SelectPage.dataKey);
if (data && data.elem.hidden.val())
data.setInitRecord(true);
});
}
/**
* 修改插件数据源
* 仅在json数据源模式有效
* @param {array} data
* @example
* [{name:'aa',sex:1},{name:'bb',sex:0},{...}]
*/
function ModifyDataSource(data) {
return this.each(function () {
if (data && $.isArray(data) && data.length > 0) {
var $this = getPlugin(this),
plugin = $this.data(SelectPage.dataKey);
if (plugin) {
plugin.clearAll(plugin);
plugin.option.data = data;
}
}
});
}
/**
* @desc 获得选中项目的文本
* @returns {string}
*/
function GetInputText() {
var str = '';
this.each(function () {
var $this = getPlugin(this), data = $this.data(SelectPage.dataKey);
if (data)
str += data.elem.combo_input.val();
});
return str;
}
/**
* @desc 获得选中项目的数据
* @returns {String}
*/
function GetInputValue() {
var str = '';
this.each(function () {
var $this = getPlugin(this), data = $this.data(SelectPage.dataKey);
if (data)
str += data.elem.hidden.val();
});
return str;
}
var old = $.fn.selectPage;
$.fn.selectPage = Plugin;
$.fn.selectPage.Constructor = SelectPage;
$.fn.selectPageClear = ClearSelected;
$.fn.selectPageRefresh = SelectedRefresh;
$.fn.selectPageData = ModifyDataSource;
$.fn.selectPageText = GetInputText;
$.fn.selectPageValue = GetInputValue;
// 处理新旧版本冲突
// =================
$.fn.selectPage.noConflict = function () {
$.fn.selectPage = old;
return this;
};
}));