1.使用

简单场景:

1. <table id="table"></table>  
2.   
3. $("#table").bootstrapTable({  
4.     url: options.url,   
5. 'get',      //请求方式(*)
6. //toolbar: '#toolbar',    //工具按钮用哪个容器
7. true,      //是否显示行间隔色
8. false,      //是否使用缓存,默认为true,所以一般情况下需要设置一下这个属性(*)
9. true,     //是否显示分页(*)
10. false,      //是否启用排序
11. "asc",     //排序方式
12. //: queryParams,//传递参数(*)
13. //初始化加载第一页,默认第一页
14. //每页的记录行数(*)
15. //可供选择的每页的行数(*)
16. //search: true,      //是否显示表格搜索,此搜索是客户端搜索,不会进服务端
17. //strictSearch: true,
18. //showColumns: true,     //是否显示所有的列
19. //showRefresh: true,     //是否显示刷新按钮
20. //最少允许的列数
21. true,    //是否启用点击选中行
22. "id",      //每一行的唯一标识,一般为主键列
23. false,     //是否显示详细视图和列表视图的切换按钮
24. "server", //服务端处理分页
25.     columns:[  
26. 'id',field: 'id', visible: false, align: 'center',valign: 'middle'},  
27. '名称',   field: 'name',  align: 'center',valign: 'middle'},  
28. '操作',field: '#',align: 'center',  
29. function(value,row,index){  
30. var e = '<a href="#" mce_href="#" οnclick="onEditClick(\''+ row.id + '\',\'' +row.flowProcessId+ '\',\'' +'\')">编辑</a> ';  
31. var f = '<a href="#" mce_href="#" οnclick="onCopyClick(\''+ row.id + '\')">复制</a> ';    
32. //var d = '<a href="#" mce_href="#" οnclick="onDeleteClick(\''+ row.id +'\')">删除</a> ';  
33. return
34.             }   
35.         }  
36.     ];  
37. });

 复杂场景:。。。

 

html配置:。。。

 

2.源码

1. // @author 文志新 http://jsfiddle.net/wenyi/47nz7ez9/3/
2.   
3. /**关于插件的通用构造
4.  *
5.  * 构造函数PluginName($trigger,options)传入触发元素和配置项,以便在构造函数中使用触发元素
6.  *     写在$.fn.pluginName外围,通过实例化$ele.data('bootstrap.table',(dat=new BootstrapTable(this,options)));
7.  *     实例写在触发元素的data属性中,以便调用该实例,避免多次创造实例;
8.  * $.fn.pluginName(option)参数是对象,执行构造函数PluginName,产生新的实例;
9.  *     是字符串,调用data对象中存储的实例执行方法,提供PluginName.prototype的方法接口;
10.  *     脱离在构造函数PluginName及其原型中的函数,通过$.fn.pluginName.util暴露接口;
11.  *     构造函数PluginName使用$ele.trigger提供事件接口;
12.  * 配置项可以是html页面data数据配置、或者$.fn.pluginName参数option配置;
13.  *     在html中的配置可以方便使用模板引擎传值实现初始化,后台java使用content.put方法;
14.  *     默认配置项利用js中一切都是对象的特点附着在PluginName.DEFAULTS;
15.  * 
16.  * 构造函数渲染页面时,先填充页面内容,再绑定事件;
17.  *     绑定事件通过$ele.off(eventType).on(eventType,function(){})先解绑;
18.  *
19.  * 书写有分支具体情况到主干通用情况,类似先做能力检测,再做浏览器嗅探
20.  *     应用场景,if(){return};抽离分支具体情况,后续代码对主干通用情况进行处理
21.  *     优先检测具体的配置项,其次对自定义配置项、默认配置项作混合处理
22.  *     预先配置子条目的显示情况、数据信息,再次配置父条目的显示情况、配置信息
23.  *
24.  * if语句传递设置的详情变量时,先顺序设置头部,再针对一般情况进行处理,其次设置尾部
25.  *     类似插件作者对分页切换页面按钮的处理,
26.  *     借form、to设置起始页展示情况,再是两串...,最后是尾页的显示情况
27.  */
28.   
29. /**关于jquery
30.  *
31.  * data:
32.  *     $(ele).data()以对象形式返回;
33.  *     $(ele).data({url:"www.baidu.com"})以对象形式设置data属性;
34.  *     $(ele).data(url,{param:"www.baidu.com"})以对象形式设置某个data属性;
35.  *
36.  * event:
37.  *     $.proxy(fn,content)调用的函数fn,传入的上下文content;
38.  *     $.Event(eventType,arguments)转化成事件,并传入参数,只可使用一次;
39.  *
40.  * type:
41.  *     $.isNumeric()判断变量是否数值型或数字值字符串,包含十六进制等;
42.  *     $.isFunction()判断是否为函数;
43.  *     $.isEmptyObject()是否为空对象;
44.  *     $.isPlainObject()是否为对象字面量;
45.  *     $.isArray()是否数组;
46.  *     $.type()判断类型;
47.  *     
48.  * util:
49.  *     $.grep([]/{},function(item,index))过滤出返回值为真的数组;
50.  *     $.map([]/{},function(item,index))过滤出以返回值为数组元素的数组;
51.  *     $.inArray()返回元素在数组中的位置;
52.  */
53.   
54. /**bootstap
55.  * 使用caret样式实现三角形;
56.  */
57.   
58. /**技巧
59.  *
60.  * 使用数组拼接字符串,这样做方便使用三目运算符处理可变的内容;
61.  * 
62.  * i<0?[]:{} 三目运算符后跟数组或对象;
63.  * 
64.  * 三目运算符以[]包裹,获取对象的属性;
65.  *
66.  * "paramName".split(/(?=[A-Z])/) 返回结果为["param","Name"];
67.  * 
68.  * str.replace(/%s/g, function(){}) 对每个匹配值应用函数;
69.  *
70.  * [{i:1},{j:2}].sort(function(a,b){}) a、b为数组元素;
71.  * 
72.  * 非字符串数组对象使用toString()方法转换后,再调用localeCompare进行比较;
73.  *
74.  * ~~利用按位非转化成整数型;
75.  *
76.  * Object.getOwnPropertyNames以数组形式返回对象的属性;
77.  * 
78.  * scrollWidth包含超过可视区域的长度;
79.  * clientWidth可视区域不包括滚动条的宽度;
80.  * offsetWidth可视区域包括滚动条的宽度;
81.  * outerWidth包括内边距、边框的宽度;
82.  * outerWidth(true)包括内边距、边框、外边距的宽度;
83.  * innerWidth包括内边距、不包括边框的宽度;
84.  *
85.  * scrollLeft()获取元素的水平偏移,有水平滚动条的情况下;
86.  * scrollTop()获取元素的垂直偏移,有垂直滚动条的情况下;
87.  *
88.  * 通过hide()方法隐藏的元素可以用:hidden伪类获取;
89.  */
90.   
91. /**关于本插件
92.  *
93.  * html页面配置项写在触发元素的data属性,在$.prototype.bootstrapTable方法将其和默认配置项合并;
94.  *     触发元素还包含表格内容如表头信息,在构造函数Bootstrap中获取该信息,与配置项对应内容合并;
95.  * js配置的优先级高于html页面配置项,initTable获取页面配置thead>tr>th、tbody>tr>td信息;
96.  * 表体渲染通过this.data实现,搜索、排序以及其他方法更新this.data数据,实现数据和显示分离;
97.  */
98. !function
99. 'use strict';  
100.   
101. /**工具函数
102.      *
103.      * sprintf(str,str1,str2):
104.      *     sprintf("<span style='%s'>%s</span>","text-align:center"."hello");
105.      *     顺序替换文本,无替换文本返回空;
106.      *     
107.      * getPropertyFromOther(list,from,to,value):
108.      *     getPropertyFromOther(this.columns,'field','title',value);
109.      *     获取field属性为value的数组元素的title属性值this.columns[i].title;
110.      *     应用场景:卡片式显示时需要获取标题栏的显示文案信息;
111.      *     
112.      * getFieldIndex(columns,field):
113.      *     getFieldIndex(this.columns,field);
114.      *     获取field属性为field的数组元素的列坐标this.columns[i].filedIndex;
115.      *     
116.      * setFieldIndex(this.options.columns):
117.      *     setFieldIndex([[
118.                 {colspan:4,title:'Group1'},// 跨几列
119.                 {rowspan:3,title:'ID'},// 跨几行
120.             ],[
121.                 {rowspan:2,title:'Name1'},
122.                 {colspan:3,title:'Group2'},
123.             ],[
124.                 {title:'Name2'},
125.                 {title:'Name3'},
126.                 {title:'Name4'},
127.             ]])
128.      *     为每条标题栏数据设置filedIndex:所在列/列坐标;
129.      *     无field主键的标题栏数据以列坐标作为field属性的值;
130.      *     意义:借用this.columns[fieldIndex]=column构建this.columns;
131.      *         this.column的数据格式为{[column]},列坐标相同的标题栏取靠后的子标题;
132.      *     问题:用户配置options.columns时需要顺序写就标题栏,以子标题不跨列为前提,函数的应用场景变得有限;
133.      *         
134.      * getScrollBarWidth获取滚动条的宽度;
135.      *
136.      * calculateObjectValue(self,name,args,defaultValue):
137.      *     当name为字符串时,获取window对象的方法并执行,参数为args,没有该方法时调用sprintf替换name文本;
138.      *     当name为函数时,传入args执行该函数;
139.      *     以上情况都不是返回defaultValue;
140.      *     问题:原型中的方法可以直接调用,window对象的方法使用户配置变得繁琐,sprintfy也可以预先作判断后调用;
141.      *
142.      * compareObjects(objectA,objectB,compareLength):
143.      *     compareObjects(this.options, options, true);
144.      *     当compareLength为真时,先比较两个对象的长度是否相同,其次比较同名元素是否等值;
145.      *     当compareLength为否时,只比较两个对象的同名元素是否等值;
146.      *     问题:在插件中的使用,依赖this.options和options长度相等,且没有不同名的属性;
147.      *
148.      * escapeHTML转义;
149.      *
150.      * getRealHeight($el):
151.      *     以子元素的最大高度作为父元素的高度;
152.      *
153.      * getRealDataAttr($(this).data()):
154.      *     将paramName的data属性转换成param-name修改完成后输出;
155.      *
156.      * getItemField(item,field,escape):
157.      *     当field为函数时,获取item[field]并进行转义(escape为真的情况下);
158.      *     当field为字符串时,以最末一个点号后的字符获取item中的属性并进行转义(escape为真的情况下);
159.      *     问题:实际应用场景field多是字符串,且没有点号,可以限制用户配置使调用函数变得方便;
160.      *
161.      * isIEBrowser是否IE浏览器或者Trident呈现引擎;
162.      */
163. var cachedWidth = null;  
164.   
165. // 顺序替换文本,无替换文本返回空;
166. var sprintf = function
167. var
168. true,  
169.             i = 1;  
170.   
171. function
172. var arg = args[i++];// 对每个匹配值应用函数,i自加1,直到无匹配值;
173.   
174. if (typeof arg === 'undefined') {  
175. false;  
176. return '';  
177.             }  
178. return
179.         });  
180. return flag ? str : '';  
181.     };  
182.   
183. // 获取from属性为value的数组元素的to属性值this.columns[i].to;
184. // 应用场景,卡片式显示时需要获取标题栏的显示文案信息;
185. var getPropertyFromOther = function
186. var result = '';  
187. function
188. if
189.                 result = item[to];  
190. return false;  
191.             }  
192. return true;  
193.         });  
194. return
195.     };  
196.   
197. // 获取field属性为field的数组元素的列坐标this.columns[i].filedIndex;
198. var getFieldIndex = function
199. var
200.   
201. function
202. if
203.                 index = i;  
204. return false;  
205.             }  
206. return true;  
207.         });  
208. return
209.     };  
210.   
211. // 为每条标题栏数据设置filedIndex:所在列/列坐标;
212. /**
213.      * 策略:
214.      * 表头分割成columns.length(总行数)* totalCol(总列数)的矩阵,以flag矩阵标记为false;
215.      * 各标题栏为columns[i][j].rowspan(行数)* columns[i][j].colspan(列数)的小矩阵;
216.      * 从左自右、从上而下遍历标题栏小矩阵,将标题栏对应的flag首行、首列标记为true;
217.      * 因标题栏只能跨列或跨行,不能既跨行又跨列,函数的实现依赖用户输入正确的options.columns格式,
218.      */
219. var setFieldIndex = function
220. var
221.             totalCol = 0,  
222.             flag = [];  
223.   
224. for
225. // 表格总列数;
226.         }  
227.   
228. for (i = 0; i < columns.length; i++) {// columns.length表格总行数;
229.             flag[i] = [];  
230. for
231. false;  
232.             }  
233.         }  
234.   
235. for
236. for (j = 0; j < columns[i].length; j++) {// columns[i].length某行共有多少元素;
237. var
238.                     rowspan = r.rowspan || 1,  
239.                     colspan = r.colspan || 1,  
240. // i为标题栏小矩阵在flag大矩阵的行位置;
241. // index记录标题栏小矩阵在flag大矩阵的列位置;
242. false, flag[i]);  
243.   
244. if
245. // fieldIndex记录每个标题栏的列坐标信息;
246.                     r.fieldIndex = index;  
247. if (typeof r.field === 'undefined') {  
248.                         r.field = index;  
249.                     }  
250.                 }  
251.   
252. // 目的是让$.inArray(false, flag[i])正确获取标题栏的列坐标;
253. for
254. true;  
255.                 }  
256. for
257. true;  
258.                 }  
259.             }  
260.         }  
261.     };  
262.   
263. // 获取滚动条的宽度;
264. var getScrollBarWidth = function
265. if (cachedWidth === null) {  
266. var inner = $('<p/>').addClass('fixed-table-scroll-inner'),  
267. '<div/>').addClass('fixed-table-scroll-outer'),  
268.                 w1, w2;  
269.   
270.             outer.append(inner);  
271. 'body').append(outer);  
272.   
273.             w1 = inner[0].offsetWidth;  
274. 'overflow', 'scroll');  
275.             w2 = inner[0].offsetWidth;  
276.   
277. if
278.                 w2 = outer[0].clientWidth;  
279.             }  
280.   
281.             outer.remove();  
282.             cachedWidth = w1 - w2;  
283.         }  
284. return
285.     };  
286.   
287. // 当name为字符串时,获取window对象的方法并执行,参数为args,没有该方法时调用sprintf替换name文本;
288. // 当name为函数时,传入args执行该函数;以上情况都不是返回defaultValue;
289. var calculateObjectValue = function
290. var
291.   
292. if (typeof name === 'string') {  
293. // support obj.func1.func2
294. var names = name.split('.');  
295.   
296. if
297.                 func = window;  
298. function
299.                     func = func[f];  
300.                 });  
301. else
302.                 func = window[name];  
303.             }  
304.         }  
305. if (typeof func === 'object') {  
306. return
307.         }  
308. if (typeof func === 'function') {  
309. return
310.         }  
311. if (!func && typeof name === 'string' && sprintf.apply(this, [name].concat(args))) {  
312. return sprintf.apply(this, [name].concat(args));  
313.         }  
314. return
315.     };  
316.   
317. // 当compareLength为真时,先比较两个对象的长度是否相同,其次比较同名元素是否等值;
318. // 当compareLength为否时,只比较两个对象的同名元素是否等值;
319. var compareObjects = function
320. var
321.             objectBProperties = Object.getOwnPropertyNames(objectB),  
322. '';  
323.   
324. if
325. if
326. return false;  
327.             }  
328.         }  
329.   
330. for (var
331.             propName = objectAProperties[i];  
332.   
333. if
334. if
335. return false;  
336.                 }  
337.             }  
338.         }  
339.   
340. return true;  
341.     };  
342.   
343. // 转义;
344. var escapeHTML = function
345. if (typeof text === 'string') {  
346. return
347. '&')  
348. '<')  
349. '>')  
350. '"')  
351. '/g, ''')  
352. '`');  
353.         }  
354. return
355.     };  
356.   
357. // 以子元素的最大高度作为父元素的高度;
358. var getRealHeight = function
359. var
360. function
361. if (height < $(this).outerHeight(true)) {  
362. this).outerHeight(true);  
363.             }  
364.         });  
365. return
366.     };  
367.   
368. // 将paramName的data属性转换成param-name修改完成后输出;
369. var getRealDataAttr = function
370. for (var attr in
371. // "paramName".split(/(?=[A-Z])/) 返回结果为["param","Name"];
372. var auxAttr = attr.split(/(?=[A-Z])/).join('-').toLowerCase();  
373. if
374.                 dataAttr[auxAttr] = dataAttr[attr];  
375. delete
376.             }  
377.         }  
378. return
379.     };  
380.   
381. // 当field为函数时,获取item[field]并进行转义(escape为真的情况下);
382. // 当field为字符串时,以最末一个点号后的字符获取item中的属性并进行转义(escape为真的情况下);
383. var getItemField = function
384. var
385.   
386. if (typeof field !== 'string'
387. return
388.         }  
389. var props = field.split('.');  
390. for (var p in
391.             value = value && value[props[p]];  
392.         }  
393. return
394.     };  
395.   
396. // 浏览器嗅探,匹配IE浏览器或呈现引擎Trident的返回为真;
397. var isIEBrowser = function
398. return !!(navigator.userAgent.indexOf("MSIE ") > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./));  
399.     };  
400.   
401.   
402.   
403. /**BootstrapTable构造函数
404.      *
405.      * this.$el带table标签的触发元素,置入this.$tableBody中;
406.      * this.$container最外层包裹元素.bootstrap-table;
407.      * this.$toolbar即是.bootstrap-table下工具栏元素.fixed-table-toolbar;
408.      * this.$pagination即是.bootstrap-table下分页元素.fixed-table-pagination;
409.      * this.$tableContainer即是.bootstrap-table下标题内容元素.fixed-table-container;
410.      * this.$tableHeader即是.fixed-table-container下表头元素.fixed-table-header;
411.      * this.$tableBody即是.fixed-table-container下表体元素.fixed-table-body;
412.      * this.$tableFooter即是.fixed-table-container下表尾元素.fixed-table-footer;
413.      * this.$tableLoading即是.fixed-table-container下加载中提示元素.fixed-table-loading;
414.      * this.$header即是this.$el下的thead元素;
415.      * this.$header_即是对this.$header的克隆,置入this.$tableHeader中,目的是实现表体的滚动;
416.      * this.options.toolbar用户自定义按钮组,置入this.$toolbar中;
417.      *
418.      *
419.      * 
420.      * this.options.column:
421.      *     混合js和html表头标题栏的配置项,包括thead>tr的class/title/html/rowspan/colspan/data;
422.      * this.columns:
423.      *     以this.columns[fieldIndex]的数组形式[columns]记录表体相应标题栏的数据内容;
424.      * this.options.data:
425.      *     有js配置,获取js配置,没有js配置,获取html配置;
426.      *     包含tbody>tr的id/class/data,tbody>tr>td的html/id/class/rowspan/title/data;
427.      * this.header.fields:
428.      *     以this.header.fields[column.fieldIndex]数组形式[field]记录表体每列数据的主键;
429.      *     应用场景:渲染表体td时由该主键通过getFieldIndex获取this.columns的序号;
430.      *     问题:不能直接通过tr的序号获取this.columns数据,或者VisibleColumns数据???
431.      *     this.header.fields剔除了this.columns中visible为false的内容;
432.      * this.header.styles、this.header.classes:
433.      *     数组形式存储经过处理的每列数据的样式、类;
434.      * this.header.formatters、this.header.cellStyles、this.header.sorters:
435.      *     数组形式存储格式化函数、设置单元格样式函数、排序函数,或者window方法名;
436.      * this.header.events、this.header.sortNames、this.header.searchables:
437.      *     数组形式存储表体相应标题栏配置的事件events、上传排序的字段sortName、可搜索searchable;
438.      *     应用场景:由主键名在this.header.fields的位置锁定对应的事件、排序字段、可搜索;
439.      * this.header.stateField:
440.      *     复选框内容上传时的字段名;
441.      * this.data:
442.      *     initSearch搜索前以及执行filterBy方法前与this.options.data等值;
443.      *     搜索后this.data为过滤后数据;
444.      *     data的数据格式:
445.                 对象形式
446.                 [{   // 行tr中的属性设置
447.                     _data:{
448.                         index:1,// 后续会自动赋值为数据在当前页的所在行号
449.                         field:field
450.                     },
451.                     _id:id,
452.                     _class:class,
453.                     field1:value1,field2:value2, //填充在单元格中的显示内容,从this.header.fields数组中获取属性名field1等
454.                     _field_id
455.                 }] // 每一行特定的样式、属性根据this.options.rowStyle、this.options.rowAttributes获取
456.                 数组形式
457.                 [["field","class"]] // 数组形式不能对每一行添加特定的data属性、id以及class
458.                                     // 特定的的样式、属性仍可由this.options.rowStyle、this.options.rowAttributes获取
459.                                     // 以及data-index添加行号、data-uniqueId每行的唯一标识,根据options.uniqueId从data中获取
460.      * this.options.data:
461.      *     initSearch搜索前以及执行filterBy方法前与this.data等值;
462.      *     搜索后this.data为未过滤数据;
463.      *     应用场景:搜索未使用前后台数据交互,通过this.options.data获取新的过滤数据this.data;
464.      * this.searchText:
465.      * this.text:
466.      *     搜索文本;
467.      * this.filterColumns:
468.      *     options.data和this.filterColumns相符则在this.data中保留,不相符则在this.data中删除;
469.      *     prototype.filterBy方法使用;
470.      *
471.      * 
472.      * 
473.      * init():
474.      *     初始化函数;
475.      * initLocale():
476.      *     将语言包添加进配置项this.options中,数据格式是{formatLoadingMessage:fn};
477.      * initContainer():
478.      *     创建包裹元素this.container及其子元素this.$toolbar、this.$pagination等,为表格添加样式;
479.      * initTable():
480.      *     获取页面thead>th、tbody>tr>td的配置内容更新options.columns、options.data配置信息;
481.      *     this.columns记录表体每列数据相应标题栏options.column的数据内容;
482.      * initHeader():
483.      *     由options.columns渲染表头,th的data-field记为column[field],data数据记为column;
484.      *     更新this.header记录主键、样式、事件、格式化函数等,以及stateField复选框上传字段;
485.      *     绑定事件,包括点击排序、确认键排序、全选,更新上传数据、页面状态等;
486.      * initFooter():
487.      *     显示隐藏表尾;
488.      * initData(data,type):
489.      *     页面初始化时this.data赋值为this.options.data;
490.      *     ajax交互时this.data赋值为后台返回的数据,options.data也同样更新为后台返回的数据;
491.      *     type为append时,表格尾部插入数据,this.data、options.data尾部插入相应数据;
492.      *     type为prepend时,表格顶部插入数据,this.data、options.data头部插入相应数据; 
493.      *     前台分页的情况下调用this.initSort进行排序,后台分页以返回数据为准;
494.      * initSort():
495.      *     onSort方法设置点击排序按钮时,更新options.sortName为相应标题栏column.field值;
496.      *     initSort由column.field值获得相应的sortName;
497.      *     调用option.sorter函数或window[option.sorter]方法进行比较排序;
498.      *     排序通过更新this.data数据实现,this.data渲染到页面使用initBody方法;
499.      * onSort():
500.      *     点击排序时更新options.sortName为被排序列数据对应column[field]值,以便initSort获取sortName;
501.      *     更新options.sortOrder为被排序列数据对应column[order]值,或保持原有值;
502.      *     触发sort事件,调用initServer获取后台数据,调用initSort排序、initBody渲染表体;
503.      * initToolbar():
504.      *     创建工具栏内的用户自定义按钮组、分页显示隐藏切换按钮、刷新按钮、筛选条目按钮;
505.      *     以及卡片表格显示切换按钮、搜索框,并绑定相应事件;筛选条目时触发column-switch事件;
506.      * onSearch():
507.      *     this.text,this.options.text设为搜索框去除两端空白的值,pageNumber设为1;
508.      *     调用initSearch将筛选本地数据;调用updatePagination完成远程交互或单渲染本地数据;
509.      *     触发search事件;
510.      * initSearch():
511.      *     前台分页的情况下,先通过this.filterColumns通过this.option.data过滤this.data数据;
512.      *     再通过搜索文本过滤this.data数据;
513.      *     输入文本和经this.header.formatters或window[this.header.formatters]函数格式化匹配比对;
514.      * initPagination():
515.      *     初始化设置分页相关页面信息显示情况,包括当前页显示第几条到第几天数据,共几条数据,每页显示几条数据;
516.      *     以及每页显示数据量切换按钮,选择页面的分页栏显示情况,再绑定事件;
517.      *     通过options.pageNumber获取this.pageFrom、this.pageTo,以便前台分页时initBody获取相应数据;
518.      * updatePagination():
519.      *     分页点选按钮有disabled属性则返回,无则重新布局分页显示面板;
520.      *     maintainSelected为否时,调用resetRows重置复选框为不选中,调用initServer交互或initbody渲染页面;
521.      *     initSever由后台返回数据;
522.      *     initPagination通过options.pageNumber取得options.pageFrom、options.pageTo;
523.      *     initBody由options.pageFrom、options.pageTo获取需要渲染的数据data;
524.      *     触发page-change事件;
525.      * onPageListChange():
526.      *     每页显示数据量下拉列表选中时触发,替换每页显示数据量按钮文本;
527.      *     更新options.pageSize,通过updatePagination调用initPagination设置this.pageFrom、this.pageTo;
528.      *     updatePagination再调用initServer完成交互,或initBody渲染本地数据;
529.      * onPageFirst():
530.      * onPagePre():
531.      * onPageNext():
532.      * onPageLast():
533.      * onPageNumber():
534.      *     更新options.pageNumber,通过updatePagination调用initPagination设置this.pageFrom、this.pageTo;
535.      *     updatePagination再调用initServer完成交互,或initBody渲染本地数据;
536.      *     跳转分页首页、上一页、下一页、尾页,由页码跳转;
537.      * initBody():
538.      *     fixedScroll为否的情况下,表体移动到顶部;
539.      *     通过this.pageFrom、this.pageTo截取this.getData()数据row渲染表体,主要是tbody>tr以及tbody>tr>td;
540.      *     tbody>tr的data-index设为行号,class、id为row._class、row._id,样式、data数据通过调用函数获得;
541.      *     tbody>tr>td区分为卡片显示和表格显示两类,显示值取经this.header.formatters[i]处理后的row[field];
542.      *     tbody>tr>td其他class、id、title、data取row[_field_class]等;
543.      *     绑定展开卡片详情按钮点击事件、复选框点击事件、this.header.events中的事件;
544.      *     触发post-body、pre-body事件; 
545.      * initServer():
546.      *     触发ajax事件(可以是用户自定义的方法options.ajax),上传数据格式为:
547.      *     {
548.      *         searchText:this.searchText,
549.      *         sortName:this.options.sortName,
550.      *         sortOrder:this.options.sortOrder,
551.      *         pageSize/limit:...,
552.      *         pageNumber/offset:...,
553.      *         [filter]:...,
554.      *         query:...
555.      *     }
556.      *     上传成功调用this.load方法,触发load-success事件、上传失败load-error事件;
557.      * initSearchText():
558.      *     初始化若设置搜索文本,开启搜索,不支持本地数据搜索; 
559.      * getCaret():
560.      *     getCaret改变排序点击箭头的上下方向;
561.      * updateSelected():
562.      *     全选以及全不选时改变全选复选框的勾选状态,以及tr行添加或删除selected类;
563.      * updateRows():
564.      *     复选框选中或撤销选中后更新this.data数据中的[this.header.stateField]属性,以便上传复选框的状态;
565.      * resetRows():
566.      *     重置,撤销复选框选中,以及data[i][that.header.stateField]赋值为false;
567.      * trigger():
568.      *     执行this.options[BootstrapTable.EVENTS[name]]函数(类似浏览器默认事件),并触发事件;
569.      * resetHeader():
570.      *     一定时间内触发this.fitHeader函数调整表头的水平偏移,垂直滚动不影响表头;
571.      * fitHeader():  
572.      *     克隆this.$el中的表头,置入this.$tableHeader中,出使垂直滚动时,表头信息不变;
573.      *     调整表体水平偏移量和表体水平一致;
574.      * resetFooter():
575.      *     创建表尾,利用footerFormatter填充表尾内容,调用fitFooter调整表尾偏移;
576.      * fitFooter():
577.      *     调整表尾水平偏移,设置表尾fnt-cell的宽度;
578.      * toggleColumn():
579.      *     toggleColumn筛选条目下拉菜单点选时更新columns[i].visible信息;
580.      *     this.columns信息的改变,重新调用表头、表体、搜索框、分页初始化函数;
581.      *     当勾选的显示条目小于this.options.minimumCountColumns时,勾选的条目设置disabled属性;
582.      * toggleRow():
583.      *     从表体中找到data-index=index或data-uniqueid=uniqueId那一行,根据visible显示或隐藏;
584.      * getVisibleFields():
585.      *     从this.column中剔除visible为false的项,返回field数组;
586.      */
587. var BootstrapTable = function
588. this.options = options;  
589. this.$el = $(el);  
590. this.$el_ = this.$el.clone();// 记录触发元素的初始值,destroy销毁重置的时候使用
591. this.timeoutId_ = 0;// 超时计时器,有滚动条的情况下调整表头的水平偏移量
592. this.timeoutFooter_ = 0;// 超时计时器,有滚动条的情况下调整表尾的水平偏移量
593.   
594. this.init();  
595.     };  
596.   
597.     BootstrapTable.DEFAULTS = {  
598. 'table table-hover',// 触发元素table加入的样式;
599. // 设置语言包;
600. // 包括分页和工具栏的高度;
601. '-',// 无显示文本时默认显示内容;
602.         sortName: undefined,  
603. // 初始化排序字段名,须是column.filed主键名;
604. // 点击排序后更新options.sortName为被排序列的主键名columns[i].field;
605. // 通过主键名在this.header.fields中的序号获取sortName,比较后排序;
606. 'asc',// 升序或降序,并且上传
607. false,// 触发元素table是否显示间行色
608.         columns: [[]],  
609.         data: [],  
610. 'rows',// 后台传回data数据的字段名
611. 'get',// ajax发送类型
612. // ajax发送地址
613.         ajax: undefined,  
614. // 用户自定义ajax,或通过字符串调用window下的方法,对插件内配置有较多使用,调用其实不便
615. true,// ajax设置
616. 'application/json',  
617. 'json',  
618.         ajaxOptions: {},  
619. function
620. return
621.         },  
622. 'limit', // undefined
623. function
624. return
625. // ajax处理相应的函数
626. false,// 分页是否显示
627. false,// 分页文案提示只显示有多少条数据
628. 'client', // client or server 前台分页或后台分页
629. // server side need to set
630. // 初始化显示第几页
631. // 初始化页面多少条数据
632. // 每页显示数据量切换配置项
633. 'right', //right, left 分页浮动设置
634. 'bottom', //bottom, top, both
635. // 分页显示位置,上、下或上下均显示,默认底部显示
636. // 设置一页显示多少条数据按钮向上下拉,还是向下下拉,默认向上下拉
637. // 设置为both时,分页在上下位置均显示,设置一页显示多少条数据按钮向上下拉
638. 'left', //right, left 每页几行数据显示区浮动情况
639. '‹',// 分页上一页按钮
640. '›',// 分页下一页按钮
641. false,// 是否支持搜索
642. false,// enter键开启搜索
643. false,// 搜索框输入内容是否须和条目显示数据严格匹配,false时只要键入部分值就可获得结果
644. 'right',// 搜索框对齐方式
645. 'btSelectItem',// 复选框默认上传name值
646. true,// 显示表头,包含标题栏内容
647. false,// 默认隐藏表尾
648. false,// 显示筛选条目按钮
649. false,// 显示分页隐藏展示按钮
650. false,// 显示刷新按钮
651. false,// 显示切换表格显示或卡片式详情显示按钮
652. 'right',// 显示隐藏分页、刷新、切换表格或卡片显示模式、筛选显示条目、下载按钮浮动设置
653. true,  
654. // smartDisplay为真,当总页数为1时,屏蔽分页,以及下拉列表仅有一条时,屏蔽切换条目数按钮下拉功能
655. false,// 是否转义
656. // 最小显示条目数
657. // data中存储复选框value的键值
658. // 从data中获取每行数据唯一标识的属性名
659. false,// 是否显示卡片式详情(移动端),直接罗列每行信息,不以表格形式显现
660. false,// 表格显示数据时,每行数据前是否有点击按钮,显示这行数据的卡片式详情
661. function
662. return '';  
663. // 折叠式卡片详情渲染文本,包含html标签、Dom元素
664. true,// 搜索框键入值执行搜索时,清除两端空格填入该搜索框
665. false,  
666. false,// 复选框只能单选,需设置column.radio属性为真
667. // 用户自定义按钮组,区别于搜索框、分页切换按钮等
668. 'left',// 用户自定义按钮组浮动情况
669. true,// 为否隐藏全选按钮
670. true,// 可排序全局设置
671. true,// ajax交互的时候是否显示loadding加载信息
672. false,// 为真且翻页时,保持前一页各条row[that.header.stateField]为翻页前的值
673.         searchTimeOut: 500,  
674. // 搜索框键入值敲enter后隔多少时间执行搜索,使用clearTimeout避免间隔时间内多次键入反复搜索
675. '',// 初始化搜索内容
676. // 按钮、搜索输入框通用大小,使用bootstrap的sm、md、lg等
677. 'glyphicon', // 按钮通用样式
678.         icons: {  
679. 'glyphicon-collapse-down icon-chevron-down',// 显示分页按钮
680. 'glyphicon-collapse-up icon-chevron-up',// 隐藏分页按钮
681. 'glyphicon-refresh icon-refresh',// 刷新按钮
682. 'glyphicon-list-alt icon-list-alt',// 切换表格详情显示、卡片式显示按钮
683. 'glyphicon-th icon-th',// 筛选条目按钮
684. 'glyphicon-plus icon-plus',// 卡片式详情展开按钮
685. 'glyphicon-minus icon-minus'// 卡片式详情折叠按钮
686. // 工具栏按钮具体样式
687.   
688. function
689. return
690. // 传递给每一行的css设置,row为这一行的data数据
691.   
692. function
693. return
694. // 传递给每一行的属性设置
695.   
696. function
697. return false;  
698.         },  
699. function
700. return false;  
701.         },  
702. function
703. return false;  
704.         },  
705. function
706. return false;  
707.         },  
708. function
709. return false;  
710.         },  
711. function
712. return false;  
713.         },  
714. function
715. return false;  
716.         },  
717. function
718. return false;  
719.         },  
720. function
721. return false;  
722.         },  
723. function
724. return false;  
725.         },  
726. function
727. return false;  
728.         },  
729. function
730. return false;  
731.         },  
732. function
733. return false;  
734.         },  
735. function
736. return false;  
737.         },  
738. function
739. return false;  
740.         },  
741. function
742. return false;  
743.         },  
744. function
745. return false;  
746.         },  
747. function
748. return false;  
749.         },  
750. function
751. return false;  
752.         },  
753. function
754. return false;  
755.         },  
756. function
757. return false;  
758.         },  
759. function
760. return false;  
761.         },  
762. function
763. return false;  
764.         },  
765. function
766. return false;  
767.         },  
768. function
769. return false;  
770.         }  
771.     };  
772.   
773.     BootstrapTable.LOCALES = [];  
774.   
775. 'en-US'] = BootstrapTable.LOCALES['en'] = {  
776. function
777. return 'Loading, please wait...';  
778.         },  
779. function
780. return sprintf('%s records per page', pageNumber);  
781. // 每页显示条目数提示文案
782. function
783. return sprintf('Showing %s to %s of %s rows', pageFrom, pageTo, totalRows);  
784. // 分页提示当前页从第pageFrom到pageTo,总totalRows条
785. function
786. return sprintf('Showing %s rows', totalRows);// 分页提示供多少条数据
787.         },  
788. function
789. return 'Search';  
790. // 设置搜索框placeholder属性
791. function
792. return 'No matching records found';  
793. // 没有数据时提示文案
794. function
795. return 'Hide/Show pagination';  
796. // 显示隐藏分页按钮title属性提示文案
797. function
798. return 'Refresh';  
799. // 刷新按钮title属性提示文案
800. function
801. return 'Toggle';  
802. // 切换表格、卡片显示模式按钮title属性提示文案
803. function
804. return 'Columns';  
805. // 筛选显示条目按钮title属性提示文案
806. function
807. return 'All';  
808.         }  
809.     };  
810.   
811. 'en-US']);  
812.   
813.     BootstrapTable.COLUMN_DEFAULTS = {  
814. false,// 有否radio,有则options.singleSelect设为真
815. false,// 有否checkbox,options.singleSelect设为真,checkbox单选
816. true,// 复选框是否可选
817. // 后台数据的id号
818. // 内容文案
819. // title属性文案
820. 'class': undefined,// 样式
821. // tbody、thead、tfoot文本对齐情况
822. // thead文本对齐情况
823. // tfoot文本对齐情况
824. // 垂直对齐情况
825. // 宽度,字符串或数值输入,均转化为"36px"或"10%"形式
826. false,// 是否可排序,options.sortable设置为真的时候可用
827. 'asc', // asc, desc
828. true,// 可见性
829. true,// 该条目可以通过筛选条目按钮切换显示状态
830. true,  
831.         formatter: undefined,  
832. // 以function(field,row,index){}格式化数据,field后台字段,row行数据,index对应row的序号值
833. // 无配置时以title显示,有配置时以返回值显示
834. // 填充表尾内容
835. // 数据格式为[{"click element":functionName}],回调中传入(value,row,index)
836. // 调用sorter函数或window[sorter]函数进行排序,高优先级
837. // 进行排序的字段名,用以获取options.data中的数据
838.         cellStyle: undefined,  
839. // 调用cellStyle函数或window[cellStyle]函数添加样式以及类;
840. // 以function(field,row,index){}设置单元格样式以及样式类,返回数据格式为{classes:"class1 class2",css:{key:value}}
841. true,// 设置哪一列的数据元素可搜索
842. true,  
843. true// 设为否时,卡片式显示时该列数据不显示
844.     };  
845.   
846.     BootstrapTable.EVENTS = {  
847. 'all.bs.table': 'onAll',  
848. 'click-cell.bs.table': 'onClickCell',  
849. 'dbl-click-cell.bs.table': 'onDblClickCell',  
850. 'click-row.bs.table': 'onClickRow',  
851. 'dbl-click-row.bs.table': 'onDblClickRow',  
852. 'sort.bs.table': 'onSort',  
853. 'check.bs.table': 'onCheck',  
854. 'uncheck.bs.table': 'onUncheck',  
855. 'check-all.bs.table': 'onCheckAll',  
856. 'uncheck-all.bs.table': 'onUncheckAll',  
857. 'check-some.bs.table': 'onCheckSome',  
858. 'uncheck-some.bs.table': 'onUncheckSome',  
859. 'load-success.bs.table': 'onLoadSuccess',  
860. 'load-error.bs.table': 'onLoadError',  
861. 'column-switch.bs.table': 'onColumnSwitch',  
862. 'page-change.bs.table': 'onPageChange',  
863. 'search.bs.table': 'onSearch',  
864. 'toggle.bs.table': 'onToggle',  
865. 'pre-body.bs.table': 'onPreBody',  
866. 'post-body.bs.table': 'onPostBody',  
867. 'post-header.bs.table': 'onPostHeader',  
868. 'expand-row.bs.table': 'onExpandRow',  
869. 'collapse-row.bs.table': 'onCollapseRow',  
870. 'refresh-options.bs.table': 'onRefreshOptions',  
871. 'reset-view.bs.table': 'onResetView'
872.     };  
873.   
874. function
875. this.initLocale();  
876. // 将语言包添加进配置项this.options中,数据格式是{formatLoadingMessage:fn};
877. this.initContainer();  
878. // 创建包裹元素this.container及其子元素this.$toolbar、this.$pagination等,为表格添加样式;
879. this.initTable();  
880. // 获取页面配置更新options.columns、options.data,this.columns记录表体对应标题栏的数据;
881. this.initHeader();  
882. // 渲染表头,设置this.header数据记录主键等,绑定表头事件,卡片式显示时隐藏表头;
883. this.initData();  
884. // 页面初始化、后台传值、表头表尾插入数据,更新this.data、options.data,前台分页则排序;
885. this.initFooter();  
886. // 显示隐藏表尾;
887. this.initToolbar();  
888. // 创建工具栏按钮组,并绑定事件;
889. this.initPagination();  
890. // 创建分页相关内容,并绑定事件;
891. this.initBody();  
892. // 渲染表体,区分卡片显示和表格显示两类,绑定相关事件;
893. this.initSearchText();  
894. // 初始化若设置搜索文本,开启搜索,不支持本地数据搜索;
895. this.initServer();  
896. // 上传数据,成功时调用load方法渲染表格;
897.     };  
898.   
899. // 将语言包添加进配置项this.options中,数据格式是{formatLoadingMessage:fn};
900. function
901. if (this.options.locale) {  
902. var parts = this.options.locale.split(/-|_/);  
903.             parts[0].toLowerCase();  
904.             parts[1] && parts[1].toUpperCase();  
905. if ($.fn.bootstrapTable.locales[this.options.locale]) {  
906. this.options, $.fn.bootstrapTable.locales[this.options.locale]);  
907. else if ($.fn.bootstrapTable.locales[parts.join('-')]) {  
908. this.options, $.fn.bootstrapTable.locales[parts.join('-')]);  
909. else if
910. this.options, $.fn.bootstrapTable.locales[parts[0]]);  
911.             }  
912.         }  
913.     };  
914.   
915. // 创建包裹元素this.container及其子元素this.$toolbar、this.$pagination等,为表格添加样式;
916. function
917. this.$container = $([  
918. '<div class="bootstrap-table">',  
919. '<div class="fixed-table-toolbar"></div>',  
920. this.options.paginationVAlign === 'top' || this.options.paginationVAlign === 'both'
921. '<div class="fixed-table-pagination" style="clear: both;"></div>'
922. '',  
923. '<div class="fixed-table-container">',  
924. '<div class="fixed-table-header"><table></table></div>',  
925. '<div class="fixed-table-body">',  
926. '<div class="fixed-table-loading">',  
927. this.options.formatLoadingMessage(),  
928. '</div>',  
929. '</div>',  
930. '<div class="fixed-table-footer"><table><tr></tr></table></div>',  
931. this.options.paginationVAlign === 'bottom' || this.options.paginationVAlign === 'both'
932. '<div class="fixed-table-pagination"></div>'
933. '',  
934. '</div>',  
935. '</div>'
936. ''));  
937.   
938. this.$container.insertAfter(this.$el);  
939. this.$tableContainer = this.$container.find('.fixed-table-container');  
940. this.$tableHeader = this.$container.find('.fixed-table-header');  
941. this.$tableBody = this.$container.find('.fixed-table-body');  
942. this.$tableLoading = this.$container.find('.fixed-table-loading');  
943. this.$tableFooter = this.$container.find('.fixed-table-footer');  
944. this.$toolbar = this.$container.find('.fixed-table-toolbar');  
945. this.$pagination = this.$container.find('.fixed-table-pagination');  
946.   
947. this.$tableBody.append(this.$el);  
948. this.$container.after('<div class="clearfix"></div>');  
949.   
950. this.$el.addClass(this.options.classes);  
951. if (this.options.striped) {  
952. this.$el.addClass('table-striped');  
953.         }  
954. if ($.inArray('table-no-bordered', this.options.classes.split(' ')) !== -1) {  
955. this.$tableContainer.addClass('table-no-bordered');  
956.         }  
957.     };  
958.   
959. // 当html中包含thead>tr>th以及tbody>tr>td时,获取页面的配置项更新options.columns、options.data;
960. // js配置的优先级高于html页面配置;
961. // this.columns以this.columns[fieldIndex]的数组形式[columns]记录表体相应标题栏的数据内容;
962. function
963. var that = this,  
964.             columns = [],  
965.             data = [];  
966.   
967. // 触发元素table中有thead子标签等则使用(查询排序的时候),无则创建
968. this.$header = this.$el.find('>thead');  
969. if (!this.$header.length) {  
970. this.$header = $('<thead></thead>').appendTo(this.$el);  
971.         }  
972. this.$header.find('tr').each(function
973. var
974.   
975. this).find('th').each(function
976.                 column.push($.extend({}, {  
977. this).html(),  
978. 'class': $(this).attr('class'),  
979. this).attr('title'),  
980. this).attr('rowspan') ? +$(this).attr('rowspan') : undefined,  
981. this).attr('colspan') ? +$(this).attr('colspan') : undefined  
982. this).data()));  
983.             });  
984.             columns.push(column);  
985.         });  
986. if (!$.isArray(this.options.columns[0])) {  
987. this.options.columns = [this.options.columns];// 都处理成两维数组的形式
988.         }  
989. this.options.columns = $.extend(true, [], columns, this.options.columns);  
990.   
991. // 借用this.columns[fieldIndex]=column构建this.columns;
992. // this.column的数据格式为{[column]},列坐标相同的标题栏取靠后的子标题;
993. // 意义:填充表体内容时,this.column提供每列数据的相关信息;
994. this.columns = [];  
995.   
996. // setFieldIndex将标题栏的fieldIndex属性赋值为标题栏所在列坐标;
997. this.options.columns);  
998.   
999. this.options.columns, function
1000. function
1001.                 column = $.extend({}, BootstrapTable.COLUMN_DEFAULTS, column);  
1002.   
1003. if (typeof column.fieldIndex !== 'undefined') {  
1004.                     that.columns[column.fieldIndex] = column;  
1005.                 }  
1006.   
1007.                 that.options.columns[i][j] = column;  
1008.             });  
1009.         });  
1010.   
1011. if (this.options.data.length) {  
1012. return;  
1013.         }  
1014.   
1015. this.$el.find('>tbody>tr').each(function
1016. var
1017.   
1018. // 获取每一行tr的id、class、data属性,以数组形式赋值给data
1019. this).attr('id');  
1020. this).attr('class');  
1021. this).data());  
1022.   
1023. // 获取某一行每个子元素的内容、id、class、rowspan、title、data属性
1024. this).find('td').each(function
1025. // field通常是后台数据的id号,没有该值的时候赋值为column列坐标信息,写入本地数据的时候
1026. var
1027.   
1028. this).html();  
1029. // save td's id, class and data-* attributes
1030. '_' + field + '_id'] = $(this).attr('id');  
1031. '_' + field + '_class'] = $(this).attr('class');  
1032. '_' + field + '_rowspan'] = $(this).attr('rowspan');  
1033. '_' + field + '_title'] = $(this).attr('title');  
1034. '_' + field + '_data'] = getRealDataAttr($(this).data());  
1035.             });  
1036.             data.push(row);  
1037.         });  
1038.   
1039. this.options.data = data;  
1040.     };  
1041.   
1042. // 由options.columns渲染表头,th的data-field记为column[field],data数据记为column;
1043. // 更新this.header记录主键、样式、事件、格式化函数等,以及stateField复选框上传字段;
1044. // 绑定事件,包括点击排序、确认键排序、全选,更新上传数据、页面状态等;
1045. function
1046. var that = this,  
1047.             visibleColumns = {},  
1048.             html = [];  
1049.   
1050. this.header = {  
1051.             fields: [],  
1052.             styles: [],  
1053.             classes: [],  
1054.             formatters: [],  
1055.             events: [],  
1056.             sorters: [],  
1057.             sortNames: [],  
1058.             cellStyles: [],  
1059.             searchables: []  
1060.         };  
1061.   
1062. this.options.columns, function
1063. '<tr>');  
1064.   
1065. // 页面以表格显示且有卡片式详情点击按钮的时候,表头首列为该按钮开辟一个空白的单元格
1066. if
1067. '<th class="detail" rowspan="%s"><div class="fht-cell"></div></th>',  
1068.                     that.options.columns.length));  
1069.             }  
1070.   
1071. function
1072. var text = '',  
1073. '',   
1074. '',   
1075. '',  
1076. ' class="%s"', column['class']),  
1077.                     order = that.options.sortOrder || column.order,  
1078. 'px',  
1079.                     width = column.width;  
1080.   
1081. // width输入宽度有%或px时,分割%或px到unitWidth中,width保留数字字符串
1082. // width输入数值时,unitWidth默认取px
1083. if
1084. if (typeof column.width === 'string') {  
1085. if (column.width.indexOf('%') !== -1) {  
1086. '%';  
1087.                         }  
1088.                     }  
1089.                 }  
1090. if (column.width && typeof column.width === 'string') {  
1091. '%', '').replace('px', '');  
1092.                 }  
1093.   
1094. 'text-align: %s; ', column.halign ? column.halign : column.align);  
1095. 'text-align: %s; ', column.align);  
1096. 'vertical-align: %s; ', column.valign);  
1097. 'width: %s; ', (column.checkbox || column.radio) && !width ?  
1098. '36px'
1099.   
1100. /** 
1101.                  * this.header.styles、this.header.classes:
1102.                  *     数组形式存储经过处理的每列数据的样式、类;
1103.                  * this.header.formatters、this.header.cellStyles、this.header.sorters:
1104.                  *     数组形式存储格式化函数、设置单元格样式函数、排序函数,或者window方法名;
1105.                  * this.header.events、this.header.sortNames、this.header.searchables:
1106.                  *     数组形式存储表体相应标题栏配置的事件events、上传排序的字段名sortName、可搜索searchable;
1107.                  */
1108. // 填充触发元素的tbody内容块时使用
1109. if (typeof column.fieldIndex !== 'undefined') {  
1110.                     that.header.fields[column.fieldIndex] = column.field;  
1111.                     that.header.styles[column.fieldIndex] = align + style;  
1112.                     that.header.classes[column.fieldIndex] = class_;  
1113.                     that.header.formatters[column.fieldIndex] = column.formatter;  
1114.                     that.header.events[column.fieldIndex] = column.events;  
1115.                     that.header.sorters[column.fieldIndex] = column.sorter;  
1116.                     that.header.sortNames[column.fieldIndex] = column.sortName;  
1117.                     that.header.cellStyles[column.fieldIndex] = column.cellStyle;  
1118.                     that.header.searchables[column.fieldIndex] = column.searchable;  
1119.   
1120. if
1121. return;  
1122.                     }  
1123.   
1124. if
1125. return;  
1126.                     }  
1127.   
1128.                     visibleColumns[column.field] = column;  
1129.                 }  
1130.   
1131. // options.columns数据回显和渲染页面
1132. '<th' + sprintf(' title="%s"', column.titleTooltip),  
1133.                     column.checkbox || column.radio ?  
1134. ' class="bs-checkbox %s"', column['class'] || '') :  
1135.                         class_,  
1136. ' style="%s"', halign + style),  
1137. ' rowspan="%s"', column.rowspan),  
1138. ' colspan="%s"', column.colspan),  
1139. ' data-field="%s"', column.field),  
1140. "tabindex='0'",  
1141. '>');  
1142.   
1143. '<div class="th-inner %s">', that.options.sortable && column.sortable ?  
1144. 'sortable both' : ''));  
1145.   
1146.                 text = column.title;  
1147.   
1148. if
1149. if
1150. '<input name="btSelectAll" type="checkbox" />';  
1151.                     }  
1152. // 复选框内容上传时的字段名
1153.                 }  
1154. if
1155. '';  
1156.                     that.header.stateField = column.field;  
1157. true;  
1158.                 }  
1159.   
1160.                 html.push(text);  
1161. '</div>');  
1162. '<div class="fht-cell"></div>');  
1163. '</div>');  
1164. '</th>');  
1165.             });  
1166. '</tr>');  
1167.         });  
1168.   
1169. this.$header.html(html.join(''));  
1170. this.$header.find('th[data-field]').each(function
1171. // 标题栏data属性写入各自的column数据,展开卡片式详情时使用
1172. this).data(visibleColumns[$(this).data('field')]);  
1173.         });  
1174.   
1175. // 绑定点击排序事件
1176. this.$container.off('click', '.th-inner').on('click', '.th-inner', function
1177. var target = $(this);  
1178. if (target.closest('.bootstrap-table')[0] !== that.$container[0])  
1179. return false;  
1180.   
1181. if
1182.                 that.onSort(event);  
1183.             }  
1184.         });  
1185.   
1186. // 确认键排序
1187. this.$header.children().children().off('keypress').on('keypress', function
1188. if (that.options.sortable && $(this).data().sortable) {  
1189. var
1190. if (code == 13) { //Enter keycode
1191.                     that.onSort(event);  
1192.                 }  
1193.             }  
1194.         });  
1195.   
1196. // 显示隐藏表头,调整this.$tableLoading位置;options.cardView为真时卡片式显示隐藏表头
1197. if (!this.options.showHeader || this.options.cardView) {  
1198. this.$header.hide();  
1199. this.$tableHeader.hide();  
1200. this.$tableLoading.css('top', 0);  
1201. else
1202. this.$header.show();  
1203. this.$tableHeader.show();  
1204. this.$tableLoading.css('top', this.$header.outerHeight() + 1);  
1205.               
1206. this.getCaret();// 更新排序箭头显示情况
1207.         }  
1208.   
1209. // 全选
1210. this.$selectAll = this.$header.find('[name="btSelectAll"]');  
1211. this.$selectAll.off('click').on('click', function
1212. var checked = $(this).prop('checked');  
1213. 'checkAll' : 'uncheckAll']();// 改变复选框勾选状态,更新上传数据
1214. // tr添加selected类
1215.         });  
1216.     };  
1217.   
1218. // 显示隐藏表尾
1219. function
1220. if (!this.options.showFooter || this.options.cardView) {  
1221. this.$tableFooter.hide();  
1222. else
1223. this.$tableFooter.show();  
1224.         }  
1225.     };  
1226.   
1227.   
1228. // 页面初始化时this.data赋值为this.options.data;
1229. // ajax交互时this.data赋值为后台返回的数据,options.data也同样更新为后台返回的数据;
1230. // type为append时,表格尾部插入数据,this.data、options.data尾部插入相应数据;
1231. // type为prepend时,表格顶部插入数据,this.data、options.data头部插入相应数据; 
1232. // 前台分页的情况下调用this.initSort,后台分页以返回数据为准;
1233. function
1234. if (type === 'append') {  
1235. this.data = this.data.concat(data);  
1236. else if (type === 'prepend') {  
1237. this.data = [].concat(data).concat(this.data);  
1238. else
1239. this.data = data || this.options.data;  
1240.         }  
1241.   
1242. if (type === 'append') {  
1243. this.options.data = this.options.data.concat(data);  
1244. else if (type === 'prepend') {  
1245. this.options.data = [].concat(data).concat(this.options.data);  
1246. else
1247. this.options.data = this.data;  
1248.         }  
1249.   
1250. if (this.options.sidePagination === 'server') {  
1251. return;  
1252.         }  
1253. this.initSort();  
1254.     };  
1255.   
1256. // onSort方法设置点击排序按钮时,更新options.sortName为相应标题栏column.field值;
1257. // initSort由column.field值获得相应的sortName;
1258. // 调用option.sorter函数或window[option.sorter]方法进行比较排序;
1259. // 或者直接比较data[sortName]进行排序;
1260. // 排序通过更新this.data数据实现,this.data渲染到页面使用initBody方法;
1261. function
1262. var that = this,  
1263. this.options.sortName,  
1264. this.options.sortOrder === 'desc'
1265. this.options.sortName, this.header.fields);  
1266.   
1267. if
1268. this.data.sort(function
1269. if
1270. // 获取colum.sortName
1271.                 }  
1272. // 获取每行数据的data[sortName]的值,转义后返回
1273. var
1274.                     bb = getItemField(b, name, that.options.escape),  
1275. // 调用column.sorter函数或window[column.sorter]方法进行比较,上下文是that.header
1276.                     value = calculateObjectValue(that.header, that.header.sorters[index], [aa, bb]);  
1277.   
1278. if
1279. return
1280.                 }  
1281.   
1282. if (aa === undefined || aa === null) {  
1283. '';  
1284.                 }  
1285. if (bb === undefined || bb === null) {  
1286. '';  
1287.                 }  
1288.   
1289. if
1290.                     aa = parseFloat(aa);  
1291.                     bb = parseFloat(bb);  
1292. if
1293. return
1294.                     }  
1295. return
1296.                 }  
1297.   
1298. if
1299. return
1300.                 }  
1301.   
1302. if (typeof aa !== 'string') {  
1303.                     aa = aa.toString();  
1304.                 }  
1305.   
1306. if (aa.localeCompare(bb) === -1) {//bb为何不要转换?
1307. return
1308.                 }  
1309.   
1310. return
1311.             });  
1312.         }  
1313.     };  
1314.   
1315. // 点击排序时更新options.sortName为被排序列数据对应column[field]值,以便initSort获取sortName;
1316. // 更新options.sortOrder为被排序列数据对应column[order]值,或保持原有值;
1317. // 触发sort事件,调用initServer获取后台数据,调用initSort排序、initBody渲染表体;
1318. function
1319. var $this = event.type === "keypress"
1320. this.$header.find('th').eq($this.index());// 记录this.$header下相同元素
1321.   
1322. this.$header.add(this.$header_).find('span.order').remove();  
1323.   
1324. // options.sortName更新被排序列数据对应column[field]值,以便initSort获取sortName加以比较;
1325. if (this.options.sortName === $this.data('field')) {  
1326. this.options.sortOrder = this.options.sortOrder === 'asc' ? 'desc' : 'asc';  
1327. else
1328. this.options.sortName = $this.data('field');  
1329. this.options.sortOrder = $this.data('order') === 'asc' ? 'desc' : 'asc';  
1330.         }  
1331. this.trigger('sort', this.options.sortName, this.options.sortOrder);  
1332.   
1333. this.add($this_).data('order', this.options.sortOrder);  
1334.   
1335. this.getCaret();// 更新排序箭头样式
1336.   
1337. if (this.options.sidePagination === 'server') {  
1338. this.initServer(this.options.silentSort);  
1339. return;  
1340.         }  
1341.   
1342. this.initSort();  
1343. this.initBody();  
1344.     };  
1345.   
1346. // 创建工具栏内的用户自定义按钮组、分页显示隐藏切换按钮、刷新按钮、筛选条目按钮
1347. //      以及卡片表格显示切换按钮、搜索框,并绑定相应事件;
1348. // 筛选条目时触发column-switch事件;
1349. function
1350. var that = this,  
1351.             html = [],  
1352.             timeoutId = 0,  
1353.             $keepOpen,  
1354.             $search,  
1355.             switchableCount = 0;  
1356.   
1357. if (this.$toolbar.find('.bars').children().length) {  
1358. 'body').append($(this.options.toolbar));  
1359.         }  
1360. this.$toolbar.html('');  
1361.   
1362. if (typeof this.options.toolbar === 'string' || typeof this.options.toolbar === 'object') {  
1363. '<div class="bars pull-%s"></div>', this.options.toolbarAlign))  
1364. this.$toolbar)  
1365. this.options.toolbar));  
1366. // $(this.options.toolbar)引用对象形式,只会在页面上创建一次
1367.         }  
1368.   
1369. '<div class="columns columns-%s btn-group pull-%s">',  
1370. this.options.buttonsAlign, this.options.buttonsAlign)];  
1371.   
1372. if (typeof this.options.icons === 'string') {  
1373. // 调用window[options.icons]函数显示按钮列表
1374. this.options.icons = calculateObjectValue(null, this.options.icons);  
1375.         }  
1376.   
1377. // 显示隐藏分页按钮
1378. if (this.options.showPaginationSwitch) {  
1379. '<button class="btn btn-default" type="button" name="paginationSwitch" title="%s">',  
1380. this.options.formatPaginationSwitch()),  
1381. '<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.paginationSwitchDown),  
1382. '</button>');  
1383.         }  
1384.   
1385. // 刷新按钮
1386. if (this.options.showRefresh) {  
1387. '<button class="btn btn-default'
1388. ' btn-%s', this.options.iconSize) +  
1389. '" type="button" name="refresh" title="%s">',  
1390. this.options.formatRefresh()),  
1391. '<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.refresh),  
1392. '</button>');  
1393.         }  
1394.   
1395. // 卡片式显示或表格详情显示切换按钮
1396. if (this.options.showToggle) {  
1397. '<button class="btn btn-default'
1398. ' btn-%s', this.options.iconSize) +  
1399. '" type="button" name="toggle" title="%s">',  
1400. this.options.formatToggle()),  
1401. '<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.toggle),  
1402. '</button>');  
1403.         }  
1404.   
1405. // 筛选条目按钮,并创建下拉列表
1406. if (this.options.showColumns) {  
1407. '<div class="keep-open btn-group" title="%s">',  
1408. this.options.formatColumns()),  
1409. '<button type="button" class="btn btn-default'
1410. ' btn-%s', this.options.iconSize) +  
1411. ' dropdown-toggle" data-toggle="dropdown">',  
1412. '<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.columns),  
1413. ' <span class="caret"></span>',  
1414. '</button>',  
1415. '<ul class="dropdown-menu" role="menu">');  
1416.   
1417. this.columns, function
1418. if
1419. return;  
1420.                 }  
1421.   
1422. if
1423. return;  
1424.                 }  
1425.   
1426. var checked = column.visible ? ' checked="checked"' : '';  
1427.   
1428. if
1429. '<li>'
1430. '<label><input type="checkbox" data-field="%s" value="%s"%s> %s</label>'
1431. '</li>', column.field, i, checked, column.title));  
1432.                     switchableCount++;  
1433.                 }  
1434.             });  
1435. '</ul>',  
1436. '</div>');  
1437.         }  
1438.   
1439. '</div>');  
1440.   
1441. if (this.showToolbar || html.length > 2) {  
1442. this.$toolbar.append(html.join(''));  
1443.         }  
1444.   
1445. // 绑定分页显示隐藏按钮点击事件
1446. if (this.options.showPaginationSwitch) {  
1447. this.$toolbar.find('button[name="paginationSwitch"]')  
1448. 'click').on('click', $.proxy(this.togglePagination, this));  
1449.         }  
1450.   
1451. // 绑定刷新按钮点击事件
1452. if (this.options.showRefresh) {  
1453. this.$toolbar.find('button[name="refresh"]')  
1454. 'click').on('click', $.proxy(this.refresh, this));  
1455.         }  
1456.   
1457. // 绑定卡片式显示、表格详情显示切换按钮点击事件
1458. if (this.options.showToggle) {  
1459. this.$toolbar.find('button[name="toggle"]')  
1460. 'click').on('click', function
1461.                     that.toggleView();  
1462.                 });  
1463.         }  
1464.   
1465. // 帮点筛选条目下拉列表中复选框的点击事件,筛选条目按钮点击事件由bootstrap提供
1466. if (this.options.showColumns) {  
1467. this.$toolbar.find('.keep-open');  
1468.   
1469. if (switchableCount <= this.options.minimumCountColumns) {  
1470. 'input').prop('disabled', true);  
1471.             }  
1472.   
1473. 'li').off('click').on('click', function
1474. // 阻止事件冒泡,并阻止同类型事件的冒泡
1475.             });  
1476. 'input').off('click').on('click', function
1477. var $this = $(this);  
1478.   
1479.                 that.toggleColumn(getFieldIndex(that.columns,  
1480. this).data('field')), $this.prop('checked'), false);  
1481. 'column-switch', $(this).data('field'), $this.prop('checked'));  
1482.             });  
1483.         }  
1484.   
1485. // 创建搜索框,并绑定搜索事件
1486. if (this.options.search) {  
1487.             html = [];  
1488.             html.push(  
1489. '<div class="pull-' + this.options.searchAlign + ' search">',  
1490. '<input class="form-control'
1491. ' input-%s', this.options.iconSize) +  
1492. '" type="text" placeholder="%s">',  
1493. this.options.formatSearch()),  
1494. '</div>');  
1495.   
1496. this.$toolbar.append(html.join(''));  
1497. this.$toolbar.find('.search input');  
1498. 'keyup drop').on('keyup drop', function
1499. if
1500. if
1501. return;  
1502.                     }  
1503.                 }  
1504.   
1505.                 clearTimeout(timeoutId);  
1506. function
1507.                     that.onSearch(event);  
1508.                 }, that.options.searchTimeOut);  
1509.             });  
1510.   
1511. if
1512. 'mouseup').on('mouseup', function
1513.                     clearTimeout(timeoutId);   
1514. function
1515.                         that.onSearch(event);  
1516.                     }, that.options.searchTimeOut);  
1517.                 });  
1518.             }  
1519.         }  
1520.     };  
1521.   
1522. // this.text,this.options.text设为搜索框去除两端空白的值,pageNumber设为1;
1523. // 调用initSearch将筛选本地数据;调用updatePagination完成远程交互或单渲染本地数据;
1524. // 触发search事件;
1525. function
1526. var
1527.   
1528. if (this.options.trimOnSearch && $(event.currentTarget).val() !== text) {  
1529.             $(event.currentTarget).val(text);  
1530.         }  
1531.   
1532. if (text === this.searchText) {  
1533. return;  
1534.         }  
1535. this.searchText = text;  
1536. this.options.searchText = text;  
1537.   
1538. this.options.pageNumber = 1;  
1539. this.initSearch();  
1540. this.updatePagination();  
1541. this.trigger('search', text);  
1542.     };  
1543.   
1544. // 前台分页的情况下,先通过this.filterColumns通过this.option.data过滤this.data数据;
1545. // 再通过搜索文本过滤this.data数据;
1546. // 输入文本和经this.header.formatters或window[this.header.formatters]函数格式化匹配比对;
1547. function
1548. var that = this;  
1549.   
1550. if (this.options.sidePagination !== 'server') {  
1551. var s = this.searchText && this.searchText.toLowerCase();  
1552. var f = $.isEmptyObject(this.filterColumns) ? null : this.filterColumns;  
1553.   
1554. // options.data和this.filterColumns相符则在this.data中保留,不相符则在this.data中删除
1555. this.data = f ? $.grep(this.options.data, function
1556. for (var key in
1557. if
1558. if
1559. return false;  
1560.                         }  
1561. else if
1562. return false;  
1563.                     }  
1564.                 }  
1565. return true;  
1566. this.options.data;  
1567.   
1568. // 在前台分页的情况下检索数据,使用$.grep返回筛选后的数组内容
1569. this.data = s ? $.grep(this.data, function
1570. for (var key in
1571.                     key = $.isNumeric(key) ? parseInt(key, 10) : key;  
1572. var value = item[key],//data[key]
1573. // 当key为field时,getFieldIndex获取相应列条目数据fieldIndex值,否则返回-1
1574. // 问题,可以设置if语句排除key不等于field的情况,j和index等值
1575.                         column = that.columns[getFieldIndex(that.columns, key)],  
1576.                         j = $.inArray(key, that.header.fields);  
1577.   
1578. if
1579.                         value = calculateObjectValue(column,  
1580.                             that.header.formatters[j], [value, item, i], value);  
1581.                     }  
1582.   
1583. var
1584. if (index !== -1 && that.header.searchables[index] && (typeof value === 'string' || typeof value === 'number')) {  
1585. if
1586. if ((value + '').toLowerCase() === s) {  
1587. return true;  
1588.                             }  
1589. else
1590. if ((value + '').toLowerCase().indexOf(s) !== -1) {  
1591. return true;  
1592.                             }  
1593.                         }  
1594.                     }  
1595.                 }  
1596. return false;  
1597. this.data;  
1598.         }  
1599.     };  
1600.   
1601. // 初始化设置分页相关页面信息显示情况,包括当前页显示第几条到第几天数据,共几条数据,每页显示几条数据;
1602. // 以及每页显示数据量切换按钮,选择页面的分页栏显示情况,再绑定事件;
1603. // 通过options.pageNumber获取this.pageFrom、this.pageTo,以便前台分页时initBody获取相应数据;
1604. function
1605. if (!this.options.pagination) {  
1606. this.$pagination.hide();  
1607. return;  
1608. else
1609. this.$pagination.show();  
1610.         }  
1611.   
1612. var that = this,  
1613.             html = [],  
1614. false,// 为真时,显示所有数据条目,同时显示数据量切换按钮文本改为options.formatAllRows()
1615.             i, from, to,  
1616.             $pageList,  
1617.             $first, $pre,  
1618.             $next, $last,  
1619.             $number,  
1620. this.getData();  
1621.   
1622. if (this.options.sidePagination !== 'server') {  
1623. this.options.totalRows = data.length;// 数据总条数
1624.         }  
1625.   
1626. // this.options.totalRows数据总条数;
1627. // this.options.pageSize一页显示几条数据,显示数据量切换按钮默认文本;
1628. // this.totalPages总页数,与this.options.totalPages似没有差别,疑为插件作者未调优代码;
1629. // this.options.totalPages总页数;
1630. // this.options.pageNumber当前页页码;
1631. // this.pageFrom当前页从总数据的第几条开始;
1632. // this.pageTo当前页到总数据的第几条为止;
1633. if (this.options.totalRows) {  
1634. // 当options.pageSize和options.formatAllRows()相同时,意味显示所有条目
1635. // 或者options.pageSize即为options.totalRows总条目数,且options.formatAllRows()在pageList设置中
1636. // $allSelected记为真,页面显示数据量切换按钮的显示文本为options.formatAllRows()
1637. if (this.options.pageSize === this.options.formatAllRows()) {  
1638. this.options.pageSize = this.options.totalRows;  
1639. true;  
1640. else if (this.options.pageSize === this.options.totalRows) {  
1641. var pageLst = typeof this.options.pageList === 'string'
1642. this.options.pageList.replace('[', '').replace(']', '')  
1643. '').toLowerCase().split(',') : this.options.pageList;// 每页显示数据条数列表项
1644. if ($.inArray(this.options.formatAllRows().toLowerCase(), pageLst)  > -1) {  
1645. true;  
1646.                 }  
1647.             }  
1648.   
1649. this.totalPages = ~~((this.options.totalRows - 1) / this.options.pageSize) + 1;  
1650. // -1针对this.options.totalRows是this.options.pageSize倍数的情况
1651.   
1652. this.options.totalPages = this.totalPages;  
1653.         }  
1654. if (this.totalPages > 0 && this.options.pageNumber > this.totalPages) {  
1655. this.options.pageNumber = this.totalPages;  
1656.         }  
1657.   
1658. this.pageFrom = (this.options.pageNumber - 1) * this.options.pageSize + 1;  
1659. this.pageTo = this.options.pageNumber * this.options.pageSize;  
1660. if (this.pageTo > this.options.totalRows) {  
1661. this.pageTo = this.options.totalRows;  
1662.         }  
1663.   
1664. // 分页提示文案,即总共包含几条数据,或当前页从第几条到第几条
1665.         html.push(  
1666. '<div class="pull-' + this.options.paginationDetailHAlign + ' pagination-detail">',  
1667. '<span class="pagination-info">',  
1668. this.options.onlyInfoPagination ? this.options.formatDetailPagination(this.options.totalRows) :  
1669. this.options.formatShowingRows(this.pageFrom, this.pageTo, this.options.totalRows),  
1670. '</span>');  
1671.   
1672. if (!this.options.onlyInfoPagination) {  
1673. '<span class="page-list">');  
1674.   
1675. // 分页提示文案,即每页显示几条数据,每页显示数据量下拉列表
1676. var
1677. '<span class="btn-group %s">',  
1678. this.options.paginationVAlign === 'top' || this.options.paginationVAlign === 'both'
1679. 'dropdown' : 'dropup'),  
1680. '<button type="button" class="btn btn-default '
1681. ' btn-%s', this.options.iconSize) +  
1682. ' dropdown-toggle" data-toggle="dropdown">',  
1683. '<span class="page-size">',  
1684. this.options.formatAllRows() : this.options.pageSize,  
1685. '</span>',  
1686. ' <span class="caret"></span>',  
1687. '</button>',  
1688. '<ul class="dropdown-menu" role="menu">'
1689.                 ],  
1690. this.options.pageList;  
1691.   
1692. // 每页切换条目数下拉列表实现
1693. if (typeof this.options.pageList === 'string') {  
1694. var list = this.options.pageList.replace('[', '').replace(']', '')  
1695. '').split(',');  
1696.   
1697.                 pageList = [];  
1698. function
1699.                     pageList.push(value.toUpperCase() === that.options.formatAllRows().toUpperCase() ?  
1700.                         that.options.formatAllRows() : +value);  
1701.                 });  
1702.             }  
1703. function
1704. // this.options.smartDisplay为真,当总页数为1时,屏蔽分页,以及下拉列表仅有一条时,屏蔽切换条目数按钮下拉功能
1705. if
1706. var
1707. if
1708. ' class="active"' : '';  
1709. else
1710. ' class="active"' : '';  
1711.                     }  
1712. '<li%s><a href="javascript:void(0)">%s</a></li>', active, page));  
1713.                 }  
1714.             });  
1715.   
1716. '</ul></span>');  
1717.   
1718. this.options.formatRecordsPerPage(pageNumber.join('')));  
1719. '</span>');  
1720.   
1721. // 分页
1722. // 策略:通过from初始页、to结尾页,先设置首页起的显示情况,再设置...按钮的显示情况,接着尾页的显示情况
1723. // 顺序设置,由一般到具体
1724. '</div>',  
1725. '<div class="pull-' + this.options.paginationHAlign + ' pagination">',  
1726. '<ul class="pagination' + sprintf(' pagination-%s', this.options.iconSize) + '">',  
1727. '<li class="page-pre"><a href="javascript:void(0)">' + this.options.paginationPreText + '</a></li>');  
1728.   
1729. if (this.totalPages < 5) {  
1730.                 from = 1;  
1731. this.totalPages;  
1732. else
1733. this.options.pageNumber - 2;  
1734.                 to = from + 4;  
1735. if
1736.                     from = 1;  
1737.                     to = 5;  
1738.                 }  
1739. if (to > this.totalPages) {  
1740. this.totalPages;  
1741.                     from = to - 4;  
1742.                 }  
1743.             }  
1744.   
1745. // 总页数大于6时,显示第一页,最后一页,pageNumber--,pageNumber,pageNumber++,以及两串...
1746. if (this.totalPages >= 6) {  
1747. if (this.options.pageNumber >= 3) {  
1748. '<li class="page-first' + (1 === this.options.pageNumber ? ' active' : '') + '">',  
1749. '<a href="javascript:void(0)">', 1, '</a>',  
1750. '</li>');  
1751.   
1752.                     from++;  
1753.                 }  
1754.   
1755. if (this.options.pageNumber >= 4) {  
1756. // from--显示第二页按钮
1757. if (this.options.pageNumber == 4 || this.totalPages == 6 || this.totalPages == 7) {  
1758.                         from--;  
1759. else
1760. '<li class="page-first-separator disabled">',  
1761. '<a href="javascript:void(0)">...</a>',  
1762. '</li>');  
1763.                     }  
1764.   
1765.                     to--;  
1766.                 }  
1767.             }  
1768.   
1769.   
1770. // 根据上一条if语句form++的情况,pageNumber临近尾页的时候执行from--,显示后五条
1771. if (this.totalPages >= 7) {  
1772. if (this.options.pageNumber >= (this.totalPages - 2)) {  
1773.                     from--;  
1774.                 }  
1775.             }  
1776.   
1777. // 根据上一条if语句to--的情况,pageNumber挨近尾页的时候执行to--,显示后五条
1778. if (this.totalPages == 6) {  
1779. if (this.options.pageNumber >= (this.totalPages - 2)) {  
1780.                     to++;  
1781.                 }  
1782. else if (this.totalPages >= 7) {  
1783. if (this.totalPages == 7 || this.options.pageNumber >= (this.totalPages - 3)) {  
1784.                     to++;  
1785.                 }  
1786.             }  
1787.   
1788. for
1789. '<li class="page-number' + (i === this.options.pageNumber ? ' active' : '') + '">',  
1790. '<a href="javascript:void(0)">', i, '</a>',  
1791. '</li>');  
1792.             }  
1793.   
1794. if (this.totalPages >= 8) {  
1795. if (this.options.pageNumber <= (this.totalPages - 4)) {  
1796. '<li class="page-last-separator disabled">',  
1797. '<a href="javascript:void(0)">...</a>',  
1798. '</li>');  
1799.                 }  
1800.             }  
1801.   
1802. if (this.totalPages >= 6) {  
1803. if (this.options.pageNumber <= (this.totalPages - 3)) {  
1804. '<li class="page-last' + (this.totalPages === this.options.pageNumber ? ' active' : '') + '">',  
1805. '<a href="javascript:void(0)">', this.totalPages, '</a>',  
1806. '</li>');  
1807.                 }  
1808.             }  
1809.   
1810.             html.push(  
1811. '<li class="page-next"><a href="javascript:void(0)">' + this.options.paginationNextText + '</a></li>',  
1812. '</ul>',  
1813. '</div>');  
1814.         }  
1815. this.$pagination.html(html.join(''));  
1816.   
1817. if (!this.options.onlyInfoPagination) {  
1818. this.$pagination.find('.page-list a');// 每页显示数据量切换按钮
1819. this.$pagination.find('.page-first');  
1820. this.$pagination.find('.page-pre');  
1821. this.$pagination.find('.page-next');  
1822. this.$pagination.find('.page-last');  
1823. this.$pagination.find('.page-number');  
1824.   
1825. if (this.options.smartDisplay) {  
1826. if (this.totalPages <= 1) {  
1827. this.$pagination.find('div.pagination').hide();  
1828.                 }  
1829. if (pageList.length < 2 || this.options.totalRows <= pageList[0]) {  
1830. this.$pagination.find('span.page-list').hide();  
1831.                 }  
1832.   
1833. this.$pagination[this.getData().length ? 'show' : 'hide']();  
1834.             }  
1835.   
1836. if
1837. this.options.pageSize = this.options.formatAllRows();  
1838.             }  
1839.   
1840. // 绑定事件
1841. 'click').on('click', $.proxy(this.onPageListChange, this));  
1842. 'click').on('click', $.proxy(this.onPageFirst, this));  
1843. 'click').on('click', $.proxy(this.onPagePre, this));  
1844. 'click').on('click', $.proxy(this.onPageNext, this));  
1845. 'click').on('click', $.proxy(this.onPageLast, this));  
1846. 'click').on('click', $.proxy(this.onPageNumber, this));  
1847.         }  
1848.     };  
1849.   
1850. // 分页点选按钮有disabled属性则返回,无则重新布局分页显示面板;
1851. // maintainSelected为否时,调用resetRows重置复选框为不选中,调用initServer交互或initbody渲染页面;
1852. // initSever由后台返回数据;
1853. // initPagination通过options.pageNumber取得options.pageFrom、options.pageTo;
1854. // initBody由options.pageFrom、options.pageTo获取需要渲染的数据data;
1855. // 触发page-change事件;
1856. function
1857. // Fix #171: IE disabled button can be clicked bug.
1858. if (event && $(event.currentTarget).hasClass('disabled')) {  
1859. return;  
1860.         }  
1861.   
1862. if (!this.options.maintainSelected) {  
1863. this.resetRows();  
1864.         }  
1865.   
1866. this.initPagination();  
1867. if (this.options.sidePagination === 'server') {  
1868. this.initServer();  
1869. else
1870. this.initBody();  
1871.         }  
1872.   
1873. this.trigger('page-change', this.options.pageNumber, this.options.pageSize);  
1874.     };  
1875.   
1876. // 每页显示数据量下拉列表选中时触发,替换每页显示数据量按钮文本;
1877. // 更新options.pageSize,通过updatePagination调用initPagination设置this.pageFrom、this.pageTo;
1878. // updatePagination再调用initServer完成交互,或initBody渲染本地数据;
1879. function
1880. var $this
1881.   
1882. this.parent().addClass('active').siblings().removeClass('active');  
1883. this.options.pageSize = $this.text().toUpperCase() === this.options.formatAllRows().toUpperCase() ?  
1884. this.options.formatAllRows() : +$this.text();  
1885. this.$toolbar.find('.page-size').text(this.options.pageSize);  
1886.   
1887. this.updatePagination(event);  
1888.     };  
1889.   
1890. // 更新options.pageNumber,通过updatePagination调用initPagination设置this.pageFrom、this.pageTo;
1891. // updatePagination再调用initServer完成交互,或initBody渲染本地数据;
1892. // 跳转分页首页
1893. function
1894. this.options.pageNumber = 1;  
1895. this.updatePagination(event);  
1896.     };  
1897. // 跳转分页上一页
1898. function
1899. if ((this.options.pageNumber - 1) == 0) {  
1900. this.options.pageNumber = this.options.totalPages;  
1901. else
1902. this.options.pageNumber--;  
1903.         }  
1904. this.updatePagination(event);  
1905.     };  
1906. // 跳转分页下一页
1907. function
1908. if ((this.options.pageNumber + 1) > this.options.totalPages) {  
1909. this.options.pageNumber = 1;  
1910. else
1911. this.options.pageNumber++;  
1912.         }  
1913. this.updatePagination(event);  
1914.     };  
1915. // 跳转尾页
1916. function
1917. this.options.pageNumber = this.totalPages;  
1918. this.updatePagination(event);  
1919.     };  
1920. // 由页码跳转
1921. function
1922. if (this.options.pageNumber === +$(event.currentTarget).text()) {  
1923. return;  
1924.         }  
1925. this.options.pageNumber = +$(event.currentTarget).text();  
1926. this.updatePagination(event);  
1927.     };  
1928.   
1929. // fixedScroll为否的情况下,表体移动到顶部;
1930. // 通过this.pageFrom、this.pageTo截取this.getData()数据row渲染表体,主要是tbody>tr以及tbody>tr>td;
1931. // tbody>tr的data-index设为行号,class、id为row._class、row._id,样式、data数据通过调用函数获得;
1932. // tbody>tr>td区分为卡片显示和表格显示两类,显示值取经this.header.formatters[i]处理后的row[field];
1933. // tbody>tr>td其他class、id、title、data取row[_field_class]等;
1934. // 绑定展开卡片详情按钮点击事件、复选框点击事件、this.header.events中的事件;
1935. // 触发post-body、pre-body事件; 
1936. function
1937. var that = this,  
1938.             html = [],  
1939. this.getData();// 获取搜索过滤后的数据
1940. // data的数据格式为对象形式
1941. // [{   // 行tr中的属性设置
1942. //      _data:{
1943. //          index:1,// 后续会自动赋值为数据在当前页的所在行号
1944. //          field:field
1945. //      },
1946. //      _id:id,
1947. //      _class:class,
1948. //      field1:value1,field2:value2, //填充在单元格中的显示内容,从this.header.fields数组中获取属性名field1等
1949. //      _field_id
1950. // }] // 每一行特定的样式、属性根据this.options.rowStyle、this.options.rowAttributes获取
1951. // 数组形式
1952. // [["field","class"]] // 数组形式不能对每一行添加特定的data属性、id以及class
1953. //                     // 特定的的样式、属性仍可由this.options.rowStyle、this.options.rowAttributes获取
1954. //                     // 以及data-index添加行号、data-uniqueId每行的唯一标识,根据options.uniqueId从data中获取
1955. //                     
1956. // tr以及checkbox中data数组的序号data-index,以便于获取data[data-index]数据调用
1957.   
1958. this.trigger('pre-body', data);  
1959.   
1960. this.$body = this.$el.find('>tbody');  
1961. if (!this.$body.length) {  
1962. this.$body = $('<tbody></tbody>').appendTo(this.$el);  
1963. // 页面初始化存在tbody>tr>td的情况下,this.options.data数据由initTable获取
1964.   
1965. //Fix #389 Bootstrap-table-flatJSON is not working
1966. // 未作分页或后台分页的情况返回所有数据
1967. if (!this.options.pagination || this.options.sidePagination === 'server') {  
1968. this.pageFrom = 1;  
1969. this.pageTo = data.length;  
1970.         }  
1971.   
1972. for (var i = this.pageFrom - 1; i < this.pageTo; i++) {  
1973. var
1974. // 行数据信息row
1975.                 style = {},  
1976.                 csses = [],  
1977. '',  
1978.                 attributes = {},  
1979.                 htmlAttributes = [];  
1980.   
1981. // 通过options.rowStyle(row,index)函数或window[options.rowStyle](row,index)获取tbody>tr样式
1982. this.options, this.options.rowStyle, [item, i], style);  
1983. if
1984. for (key in
1985. ': '
1986.                 }  
1987.             }  
1988.   
1989. // 通过options.rowAttributes(row,index)函数或window[options.rowAttributes](row,index)获取tbody>tr属性
1990. this.options,  
1991. this.options.rowAttributes, [item, i], attributes);  
1992. if
1993. for (key in
1994. '%s="%s"', key, escapeHTML(attributes[key])));  
1995.                 }  
1996.             }  
1997.   
1998. // 通过row._data,row._id,row._class,row[options.uniqueId]渲染tbody>tr
1999. if
2000. function
2001. if (k === 'index') {  
2002. return;  
2003.                     }  
2004. ' data-%s="%s"', k, v);  
2005.                 });  
2006.             }  
2007.   
2008. '<tr',  
2009. ' %s', htmlAttributes.join(' ')),  
2010. ' id="%s"', $.isArray(item) ? undefined : item._id),  
2011. ' class="%s"', style.classes || ($.isArray(item) ? undefined : item._class)),  
2012. ' data-index="%s"', i),  
2013. ' data-uniqueid="%s"', item[this.options.uniqueId]),  
2014. '%s', data_),  
2015. '>'
2016.             );  
2017.   
2018. // 卡片式显示跨列
2019. if (this.options.cardView) {  
2020. '<td colspan="%s">', this.header.fields.length));  
2021.             }  
2022.   
2023. // 表格显示时添加每行数据前点击展示卡片式详情按钮
2024. if (!this.options.cardView && this.options.detailView) {  
2025. '<td>',  
2026. '<a class="detail-icon" href="javascript:">',  
2027. '<i class="%s %s"></i>', this.options.iconsPrefix, this.options.icons.detailOpen),  
2028. '</a>',  
2029. '</td>');  
2030.             }  
2031.   
2032. // 遍历this.header.fields获取主键field值,再由主键field拼接row中的属性取值,包括row[field]
2033. // 显示文本row[field]调用对应的this.header.formatter[j]处理后获取
2034. // j即列坐标
2035. this.header.fields, function
2036. var text = '',  
2037. // 获取row[field]
2038. '',  
2039.                     cellStyle = {},  
2040. '',  
2041.                     class_ = that.header.classes[j],  
2042. '',  
2043. '',  
2044. '',  
2045.                     column = that.columns[getFieldIndex(that.columns, field)];  
2046.   
2047. if (!column.visible) {// 筛选时设置
2048. return;  
2049.                 }  
2050.   
2051. 'style="%s"', csses.concat(that.header.styles[j]).join('; '));  
2052.   
2053. // 调用that.header.formatters[j](item.field,item,i)格式化显示内容
2054. // 特别当单元格是复选框的时候,value返回值可以是对象形式{checked:true;disabled:true},此时无显示文本
2055.                 value = calculateObjectValue(column,  
2056.                     that.header.formatters[j], [value, item, i], value);  
2057.   
2058. if (item['_' + field + '_id']) {  
2059. ' id="%s"', item['_' + field + '_id']);  
2060.                 }  
2061. if (item['_' + field + '_class']) {  
2062. ' class="%s"', item['_' + field + '_class']);  
2063.                 }  
2064. if (item['_' + field + '_rowspan']) {  
2065. ' rowspan="%s"', item['_' + field + '_rowspan']);  
2066.                 }  
2067. if (item['_' + field + '_title']) {  
2068. ' title="%s"', item['_' + field + '_title']);  
2069.                 }  
2070. // 调用that.header.cellStyles[j](item.field,item,i)设置单元格显示样式
2071.                 cellStyle = calculateObjectValue(that.header,  
2072.                     that.header.cellStyles[j], [value, item, i], cellStyle);  
2073. if
2074. ' class="%s"', cellStyle.classes);  
2075.                 }  
2076. if
2077. var
2078. for (var key in
2079. ': '
2080.                     }  
2081. 'style="%s"', csses_.concat(that.header.styles[j]).join('; '));  
2082.                 }  
2083.   
2084. if (item['_' + field + '_data'] && !$.isEmptyObject(item['_' + field + '_data'])) {  
2085. '_' + field + '_data'], function
2086. if (k === 'index') {  
2087. return;  
2088.                         }  
2089. ' data-%s="%s"', k, v);  
2090.                     });  
2091.                 }  
2092.   
2093. if
2094. 'checkbox'
2095. 'radio'
2096.   
2097.                     text = [sprintf(that.options.cardView ?  
2098. '<div class="card-view %s">' : '<td class="bs-checkbox %s">', column['class'] || ''),  
2099. '<input'
2100. ' data-index="%s"', i) +  
2101. ' name="%s"', that.options.selectItemName) +  
2102. ' type="%s"', type) +  
2103. ' value="%s"', item[that.options.idField]) +  
2104. ' checked="%s"', value === true
2105. 'checked'
2106. ' disabled="%s"', !column.checkboxEnabled ||  
2107. 'disabled'
2108. ' />',  
2109. typeof value === 'string' ? value : '',  
2110. '</div>' : '</td>'
2111. '');  
2112.   
2113. // 复选框上传内容字段名属性后添加true选中/false未选中值
2114. true
2115. else
2116. typeof value === 'undefined' || value === null
2117.                         that.options.undefinedText : value;  
2118.   
2119. // getPropertyFromOther卡片式显示时获取标题栏的文本内容
2120. '<div class="card-view">',  
2121. '<span class="title" %s>%s</span>', style,  
2122. 'field', 'title', field)) : '',  
2123. '<span class="value">%s</span>', value),  
2124. '</div>'
2125. '') : [sprintf('<td%s %s %s %s %s %s>', id_, class_, style, data_, rowspan_, title_),  
2126.                         value,  
2127. '</td>'
2128. '');  
2129.   
2130. if (that.options.cardView && that.options.smartDisplay && value === '') {  
2131. // 占位符,以利于根据元素序号准确地绑定事件
2132. '<div class="card-view"></div>';  
2133.                     }  
2134.                 }  
2135.   
2136.                 html.push(text);  
2137.             });  
2138.   
2139. if (this.options.cardView) {  
2140. '</td>');  
2141.             }  
2142.   
2143. '</tr>');  
2144.         }  
2145.   
2146. if
2147. '<tr class="no-records-found">',  
2148. '<td colspan="%s">%s</td>',  
2149. this.$header.find('th').length, this.options.formatNoMatches()),  
2150. '</tr>');  
2151.         }  
2152.   
2153. this.$body.html(html.join(''));  
2154.   
2155. if
2156. this.scrollTo(0);  
2157.         }  
2158.   
2159. // 点击单元格触发单元格以及当前行点击事件,复选框则勾选
2160. this.$body.find('> tr[data-index] > td').off('click dblclick').on('click dblclick', function
2161. var $td = $(this),  
2162.                 $tr = $td.parent(),  
2163. 'index')],// 获取当前行的data[data-index]数据调用
2164. // 返回一行内单元格所在的列坐标
2165.                 field = that.header.fields[that.options.detailView && !that.options.cardView ? index - 1 : index],  
2166.                 column = that.columns[getFieldIndex(that.columns, field)],  
2167.                 value = getItemField(item, field, that.options.escape);  
2168.   
2169. if ($td.find('.detail-icon').length) {  
2170. return;  
2171.             }  
2172.   
2173. // 单元格点击事件传入单元格的field(借此获取data中的有关数据)、显示内容value值data[data-index][field]、
2174. // 当前行data数据item值data[data-index]、单元格jquery对象$td
2175. 'click' ? 'click-cell' : 'dbl-click-cell', field, value, item, $td);  
2176. // 行点击事件传入当前行data数据item值data[data-index]以及当前行jquery对象$tr
2177. 'click' ? 'click-row' : 'dbl-click-row', item, $tr);  
2178.   
2179. if (e.type === 'click'
2180. var $selectItem = $tr.find(sprintf('[name="%s"]', that.options.selectItemName));  
2181. if
2182. // #144: .trigger('click') bug
2183.                 }  
2184.             }  
2185.         });  
2186.   
2187. // 展开折叠卡片式详情
2188. this.$body.find('> tr[data-index] > td > .detail-icon').off('click').on('click', function
2189. var $this = $(this),  
2190. this.parent().parent(),  
2191. 'index'),  
2192. // Fix #980 Detail view, when searching, returns wrong row
2193.   
2194. if ($tr.next().is('tr.detail-view')) {  
2195. this.find('i').attr('class', sprintf('%s %s', that.options.iconsPrefix, that.options.icons.detailOpen));  
2196.                 $tr.next().remove();  
2197. 'collapse-row', index, row);  
2198. else
2199. this.find('i').attr('class', sprintf('%s %s', that.options.iconsPrefix, that.options.icons.detailClose));  
2200. '<tr class="detail-view"><td colspan="%s"></td></tr>', $tr.find('td').length));  
2201. var $element = $tr.next().find('td');  
2202. // options.detailFormatter执行后渲染折叠式卡片详情文本内容,包含html标签、Dom元素
2203. var content = calculateObjectValue(that.options, that.options.detailFormatter, [index, row, $element], '');  
2204. if($element.length === 1) {  
2205.                     $element.append(content);  
2206.                 }  
2207. 'expand-row', index, row, $element);  
2208.             }  
2209.             that.resetView();  
2210.         });  
2211.   
2212. // 绑定复选框点击事件
2213. this.$selectItem = this.$body.find(sprintf('[name="%s"]', this.options.selectItemName));  
2214. this.$selectItem.off('click').on('click', function
2215.             event.stopImmediatePropagation();  
2216.   
2217. var $this = $(this),  
2218. this.prop('checked'),  
2219. this.data('index')];  
2220.   
2221. if (that.options.maintainSelected && $(this).is(':radio')) {  
2222. function
2223. false;  
2224.                 });  
2225.             }  
2226.   
2227.             row[that.header.stateField] = checked;  
2228.   
2229. if
2230. this).each(function
2231. this).data('index')][that.header.stateField] = false;  
2232.                 });  
2233. ':checked').not(this).prop('checked', false);  
2234.             }  
2235.   
2236.             that.updateSelected();  
2237. 'check' : 'uncheck', row, $this);  
2238.         });  
2239.   
2240. // 由this.header.events为tbody>tr>td中子元素绑定事件
2241. this.header.events, function
2242. if
2243. return;  
2244.             }  
2245. // fix bug, if events is defined with namespace
2246. if (typeof events === 'string') {  
2247. null, events);  
2248.             }  
2249.   
2250. var
2251.                 fieldIndex = $.inArray(field, that.getVisibleFields());  
2252.   
2253. if
2254.                 fieldIndex += 1;  
2255.             }  
2256.   
2257. for (var key in
2258. '>tr:not(.no-records-found)').each(function
2259. var $tr = $(this),  
2260. '.card-view' : 'td').eq(fieldIndex),  
2261. ' '),  
2262.                         name = key.substring(0, index),  
2263.                         el = key.substring(index + 1),  
2264.                         func = events[key];  
2265.   
2266. function
2267. var index = $tr.data('index'),  
2268.                             row = that.data[index],  
2269.                             value = row[field];  
2270.   
2271. this, [e, value, row, index]);  
2272.                     });  
2273.                 });  
2274.             }  
2275.         });  
2276.   
2277. this.updateSelected();  
2278. this.resetView();  
2279.   
2280. this.trigger('post-body');  
2281.     };  
2282.   
2283. // 触发ajax事件(可以是用户自定义的方法options.ajax),上传数据格式为
2284. // {
2285. //      searchText:this.searchText,
2286. //      sortName:this.options.sortName,
2287. //      sortOrder:this.options.sortOrder,
2288. //      pageSize/limit:...,
2289. //      pageNumber/offset:...,
2290. //      [filter]:...,
2291. //      query:...
2292. // }
2293. // 触发上传成功调用this.load方法,触发load-success事件、上传失败load-error事件
2294. function
2295. var that = this,  
2296.             data = {},  
2297.             params = {  
2298. this.searchText,  
2299. this.options.sortName,  
2300. this.options.sortOrder  
2301.             },  
2302. // ajax配置
2303.   
2304. if(this.options.pagination) {  
2305. this.options.pageSize === this.options.formatAllRows() ?  
2306. this.options.totalRows : this.options.pageSize;  
2307. this.options.pageNumber;  
2308.         }  
2309.   
2310. if (!this.options.url && !this.options.ajax) {  
2311. return;  
2312.         }  
2313.   
2314. // 意义???
2315. if (this.options.queryParamsType === 'limit') {  
2316.             params = {  
2317.                 search: params.searchText,  
2318.                 sort: params.sortName,  
2319.                 order: params.sortOrder  
2320.             };  
2321. if (this.options.pagination) {  
2322. this.options.pageSize === this.options.formatAllRows() ?  
2323. this.options.totalRows : this.options.pageSize;  
2324. this.options.pageSize === this.options.formatAllRows() ?  
2325. this.options.pageSize * (this.options.pageNumber - 1);  
2326.             }  
2327.         }  
2328.   
2329. // this.filterColumnsPartial用于设置后台过滤???
2330. if (!($.isEmptyObject(this.filterColumnsPartial))) {  
2331. 'filter'] = JSON.stringify(this.filterColumnsPartial, null);  
2332.         }  
2333.   
2334. // 调用options.queryParams处理上传的内容param,包括搜索文本、排序字段、排序方式
2335. // 以及当前页显示几条数据、当前页数或limit、offset
2336. this.options, this.options.queryParams, [params], data);  
2337.   
2338.         $.extend(data, query || {});  
2339.   
2340. if (data === false) {  
2341. return;  
2342.         }  
2343.   
2344. if
2345. this.$tableLoading.show();  
2346.         }  
2347. null, this.options.ajaxOptions), {  
2348. this.options.method,  
2349. this.options.url,  
2350. this.options.contentType === 'application/json' && this.options.method === 'post'
2351.                 JSON.stringify(data) : data,  
2352. this.options.cache,  
2353. this.options.contentType,  
2354. this.options.dataType,  
2355. function
2356.                 res = calculateObjectValue(that.options, that.options.responseHandler, [res], res);  
2357.                 that.load(res);  
2358. 'load-success', res);  
2359. if
2360.             },  
2361. function
2362. 'load-error', res.status, res);  
2363. if
2364.             }  
2365.         });  
2366.   
2367. if (this.options.ajax) {  
2368. this, this.options.ajax, [request], null);  
2369. else
2370.             $.ajax(request);  
2371.         }  
2372.     };  
2373.   
2374. // 初始化若设置搜索文本,开启搜索,不支持本地数据搜索
2375. function
2376. if (this.options.search) {  
2377. if (this.options.searchText !== '') {  
2378. var $search = this.$toolbar.find('.search input');  
2379. this.options.searchText);  
2380. this.onSearch({currentTarget: $search});  
2381.             }  
2382.         }  
2383.     };  
2384.   
2385. // getCaret改变排序点击箭头的上下方向
2386. function
2387. var that = this;  
2388.   
2389. this.$header.find('th'), function
2390. '.sortable').removeClass('desc asc').addClass($(th).data('field') === that.options.sortName ? that.options.sortOrder : 'both');  
2391.         });  
2392.     };  
2393.   
2394. // 全选以及全不选时改变全选复选框的勾选状态,以及tr行添加或删除selected类
2395. function
2396. var checkAll = this.$selectItem.filter(':enabled').length &&  
2397. this.$selectItem.filter(':enabled').length ===  
2398. this.$selectItem.filter(':enabled').filter(':checked').length;  
2399.   
2400. this.$selectAll.add(this.$selectAll_).prop('checked', checkAll);  
2401.   
2402. this.$selectItem.each(function
2403. this).closest('tr')[$(this).prop('checked') ? 'addClass' : 'removeClass']('selected');  
2404.         });  
2405.     };  
2406.   
2407. // 复选框选中或撤销选中后更新this.data数据中的[this.header.stateField]属性,以便上传复选框的状态
2408. function
2409. var that = this;  
2410.   
2411. this.$selectItem.each(function
2412. this).data('index')][that.header.stateField] = $(this).prop('checked');  
2413.         });  
2414.     };  
2415.   
2416. // 重置,撤销复选框选中,以及data[i][that.header.stateField]赋值为false
2417. function
2418. var that = this;  
2419.   
2420. this.data, function
2421. 'checked', false);  
2422. 'checked', false);  
2423. if
2424. false;  
2425.             }  
2426.         });  
2427.     };  
2428.   
2429. // 执行this.options[BootstrapTable.EVENTS[name]]函数(类似浏览器默认事件),并触发事件
2430. function
2431. var
2432.   
2433. '.bs.table';  
2434. this.options[BootstrapTable.EVENTS[name]].apply(this.options, args);  
2435. this.$el.trigger($.Event(name), args);  
2436.   
2437. this.options.onAll(name, args);  
2438. this.$el.trigger($.Event('all.bs.table'), [name, args]);  
2439.     };  
2440.   
2441. // 一定时间内触发this.fitHeader函数调整表头的水平偏移,垂直滚动不影响表头
2442. function
2443. // fix #61: the hidden table reset header bug.
2444. // fix bug: get $el.css('width') error sometime (height = 500)
2445. this.timeoutId_);  
2446. this.timeoutId_ = setTimeout($.proxy(this.fitHeader, this), this.$el.is(':hidden') ? 100 : 0);  
2447.     };  
2448.   
2449. // 克隆this.$el中的表头,置入this.$tableHeader中,出使垂直滚动时,表头信息不变
2450. // 调整表体水平偏移量和表体水平一致
2451. function
2452. var that = this,  
2453.             fixedBody,  
2454.             scrollWidth,  
2455.             focused,  
2456.             focusedTemp;  
2457.   
2458. if (that.$el.is(':hidden')) {  
2459.             that.timeoutId_ = setTimeout($.proxy(that.fitHeader, that), 100);  
2460. return;  
2461.         }  
2462. this.$tableBody.get(0);// 包裹表单的.fixed-table-body元素
2463.   
2464. // .fixed-table-container有固定高度,其子元素.fixed-table-body超过该高度就显示滚动条
2465.         scrollWidth = fixedBody.scrollWidth > fixedBody.clientWidth &&  
2466. this.$header.outerHeight() ?  
2467.             getScrollBarWidth() : 0;  
2468.   
2469. this.$el.css('margin-top', -this.$header.outerHeight());  
2470.   
2471. // 表头聚焦的元素添加focus-temp类,从而使this.$tableHeader的同个元素获得焦点
2472. ':focus');  
2473. if
2474. var $th = focused.parents('th');  
2475. if
2476. var dataField = $th.attr('data-field');  
2477. if
2478. var $headerTh = this.$header.find("[data-field='" + dataField + "']");  
2479. if
2480. ":input").addClass("focus-temp");  
2481.                     }  
2482.                 }  
2483.             }  
2484.         }  
2485.   
2486. this.$header_ = this.$header.clone(true, true);  
2487. this.$selectAll_ = this.$header_.find('[name="btSelectAll"]');  
2488. this.$tableHeader.css({  
2489. 'margin-right': scrollWidth  
2490. 'table').css('width', this.$el.outerWidth())  
2491. '').attr('class', this.$el.attr('class'))  
2492. this.$header_);  
2493.   
2494.   
2495. '.focus-temp:visible:eq(0)');  
2496. if
2497.             focusedTemp.focus();  
2498. this.$header.find('.focus-temp').removeClass('focus-temp');  
2499.         }  
2500.   
2501. // fix bug: $.data() is not working as expected after $.append()
2502. // that.$header_是jquery对象,如果改变了this的值,$(this).data()获取内容和bug是咋回事???
2503. this.$header.find('th[data-field]').each(function
2504. 'th[data-field="%s"]', $(this).data('field'))).data($(this).data());  
2505.         });  
2506.   
2507. var visibleFields = this.getVisibleFields();  
2508.   
2509. // 标题栏单元格中的.fht-cell元素和表格中元素的宽度相一致,意义???
2510. this.$body.find('>tr:first-child:not(.no-records-found) > *').each(function
2511. var $this = $(this),  
2512.                 index = i;  
2513.   
2514. if
2515. if
2516. 'th.detail').find('.fht-cell').width($this.innerWidth());  
2517.                 }  
2518.                 index = i - 1;  
2519.             }  
2520.   
2521. 'th[data-field="%s"]', visibleFields[index]))  
2522. '.fht-cell').width($this.innerWidth());  
2523.         });  
2524.   
2525. // 当窗口缩放时,出现滚动条,表头表尾水平偏移情况相当
2526. this.$tableBody.off('scroll').on('scroll', function
2527. this).scrollLeft());  
2528.   
2529. if
2530. this).scrollLeft());  
2531.             }  
2532.         });  
2533. 'post-header');  
2534.     };  
2535.   
2536. // 创建表尾,利用footerFormatter填充表尾内容,调用fitFooter调整表尾偏移
2537. function
2538. var that = this,  
2539.             data = that.getData(),  
2540.             html = [];  
2541.   
2542. if (!this.options.showFooter || this.options.cardView) {  
2543. return;  
2544.         }  
2545.   
2546. if (!this.options.cardView && this.options.detailView) {  
2547. '<td><div class="th-inner"> </div><div class="fht-cell"></div></td>');  
2548.         }  
2549.   
2550. this.columns, function
2551. var falign = '',   
2552. '',  
2553. ' class="%s"', column['class']);  
2554.   
2555. if
2556. return;  
2557.             }  
2558.   
2559. if
2560. return;  
2561.             }  
2562.   
2563. 'text-align: %s; ', column.falign ? column.falign : column.align);  
2564. 'vertical-align: %s; ', column.valign);  
2565.   
2566. '<td', class_, sprintf(' style="%s"', falign + style), '>');  
2567. '<div class="th-inner">');  
2568.   
2569. ' ') || ' ');  
2570.   
2571. '</div>');  
2572. '<div class="fht-cell"></div>');  
2573. '</div>');  
2574. '</td>');  
2575.         });  
2576.   
2577. this.$tableFooter.find('tr').html(html.join(''));  
2578. this.timeoutFooter_);  
2579. this.timeoutFooter_ = setTimeout($.proxy(this.fitFooter, this),  
2580. this.$el.is(':hidden') ? 100 : 0);  
2581.     };  
2582.   
2583. // 调整表尾水平偏移,设置表尾fnt-cell的宽度
2584. function
2585. var that = this,  
2586.             $footerTd,  
2587.             elWidth,  
2588.             scrollWidth;  
2589.   
2590. this.timeoutFooter_);  
2591. if (this.$el.is(':hidden')) {  
2592. this.timeoutFooter_ = setTimeout($.proxy(this.fitFooter, this), 100);  
2593. return;  
2594.         }  
2595.   
2596. this.$el.css('width');  
2597. this.$tableBody.width() ? getScrollBarWidth() : 0;  
2598.   
2599. this.$tableFooter.css({  
2600. 'margin-right': scrollWidth  
2601. 'table').css('width', elWidth)  
2602. 'class', this.$el.attr('class'));  
2603.   
2604. this.$tableFooter.find('td');  
2605.   
2606. this.$body.find('>tr:first-child:not(.no-records-found) > *').each(function
2607. var $this = $(this);  
2608.   
2609. '.fht-cell').width($this.innerWidth());  
2610.         });  
2611.     };  
2612.   
2613. // toggleColumn筛选条目下拉菜单点选时更新columns[i].visible信息;
2614. // this.columns信息的改变,重新调用表头、表体、搜索框、分页初始化函数;
2615. // 当勾选的显示条目小于this.options.minimumCountColumns时,勾选的条目设置disabled属性;
2616. function
2617. if
2618. return;  
2619.         }  
2620. this.columns[index].visible = checked;  
2621.   
2622. this.initHeader();  
2623. this.initSearch();  
2624. this.initPagination();  
2625. this.initBody();  
2626.   
2627. if (this.options.showColumns) {// this.options.showColumns显示筛选条目按钮
2628. var $items = this.$toolbar.find('.keep-open input').prop('disabled', false);  
2629.   
2630. if
2631. '[value="%s"]', index)).prop('checked', checked);  
2632.             }  
2633.   
2634. if ($items.filter(':checked').length <= this.options.minimumCountColumns) {  
2635. ':checked').prop('disabled', true);  
2636.             }  
2637.         }  
2638.     };  
2639.   
2640. // 从表体中找到data-index=index或data-uniqueid=uniqueId那一行,根据visible显示或隐藏
2641. function
2642. if
2643. return;  
2644.         }  
2645.   
2646. this.$body.find(typeof index !== 'undefined'
2647. 'tr[data-index="%s"]', index) :  
2648. 'tr[data-uniqueid="%s"]', uniqueId))  
2649. 'show' : 'hide']();  
2650.     };  
2651.   
2652. // 从this.column中剔除visible为false的项,返回field数组
2653. function
2654. var that = this,  
2655.             visibleFields = [];  
2656.   
2657. this.header.fields, function
2658. // this.columns以列坐标:数据的形式保存
2659. var
2660.   
2661. if
2662. return;  
2663.             }  
2664.             visibleFields.push(field);  
2665.         });  
2666. return
2667.     };  
2668.   
2669.   
2670.   
2671. /**公共方法:通过bootstrap(fnName,argunments)调用
2672.      *
2673.      * resetView():
2674.      *     调整表体的高度;
2675.      * getData():
2676.      *     搜索过滤后的数据保存在this.data中,过滤前数据保存在options.data,针对数据在前台的情况;
2677.      *     有过滤数据,返回过滤数据this.data,无则返回未过滤数据this.options.data;
2678.      *     前台分页,获取this.pageFrom-1到this.pageTo的data数据或者整个data数据;
2679.      * load():
2680.      *     使用后台传回的数据或本地data数据更新data、搜索框、分页、表体显示;
2681.      *     后台传回数据格式为{total:,rows:,[fixedScroll]:};
2682.      * append():
2683.      *     从表格尾部插入数据;
2684.      * prepend():
2685.      *     从表格头部插入数据;
2686.      * remove():
2687.      *     移除指定行数据,通过行数据row中的某个属性比较删除拥有相同值的行数据data;
2688.      *     param数据格式为{field:paramName,values:paramValues},paramName、paramValues和data对应;
2689.      * removeAll():
2690.      *     移除所有行数据;
2691.      * getRowByUniqueId():
2692.      *     获取row[options.uniqueId]或者row._data[options.uniqueId]同id相等的某一行数据; 
2693.      * removeByUniqueId():
2694.      *     移除row[options.uniqueId]或者row._data[options.uniqueId]同id相等的某一行数据;
2695.      * updateByUniqueId():
2696.      *     更新替换某一行数据,参数格式为{id:row[options.uniqueId],row:row替换数据};
2697.      * insertRow():
2698.      *     在某一行后插入数据,参数格式为{index:index行号,row:row插入数据内容};
2699.      * updateRow():
2700.      *     更新替换某一行数据,参数格式为{index:index行号,row:row替换数据};
2701.      * showRow():
2702.      *     根据{[index:index],[uniqueid:uniqueId]}找到某一行,显示;
2703.      * hideRow():
2704.      *     根据{[index:index],[uniqueid:uniqueId]}找到某一行,隐藏;
2705.      * getRowsHidden():  
2706.      *     获取并返回隐藏的行,根据show将这些行数据显示出来;
2707.      * mergeCells():
2708.      *     合并单元格,传参为{index:index.field:field,rowspan:3,colspan:4};
2709.      *     隐藏被合并单元格,重新设置显示单元格rowspan、colspan属性;
2710.      * updateCell():
2711.      *     更新单元的显示文本,传参为{index:index,field:field,value:value},根据index、field找到单元格;
2712.      * getOptions():
2713.      *     返回配置项;
2714.      * getSelections():
2715.      *     通过过滤后的数据this.data返回选中行的数据;
2716.      * getAllSelections():
2717.      *     通过未过滤的数据this.options.data返回选中行的数据;
2718.      * checkAll():
2719.      *     全选;
2720.      * unCheckAll():
2721.      *     全不选;
2722.      * checkInvert():
2723.      *     反选;
2724.      * checkAll_():
2725.      *     全选或全不选执行函数;
2726.      * check():
2727.      *     选中;
2728.      * unCheck():
2729.      *     取消选中;
2730.      * check_():
2731.      *     选中、取消选中执行函数;
2732.      * checkBy():
2733.      *     选中某几行数据;
2734.      * unCheckBy():
2735.      *     取消选中某几行数据;
2736.      * checkBy_():
2737.      *     根据条件选中、取消选中某几行数据执行函数,obj参数格式为{field:paramName,values:paramValues};
2738.      * destory():
2739.      *     移出触发元素,其内容、样式通过this.$el_改为初始值,移除构造函数添加最外层包裹元素this.$container;
2740.      * showLoading():
2741.      *     显示后台数据载入文案;
2742.      * hideLoading():
2743.      *     隐藏后台数据载入文案;
2744.      * togglePagination():
2745.      *     分页切换按钮显示隐藏分页内容;
2746.      * refresh():
2747.      *     刷新页面到第一页,传入参数为{url:url,slient:slient,query:query};
2748.      * resetWidth():
2749.      *     调用fitHeader、fitFooter函数调整表头、表尾的宽度;
2750.      * showColumn():
2751.      *     根据field属性获得fieldIndex,再调用toggleColumn显示某列;
2752.      * hideColumn():
2753.      *     根据field属性获得fieldIndex,再调用toggleColumn隐藏某列;
2754.      * getHiddenColumns():
2755.      *     获得隐藏的某几列;
2756.      * filterBy():
2757.      *     设置过滤数组this.filterColumns;
2758.      *     options.data和this.filterColumns相符则在this.data中保留,不相符则在this.data中删除;
2759.      *     设置页码为1,重新调用initSearch、updatePagination渲染表格; 
2760.      * scrollTo():
2761.      *     设置this.$tableBody滚动条的垂直偏移,意义是移动到第几行数据;
2762.      * getScrollPosition():
2763.      *     表体滚动到顶部;
2764.      * selectPage():
2765.      *     设置this.options.pageNumber当前页,调用updatePagination更新表体,initBody或initServer方法;
2766.      * prevPage():
2767.      * nextPage():
2768.      *     上一页,下一页;
2769.      * toggleView():
2770.      *     切换卡片式显示或者表格详情显示;
2771.      * refreshView():
2772.      *     更新传入的配置项options,调用destory重置,init重新渲染页面;
2773.      * resetSearch():
2774.      *     设置搜索框文本,启动数据搜索;
2775.      * expandRow_():
2776.      *     表格详情显示时,折叠展开按钮执行函数;
2777.      * expandRow():
2778.      *     展开对应行的卡片详情;
2779.      * collapseRow():
2780.      *     折叠对应行的卡片详情;
2781.      * expandAllRows():
2782.      *     expandAllRows展开所有卡片式详情,在表格显示的时候;
2783.      *     isSubTable为真,展开父子表格的详情;
2784.      * collapseAllRows():
2785.      *     expandAllRows展开所有卡片式详情,在表格显示的时候;
2786.      * updateFormatText():
2787.      *     更新配置项中的格式化函数;
2788.      */
2789.   
2790. // 调整表体的高度
2791. function
2792. var
2793.   
2794. if
2795. this.options.height = params.height;  
2796.         }  
2797.   
2798. this.$selectAll.prop('checked', this.$selectItem.length > 0 &&  
2799. this.$selectItem.length === this.$selectItem.filter(':checked').length);  
2800.   
2801. if (this.options.height) {  
2802. var toolbarHeight = getRealHeight(this.$toolbar),  
2803. this.$pagination),  
2804. this.options.height - toolbarHeight - paginationHeight;  
2805.   
2806. this.$tableContainer.css('height', height + 'px');  
2807.         }  
2808.   
2809. if (this.options.cardView) {  
2810. this.$el.css('margin-top', '0');  
2811. this.$tableContainer.css('padding-bottom', '0');  
2812. return;  
2813.         }  
2814.   
2815. if (this.options.showHeader && this.options.height) {  
2816. this.$tableHeader.show();  
2817. this.resetHeader();  
2818. this.$header.outerHeight();  
2819. else
2820. this.$tableHeader.hide();  
2821. this.trigger('post-header');  
2822.         }  
2823.   
2824. if (this.options.showFooter) {  
2825. this.resetFooter();  
2826. if (this.options.height) {  
2827. this.$tableFooter.outerHeight() + 1;  
2828.             }  
2829.         }  
2830.   
2831. this.getCaret();  
2832. this.$tableContainer.css('padding-bottom', padding + 'px');  
2833. this.trigger('reset-view');  
2834.     };  
2835.   
2836. //  过滤或搜索过滤后的数据保存在this.data中,过滤前的数据保存在this.options.data,针对数据在前台的情况;
2837. //  有过滤数据,返回过滤数据this.data,无则返回未过滤数据this.options.data;
2838. //  前台分页,获取this.pageFrom-1到this.pageTo的data数据或者整个data数据;
2839. function
2840. return (this.searchText || !$.isEmptyObject(this.filterColumns) || !$.isEmptyObject(this.filterColumnsPartial)) ?  
2841. this.data.slice(this.pageFrom - 1, this.pageTo) : this.data) :  
2842. this.options.data.slice(this.pageFrom - 1, this.pageTo) : this.options.data);  
2843.     };  
2844.   
2845. // 使用后台传回的数据或本地data数据更新data、搜索框、分页、表体显示
2846. // 后台传回数据格式为{total:,rows:,[fixedScroll]:}
2847. function
2848. var fixedScroll = false;  
2849.   
2850. // #431: support pagination
2851. if (this.options.sidePagination === 'server') {  
2852. this.options.totalRows = data.total;  
2853.             fixedScroll = data.fixedScroll;  
2854. this.options.dataField];  
2855. else if (!$.isArray(data)) { // support fixedScroll
2856.             fixedScroll = data.fixedScroll;  
2857.             data = data.data;  
2858.         }  
2859.   
2860. this.initData(data);  
2861. this.initSearch();  
2862. this.initPagination();  
2863. this.initBody(fixedScroll);  
2864.     };  
2865.   
2866. // 从表格尾部插入数据
2867. function
2868. this.initData(data, 'append');  
2869. this.initSearch();  
2870. this.initPagination();  
2871. this.initSort();  
2872. this.initBody(true);  
2873.     };  
2874.   
2875. // 从表格头部插入数据
2876. function
2877. this.initData(data, 'prepend');  
2878. this.initSearch();  
2879. this.initPagination();  
2880. this.initSort();  
2881. this.initBody(true);  
2882.     };  
2883.   
2884. // 移除指定行数据,通过行数据row中的某个属性比较删除拥有相同值的行数据data
2885. // param数据格式为{field:paramName,values:paramValues},paramName、paramValues和data对应
2886. /** var ids = $.map($table.bootstrapTable('getSelections'), function (row) {
2887.             return row.id;
2888.         });
2889.         $table.bootstrapTable('remove', {
2890.             field: 'id',
2891.             values: ids
2892.         });
2893.     */
2894. function
2895. var len = this.options.data.length,  
2896.             i, row;  
2897.   
2898. if (!params.hasOwnProperty('field') || !params.hasOwnProperty('values')) {  
2899. return;  
2900.         }  
2901.   
2902. for
2903. this.options.data[i];  
2904.   
2905. if
2906. continue;  
2907.             }  
2908. if
2909. this.options.data.splice(i, 1);  
2910.             }  
2911.         }  
2912.   
2913. if (len === this.options.data.length) {  
2914. return;  
2915.         }  
2916.   
2917. this.initSearch();  
2918. this.initPagination();  
2919. this.initSort();  
2920. this.initBody(true);  
2921.     };  
2922.   
2923. // 移除所有行数据
2924. function
2925. if (this.options.data.length > 0) {  
2926. this.options.data.splice(0, this.options.data.length);  
2927. this.initSearch();  
2928. this.initPagination();  
2929. this.initBody(true);  
2930.         }  
2931.     };  
2932.   
2933. // 获取row[options.uniqueId]或者row._data[options.uniqueId]同id相等的某一行数据
2934. function
2935. var uniqueId = this.options.uniqueId,  
2936. this.options.data.length,  
2937. null,  
2938.             i, row, rowUniqueId;  
2939.   
2940. for
2941. this.options.data[i];  
2942.   
2943. if (row.hasOwnProperty(uniqueId)) { // uniqueId is a column
2944.                 rowUniqueId = row[uniqueId];  
2945. else if(row._data.hasOwnProperty(uniqueId)) { // uniqueId is a row data property
2946.                 rowUniqueId = row._data[uniqueId];  
2947. else
2948. continue;  
2949.             }  
2950.   
2951. if (typeof rowUniqueId === 'string') {  
2952.                 id = id.toString();  
2953. else if (typeof rowUniqueId === 'number') {  
2954. if
2955.                     id = parseInt(id);  
2956. else if
2957.                     id = parseFloat(id);  
2958.                 }  
2959.             }  
2960.   
2961. if
2962.                 dataRow = row;  
2963. break;  
2964.             }  
2965.         }  
2966.   
2967. return
2968.     };  
2969.   
2970. // 移除row[options.uniqueId]或者row._data[options.uniqueId]同id相等的某一行数据
2971. function
2972. var len = this.options.data.length,  
2973. this.getRowByUniqueId(id);  
2974.   
2975. if
2976. this.options.data.splice(this.options.data.indexOf(row), 1);  
2977.         }  
2978.   
2979. if (len === this.options.data.length) {  
2980. return;  
2981.         }  
2982.   
2983. this.initSearch();  
2984. this.initPagination();  
2985. this.initBody(true);  
2986.     };  
2987.   
2988. // 更新替换某一行数据,参数格式为{id:row[options.uniqueId],row:row替换数据}
2989. function
2990. var
2991.   
2992. if (!params.hasOwnProperty('id') || !params.hasOwnProperty('row')) {  
2993. return;  
2994.         }  
2995.   
2996. this.getRowByUniqueId(params.id), this.options.data);  
2997.   
2998. if
2999. return;  
3000.         }  
3001.   
3002. this.data[rowId], params.row);  
3003. this.initSort();  
3004. this.initBody(true);  
3005.     };  
3006.   
3007. // 在某一行后插入数据,参数格式为{index:index行号,row:row插入数据内容}
3008. function
3009. if (!params.hasOwnProperty('index') || !params.hasOwnProperty('row')) {  
3010. return;  
3011.         }  
3012. this.data.splice(params.index, 0, params.row);  
3013. this.initSearch();  
3014. this.initPagination();  
3015. this.initSort();  
3016. this.initBody(true);  
3017.     };  
3018.   
3019. // 更新替换某一行数据,参数格式为{index:index行号,row:row替换数据}
3020. function
3021. if (!params.hasOwnProperty('index') || !params.hasOwnProperty('row')) {  
3022. return;  
3023.         }  
3024. this.data[params.index], params.row);  
3025. this.initSort();  
3026. this.initBody(true);  
3027.     };  
3028.   
3029. // 根据{[index:index],[uniqueid:uniqueId]}找到某一行,显示
3030. function
3031. if (!params.hasOwnProperty('index') && !params.hasOwnProperty('uniqueId')) {  
3032. return;  
3033.         }  
3034. this.toggleRow(params.index, params.uniqueId, true);  
3035.     };  
3036.   
3037. // 根据{[index:index],[uniqueid:uniqueId]}找到某一行,隐藏
3038. function
3039. if (!params.hasOwnProperty('index') && !params.hasOwnProperty('uniqueId')) {  
3040. return;  
3041.         }  
3042. this.toggleRow(params.index, params.uniqueId, false);  
3043.     };  
3044.   
3045. // 获取并返回隐藏的行,根据show将这些行数据显示出来
3046. function
3047. var rows = $(this.$body[0]).children().filter(':hidden'),  
3048.             i = 0;  
3049. if
3050. for
3051.                 $(rows[i]).show();  
3052.             }  
3053.         }  
3054. return
3055.     };  
3056.   
3057. // 合并单元格,传参为{index:index.field:field,rowspan:3,colspan:4}
3058. // 隐藏被合并单元格,重新设置显示单元格rowspan、colspan属性
3059. function
3060. var
3061. this.getVisibleFields()),  
3062.             rowspan = options.rowspan || 1,  
3063.             colspan = options.colspan || 1,  
3064.             i, j,  
3065. this.$body.find('>tr'),  
3066.             $td;  
3067.   
3068. if (this.options.detailView && !this.options.cardView) {  
3069.             col += 1;  
3070.         }  
3071.   
3072. '>td').eq(col);  
3073.   
3074. if (row < 0 || col < 0 || row >= this.data.length) {  
3075. return;  
3076.         }  
3077.   
3078. for
3079. for
3080. '>td').eq(j).hide();  
3081.             }  
3082.         }  
3083.   
3084. 'rowspan', rowspan).attr('colspan', colspan).show();  
3085.     };  
3086.   
3087. // 更新单元的显示文本,传参为{index:index,field:field,value:value},根据index、field找到单元格
3088. function
3089. if (!params.hasOwnProperty('index') ||  
3090. 'field') ||  
3091. 'value')) {  
3092. return;  
3093.         }  
3094. this.data[params.index][params.field] = params.value;  
3095.   
3096. if (params.reinit === false) {  
3097. return;  
3098.         }  
3099. this.initSort();  
3100. this.initBody(true);  
3101.     };  
3102.   
3103. // 返回配置项
3104. function
3105. return this.options;  
3106.     };  
3107.   
3108. // 通过过滤后的数据this.data返回选中行的数据
3109. function
3110. var that = this;  
3111.   
3112. return $.grep(this.data, function
3113. return
3114.         });  
3115.     };  
3116.   
3117. // 通过未过滤的数据this.options.data返回选中行的数据
3118. function
3119. var that = this;  
3120.   
3121. return $.grep(this.options.data, function
3122. return
3123.         });  
3124.     };  
3125.   
3126. // 执行全选
3127. function
3128. this.checkAll_(true);  
3129.     };  
3130.   
3131. // 执行全不选
3132. function
3133. this.checkAll_(false);  
3134.     };  
3135.   
3136. // 反选,调用updateRows执行initSort、initBody,调用updateSelect为行元素tr添加selected类
3137. function
3138. var that = this;  
3139. var rows = that.$selectItem.filter(':enabled');  
3140. var checked = rows.filter(':checked');  
3141. function() {  
3142. this).prop('checked', !$(this).prop('checked'));  
3143.         });  
3144.         that.updateRows();  
3145.         that.updateSelected();  
3146. 'uncheck-some', checked);  
3147.         checked = that.getSelections();  
3148. 'check-some', checked);  
3149.     };  
3150.   
3151. // 全选或全不选执行函数,为什么这时又不像所在的行添加selected类???
3152. function
3153. var
3154. if
3155. this.getSelections();  
3156.         }  
3157. this.$selectAll.add(this.$selectAll_).prop('checked', checked);//全选按钮
3158. this.$selectItem.filter(':enabled').prop('checked', checked);  
3159. this.updateRows();  
3160. if
3161. this.getSelections();  
3162.         }  
3163. this.trigger(checked ? 'check-all' : 'uncheck-all', rows);  
3164.     };  
3165.   
3166. // 选中
3167. function
3168. this.check_(true, index);  
3169.     };  
3170.   
3171. // 取消选中
3172. function
3173. this.check_(false, index);  
3174.     };  
3175.   
3176. // 选中、取消选中执行函数
3177. function
3178. var $el = this.$selectItem.filter(sprintf('[data-index="%s"]', index)).prop('checked', checked);  
3179. this.data[index][this.header.stateField] = checked;  
3180. this.updateSelected();  
3181. this.trigger(checked ? 'check' : 'uncheck', this.data[index], $el);  
3182.     };  
3183.   
3184. // 选中某几行数据
3185. function
3186. this.checkBy_(true, obj);  
3187.     };  
3188.   
3189. // 取消选中某几行数据
3190. function
3191. this.checkBy_(false, obj);  
3192.     };  
3193.   
3194. // 根据条件选中、取消选中某几行数据执行函数,obj参数格式为{field:paramName,values:paramValues}
3195. function
3196. if (!obj.hasOwnProperty('field') || !obj.hasOwnProperty('values')) {  
3197. return;  
3198.         }  
3199.   
3200. var that = this,  
3201.             rows = [];  
3202. this.options.data, function
3203. if
3204. return false;  
3205.             }  
3206. if
3207. var $el = that.$selectItem.filter(':enabled')  
3208. '[data-index="%s"]', index)).prop('checked', checked);  
3209.                 row[that.header.stateField] = checked;  
3210.                 rows.push(row);  
3211. 'check' : 'uncheck', row, $el);  
3212.             }  
3213.         });  
3214. this.updateSelected();  
3215. this.trigger(checked ? 'check-some' : 'uncheck-some', rows);  
3216.     };  
3217.   
3218. // 移出触发元素,其内容、样式通过this.$el_改为初始值,移除构造函数添加最外层包裹元素this.$container
3219. function
3220. this.$el.insertBefore(this.$container);  
3221. this.options.toolbar).insertBefore(this.$el);  
3222. this.$container.next().remove();  
3223. this.$container.remove();  
3224. this.$el.html(this.$el_.html())  
3225. 'margin-top', '0')  
3226. 'class', this.$el_.attr('class') || ''); // reset the class
3227.     };  
3228.   
3229. // 显示后台数据载入文案
3230. function
3231. this.$tableLoading.show();  
3232.     };  
3233.   
3234. // 隐藏后台数据载入文案
3235. function
3236. this.$tableLoading.hide();  
3237.     };  
3238.   
3239. // 分页切换按钮显示隐藏分页内容
3240. function
3241. this.options.pagination = !this.options.pagination;  
3242. var button = this.$toolbar.find('button[name="paginationSwitch"] i');  
3243. if (this.options.pagination) {  
3244. "class", this.options.iconsPrefix + " " + this.options.icons.paginationSwitchDown);  
3245. else
3246. "class", this.options.iconsPrefix + " " + this.options.icons.paginationSwitchUp);  
3247.         }  
3248. this.updatePagination();  
3249.     };  
3250.   
3251. // 刷新页面到第一页,传入参数为{url:url,slient:slient,query:query}
3252. function
3253. if
3254. this.options.url = params.url;  
3255. this.options.pageNumber = 1;  
3256.         }  
3257. this.initServer(params && params.silent, params && params.query);  
3258.     };  
3259.   
3260. // 调用fitHeader、fitFooter函数调整表头、表尾的宽度
3261. function
3262. if (this.options.showHeader && this.options.height) {  
3263. this.fitHeader();  
3264.         }  
3265. if (this.options.showFooter) {  
3266. this.fitFooter();  
3267.         }  
3268.     };  
3269.   
3270. // 根据field属性获得fieldIndex,再调用toggleColumn显示某列
3271. function
3272. this.toggleColumn(getFieldIndex(this.columns, field), true, true);  
3273.     };  
3274.   
3275. // 根据field属性获得fieldIndex,再调用toggleColumn隐藏某列
3276. function
3277. this.toggleColumn(getFieldIndex(this.columns, field), false, true);  
3278.     };  
3279.   
3280. // 获得隐藏的某几列
3281. function
3282. return $.grep(this.columns, function
3283. return
3284.         });  
3285.     };  
3286.   
3287. // 设置过滤数组this.filterColumns;
3288. // options.data和this.filterColumns相符则在this.data中保留,不相符则在this.data中删除;
3289. // 设置页码为1,重新调用initSearch、updatePagination渲染表格;
3290. function
3291. this.filterColumns = $.isEmptyObject(columns) ? {} : columns;  
3292. this.options.pageNumber = 1;  
3293. this.initSearch();  
3294. this.updatePagination();  
3295.     };  
3296.   
3297. // 设置this.$tableBody滚动条的垂直偏移,意义是移动到第几行数据
3298. function
3299. if (typeof value === 'string') {  
3300. 'bottom' ? this.$tableBody[0].scrollHeight : 0;  
3301.         }  
3302. if (typeof value === 'number') {  
3303. this.$tableBody.scrollTop(value);  
3304.         }  
3305. if (typeof value === 'undefined') {  
3306. return this.$tableBody.scrollTop();// 返回顶部
3307.         }  
3308.     };  
3309.   
3310. // 表体滚动到顶部
3311. function
3312. return this.scrollTo();  
3313.     };  
3314.   
3315. // 设置this.options.pageNumber当前页,调用updatePagination更新表体,initBody或initServer方法
3316. function
3317. if (page > 0 && page <= this.options.totalPages) {  
3318. this.options.pageNumber = page;  
3319. this.updatePagination();  
3320.         }  
3321.     };  
3322.   
3323. // 前一页
3324. function
3325. if (this.options.pageNumber > 1) {  
3326. this.options.pageNumber--;  
3327. this.updatePagination();  
3328.         }  
3329.     };  
3330.   
3331. // 后一页
3332. function
3333. if (this.options.pageNumber < this.options.totalPages) {  
3334. this.options.pageNumber++;  
3335. this.updatePagination();  
3336.         }  
3337.     };  
3338.   
3339. // 切换卡片式显示或者表格详情显示
3340. function
3341. this.options.cardView = !this.options.cardView;  
3342. this.initHeader();  
3343. // Fixed remove toolbar when click cardView button.
3344. //that.initToolbar();
3345. this.initBody();  
3346. this.trigger('toggle', this.options.cardView);  
3347.     };  
3348.   
3349. // 更新传入的配置项options,调用destory重置,init重新渲染页面
3350. function
3351. //If the objects are equivalent then avoid the call of destroy / init methods
3352. // 当this.options和options长度相当,其中一个属性不同的时候,也会被if语句提前返回???
3353. if (compareObjects(this.options, options, true)) {  
3354. return;  
3355.         }  
3356. this.options = $.extend(this.options, options);  
3357. this.trigger('refresh-options', this.options);  
3358. this.destroy();  
3359. this.init();  
3360.     };  
3361.   
3362. // 设置搜索框文本,启动数据搜索
3363. function
3364. var $search = this.$toolbar.find('.search input');  
3365. '');  
3366. this.onSearch({currentTarget: $search});  
3367.     };  
3368.   
3369. // 表格详情显示时,折叠展开按钮执行函数
3370. function
3371. var $tr = this.$body.find(sprintf('> tr[data-index="%s"]', index));  
3372. if ($tr.next().is('tr.detail-view') === (expand ? false : true)) {  
3373. '> td > .detail-icon').click();  
3374.         }  
3375.     };  
3376.   
3377. // 展开对应行的卡片详情
3378. function
3379. this.expandRow_(true, index);  
3380.     };  
3381.   
3382. // 折叠对应行的卡片详情
3383. function
3384. this.expandRow_(false, index);  
3385.     };  
3386.   
3387. // expandAllRows展开所有卡片式详情,在表格显示的时候
3388. // isSubTable为真,展开父子表格的详情
3389. function
3390. if
3391. var $tr = this.$body.find(sprintf('> tr[data-index="%s"]', 0)),  
3392. this,  
3393. null,  
3394. false,  
3395.                 idInterval = -1;  
3396.   
3397. if (!$tr.next().is('tr.detail-view')) {  
3398. '> td > .detail-icon').click();  
3399. true;  
3400. else if (!$tr.next().next().is('tr.detail-view')) {  
3401. ".detail-icon").click();  
3402. true;  
3403.             }  
3404.   
3405. if
3406. try
3407. function
3408. // 父子表格情况,从.detail-view中找到.detail-icon并点击
3409. "tr.detail-view").last().find(".detail-icon");  
3410. if
3411.                             detailIcon.click();  
3412. else
3413.                             clearInterval(idInterval);  
3414.                         }  
3415.                     }, 1);  
3416. catch
3417.                     clearInterval(idInterval);  
3418.                 }  
3419.             }  
3420. else
3421. var trs = this.$body.children();  
3422. for (var
3423. this.expandRow_(true, $(trs[i]).data("index"));  
3424.             }  
3425.         }  
3426.     };  
3427.   
3428. // expandAllRows展开所有卡片式详情,在表格显示的时候
3429. function
3430. if
3431. this.expandRow_(false, 0);  
3432. else
3433. var trs = this.$body.children();  
3434. for (var
3435. this.expandRow_(false, $(trs[i]).data("index"));  
3436.             }  
3437.         }  
3438.     };  
3439.   
3440. // 更新配置项中的格式化函数
3441. function
3442. if (this.options[sprintf('format%s', name)]) {  
3443. if (typeof text === 'string') {  
3444. this.options[sprintf('format%s', name)] = function
3445. return
3446.                 };  
3447. else if (typeof text === 'function') {  
3448. this.options[sprintf('format%s', name)] = text;  
3449.             }  
3450.         }  
3451. this.initToolbar();  
3452. this.initPagination();  
3453. this.initBody();  
3454.     };  
3455.   
3456. // BOOTSTRAP TABLE PLUGIN DEFINITION
3457. // =======================
3458.   
3459. var
3460. 'getOptions',  
3461. 'getSelections', 'getAllSelections', 'getData',  
3462. 'load', 'append', 'prepend', 'remove', 'removeAll',  
3463. 'insertRow', 'updateRow', 'updateCell', 'updateByUniqueId', 'removeByUniqueId',  
3464. 'getRowByUniqueId', 'showRow', 'hideRow', 'getRowsHidden',  
3465. 'mergeCells',  
3466. 'checkAll', 'uncheckAll', 'checkInvert',  
3467. 'check', 'uncheck',  
3468. 'checkBy', 'uncheckBy',  
3469. 'refresh',  
3470. 'resetView',  
3471. 'resetWidth',  
3472. 'destroy',  
3473. 'showLoading', 'hideLoading',  
3474. 'showColumn', 'hideColumn', 'getHiddenColumns',  
3475. 'filterBy',  
3476. 'scrollTo',  
3477. 'getScrollPosition',  
3478. 'selectPage', 'prevPage', 'nextPage',  
3479. 'togglePagination',  
3480. 'toggleView',  
3481. 'refreshOptions',  
3482. 'resetSearch',  
3483. 'expandRow', 'collapseRow', 'expandAllRows', 'collapseAllRows',  
3484. 'updateFormatText'
3485.     ];  
3486.   
3487. function
3488. var
3489.             args = Array.prototype.slice.call(arguments, 1);  
3490.   
3491. this.each(function
3492. var $this = $(this),  
3493. this.data('bootstrap.table'),  
3494. // 配置项在触发元素的data数据中,或在js的option传参中
3495. this.data(),  
3496. typeof option === 'object'
3497.   
3498. if (typeof option === 'string') {  
3499. if
3500. throw new Error("Unknown method: "
3501.                 }  
3502.   
3503. if
3504. return;  
3505.                 }  
3506.   
3507.                 value = data[option].apply(data, args);  
3508.   
3509. if (option === 'destroy') {  
3510. this.removeData('bootstrap.table');  
3511.                 }  
3512.             }  
3513.   
3514. if
3515. this.data('bootstrap.table', (data = new BootstrapTable(this, options)));  
3516.             }  
3517.         });  
3518.   
3519. return typeof value === 'undefined' ? this
3520.     };  
3521.   
3522.     $.fn.bootstrapTable.Constructor = BootstrapTable;  
3523.     $.fn.bootstrapTable.defaults = BootstrapTable.DEFAULTS;  
3524.     $.fn.bootstrapTable.columnDefaults = BootstrapTable.COLUMN_DEFAULTS;  
3525.     $.fn.bootstrapTable.locales = BootstrapTable.LOCALES;  
3526.     $.fn.bootstrapTable.methods = allowedMethods;  
3527.     $.fn.bootstrapTable.utils = {  
3528.         sprintf: sprintf,  
3529.         getFieldIndex: getFieldIndex,  
3530.         compareObjects: compareObjects,  
3531.         calculateObjectValue: calculateObjectValue  
3532.     };  
3533.   
3534. // BOOTSTRAP TABLE INIT
3535. // =======================
3536.   
3537. function
3538. '[data-toggle="table"]').bootstrapTable();  
3539.     });  
3540. }(jQuery);