You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2314 lines
81 KiB

/**
* @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.13(v2.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.19(v2.2)
* 增加为原始输入框的value属性设置初始化值,以初始化插件选中项目
* 修复多选模式下关闭标签出错的问题
* 修复输入查询关键字后失去焦点,再次获得焦点时,插件没有根据已存在的关键进行过滤
* 增加inputDelay配置项目,设置ajax数据源模式下,延迟输入查询的时间,避免在单位时间内连续输入发起的连续ajax查询,单位:秒,默认值:0.5
* 修正对数字类型的列进行排序时,仍然以字符串的方式进行排序
* 2017.08.23(v2.3)
* 修复在查询关键字状态下,分页数据没有被更新,导致分页按钮功能不正常问题
* 清理整理内部对象
* 修复多选模式下,若设置了最大选中项目个数,点击“全选本页”按钮时,仅选中指定的最大数量
* 增加selectpage.base.css兼容无UI框架的方案,但建议要至少使用normalize.css
* 2017.08.26(v2.4)
* 增加pagination参数,指定稿件是否使用分页加载数据,以及显示分页栏
* 增加listSize参数,指定了不使用分页的列表,显示的高度,单位为个(选项个数),默认显示10个项目的高度
* 设置selectOnly:true的情况下,输入框为只读模式,不允许输入查询过滤
* 修复多选模式下及设置了最大选中项目时,选中了项目再次点击“全选本页”按钮会在已选择的基础上增加最大选中项目个数的项目
* 调整下拉列表样式及位置
* 增加单选模式下,选中项目后,自动显示清空按钮
* 修复多选模式下,移除本页和清除所有两个按钮点击后,回调出错的问题
* 增加搜索无结果时显示提示信息
* 2017.09.07(v2.5)
* 修复多选模式下,初始化项目的显示文本没有使用formatItem回调进行格式化
* 修复ajax数据源模式下,输入查询关键字时,翻页始终为第一页的问题
* 2017.09.07(v2.6)
* 修复单选模式下初始化项目的显示文本没有使用formatItem回调格式化的问题
* 修复单选模式存在初始化项目时,再打开下拉列表时,仅显示匹配的项目一条数据的问题
* 修复多选模式下,动态修改选中值selectPageRefresh功能无效
* 2017.09.12(v2.7)
* 增加eClear回调,单选模式下,清除按钮的功能回调
* 单选,多选模式下,输入框禁用或只读状态,不显示清除按钮
* 2017.09.23(v2.8)
* 调整部分样式
* 修复可视区域高度较小时,列表始终会向上展开的问题
* 分离键盘事件处理,对键盘输入精准控制
* 优化区域外点击处理
* 优化数据展示渲染效率
* 优化列表位置定位的准确性
*/
;(function($){
"use strict";
/**
* @desc 默认参数集
*/
var defaults = {
/**
* @desc 数据源(String:Ajax查询的URL|Object:JSON格式的数据源)
* @type {string|Object}
* @example
* string:服务端请求的URL地址
* Object:JSON格式数组,推荐格式:[{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) {
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: 'sp_navi',
// 下拉结果列表
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 = $('<div>').addClass('pagination').append('<ul>');
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'));
}
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
},
success: function(json) {
var d = null;
if(self.option.eAjaxSuccess && $.isFunction(self.option.eAjaxSuccess))
d = self.option.eAjaxSuccess(json);
self.afterInit(self, d.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];
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
};
_orgParams[searchKey] = q_word[0];
if (_paramsFunc && $.isFunction(_paramsFunc)) {
var result = _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, errorThrown);
return;
}
var data = self.option.eAjaxSuccess(returnData);
//数据结构处理
var json = {};
json.originalResult = data.list;
json.cnt_whole = data.totalRow;
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).hide().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>');
$(pagebar).show();
}
};
var pagebar = $('ul', $(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).hide().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);
}
$(self.elem.results).show();
if(self.option.multiple && self.option.multipleControlbar) $(self.elem.control).show();
if(self.option.pagination) $(self.elem.navi).show();
//显示结果集列表并调整位置
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) {
console.log(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).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;
}
var old = $.fn.selectPage;
$.fn.selectPage = Plugin;
$.fn.selectPage.Constructor = SelectPage;
$.fn.selectPageClear = ClearSelected;
$.fn.selectPageRefresh = SelectedRefresh;
$.fn.selectPageData = ModifyDataSource;
$.fn.selectPageText = GetInputText;
// 处理新旧版本冲突
// =================
$.fn.selectPage.noConflict = function () {
$.fn.selectPage = old;
return this;
};
})(window.jQuery);