bjui-tablefixed.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543
  1. /*!
  2. * B-JUI v1.2 (http://b-jui.com)
  3. * Git@OSC (http://git.oschina.net/xknaan/B-JUI)
  4. * Copyright 2014 K'naan (xknaan@163.com).
  5. * Licensed under Apache (http://www.apache.org/licenses/LICENSE-2.0)
  6. */
  7. /* ========================================================================
  8. * B-JUI: bjui-tablefixed.js v1.2
  9. * @author K'naan (xknaan@163.com)
  10. * -- Modified from dwz.stable.js (author:ZhangHuihua@msn.com, Roger Wu)
  11. * http://git.oschina.net/xknaan/B-JUI/blob/master/BJUI/js/bjui-tablefixed.js
  12. * ========================================================================
  13. * Copyright 2014 K'naan.
  14. * Licensed under Apache (http://www.apache.org/licenses/LICENSE-2.0)
  15. * ======================================================================== */
  16. +function ($) {
  17. 'use strict';
  18. // TABLEFIXED CLASS DEFINITION
  19. // ======================
  20. var Tablefixed = function(element, options) {
  21. this.$element = $(element)
  22. this.options = options
  23. this.tools = this.TOOLS()
  24. }
  25. Tablefixed.SCROLLW = 18
  26. Tablefixed.DEFAULTS = {
  27. width: '100%'
  28. }
  29. Tablefixed.prototype.TOOLS = function() {
  30. var that = this
  31. var tools = {
  32. getLeft: function($obj) {
  33. var width = 0
  34. $obj.prevAll().each(function() {
  35. width += $(this).outerWidth()
  36. })
  37. return width
  38. },
  39. getRight: function($obj) {
  40. var width = 0
  41. $obj.prevAll().andSelf().each(function() {
  42. width += $(this).outerWidth()
  43. })
  44. return width - 1
  45. },
  46. getCellNum: function($obj) {
  47. return $obj.prevAll().andSelf().size()
  48. },
  49. getColspan: function($obj) {
  50. return $obj.attr('colspan') || 1
  51. },
  52. getStart: function($obj) {
  53. var start = 1
  54. $obj.prevAll().each(function() {
  55. start += parseInt($(this).attr('colspan') || 1)
  56. })
  57. return start
  58. },
  59. getPageCoord: function(element) {
  60. var coord = {x: 0, y: 0}
  61. while (element) {
  62. coord.x += element.offsetLeft
  63. coord.y += element.offsetTop
  64. element = element.offsetParent
  65. }
  66. return coord
  67. },
  68. getOffset: function($obj, e) {
  69. if (!$.support.leadingWhitespace) {
  70. var $objset = $obj.offset()
  71. var evtset = {
  72. offsetX: e.pageX || e.screenX,
  73. offsetY: e.pageY || e.screenY
  74. }
  75. var offset = {
  76. offsetX: evtset.offsetX - $objset.left,
  77. offsetY: evtset.offsetY - $objset.top
  78. }
  79. return offset
  80. }
  81. var target = e.target
  82. if (target.offsetLeft == undefined){
  83. target = target.parentNode
  84. }
  85. var pageCoord = this.getPageCoord(target)
  86. var eventCoord = {
  87. x: window.pageXOffset + e.clientX,
  88. y: window.pageYOffset + e.clientY
  89. }
  90. var offset = {
  91. offsetX: eventCoord.x - pageCoord.x,
  92. offsetY: eventCoord.y - pageCoord.y
  93. }
  94. return offset
  95. }
  96. }
  97. return tools
  98. }
  99. Tablefixed.prototype.resetWidth = function() {
  100. var $fixed = this.$element,
  101. width = $fixed.width(),
  102. $table = $fixed.find('table'),
  103. tableW = $table && $table.width(),
  104. $ths = $table.eq(0) && $table.eq(0).find('tr:first-child > th'),
  105. $tds = $table.eq(1) && $table.eq(1).find('tr:first-child > td')
  106. if ($table && ((width - tableW) < Tablefixed.SCROLLW)) {
  107. var fixedW = parseInt((width - tableW) / $ths.length)
  108. $table.width(width - Tablefixed.SCROLLW)
  109. $ths.each(function(i) {
  110. var tw = parseInt($(this).css('width'))
  111. $(this).width(tw + fixedW)
  112. if ($tds.eq(i)) $tds.eq(i).width(tw + fixedW)
  113. })
  114. }
  115. }
  116. Tablefixed.prototype.init = function() {
  117. if (!this.$element.isTag('table')) return
  118. this.$container = this.$element.parent().addClass('bjui-resizeGrid')
  119. this.$fixed = undefined
  120. var width = this.$container.width()
  121. var height = this.options.height
  122. if (this.$container.hasClass('tab-pane')) width = this.$container.parent().width() - 20
  123. if (typeof this.options.width == 'string' && this.options.width.indexOf('%')) {
  124. this.options.newWidth = width * (this.options.width.replace('%', '') / 100)
  125. } else {
  126. this.options.newWidth = parseInt(this.options.width)
  127. }
  128. this.options.styles = []
  129. this.$element.wrap('<div class="bjui-tablefixed clearfix"></div>')
  130. this.$fixed = this.$element.parent()
  131. this.initHead()
  132. this.initBody()
  133. this.resizeCol()
  134. this.resizeGrid()
  135. if (height && !this.$fixed.closest('.tab-content').length) this.$fixed.height(height).addClass('fixedH')
  136. }
  137. Tablefixed.prototype.initHead = function() {
  138. var styles = this.options.styles = []
  139. var $hTrs = this.$element.find('thead > tr')
  140. var $fThs = $hTrs.eq(0).find('> th')
  141. var $table = this.$element
  142. var fixedW = 0
  143. var hTh = []
  144. var cols = []
  145. var jj = -1
  146. $fThs.each(function(i) {
  147. var $th = $(this),
  148. colspan = parseInt($th.attr('colspan') || 1),
  149. width = $th.attr('width'),
  150. align = $th.attr('align'),
  151. w = ''
  152. for (var k = 0; k < colspan; k++) {
  153. if (colspan == 1 && width) w = ' width="'+ width +'"'
  154. if (align) $th.removeAttr('align').addClass(align)
  155. hTh.push('<th'+ w +'></th>')
  156. }
  157. $th.attr('colsNum', jj += colspan)
  158. cols[i] = colspan
  159. })
  160. var thLen = hTh.length,
  161. $hTh = $('<tr class="resize-head">'+ hTh.join('') +'</tr>')
  162. if ($hTrs.length > 1) {
  163. jj = 0
  164. var $ths2 = $hTrs.eq(1).find('> th')
  165. $.each(cols, function(i, n) {
  166. n = parseInt(n)
  167. if (n > 1) {
  168. var colsNum = parseInt($fThs.eq(i).attr('colsnum'))
  169. for (var k = n - 1; k >= 0; k--) {
  170. var $th = $ths2.eq(jj++), myNum = colsNum - k, width = $th.attr('width'), align = $th.attr('align')
  171. var $_th = $hTh.find('> th').eq(myNum)
  172. if ($th && $th.length) $th.attr('colsnum', myNum)
  173. if (width) $_th.attr('width', width)
  174. if (align) $th.addClass(align).removeAttr('align')
  175. }
  176. }
  177. })
  178. }
  179. this.$fixed.html(this.$element.html())
  180. var $thead = this.$fixed.find('thead')
  181. $thead.prepend($hTh)
  182. $hTh.find('> th').each(function(i) {
  183. var $th = $(this)
  184. var style = [], width = $th.innerWidth()
  185. style[0] = parseInt(width)
  186. fixedW += style[0]
  187. styles[styles.length] = style
  188. })
  189. fixedW = parseInt((this.options.newWidth - Tablefixed.SCROLLW - fixedW) / thLen)
  190. var $ths = $thead.find('> tr:eq(0) > th')
  191. this.options.$ths = $ths
  192. $ths.each(function(i) {
  193. var $th = $(this), style = styles[i], w = $th.attr('width')
  194. $th
  195. .removeAttr('align')
  196. .width(style[0] + fixedW)
  197. style[0] = (style[0] + fixedW)
  198. if (w) {
  199. style[0] = parseInt(w)
  200. $th.width(w).removeAttr('width')
  201. }
  202. })
  203. $thead.find('> tr:gt(0) > th').each(function() {
  204. var $th = $(this)
  205. $th.html('<div class="fixedtableCol">'+ $th.html() +'</div>')
  206. })
  207. $thead.wrap('<div class="fixedtableHeader" style="width:'+ (this.options.newWidth - Tablefixed.SCROLLW) + 'px;overflow:hidden;"><div class="fixedtableThead"><table class="table table-bordered" style="width:'+ (this.options.newWidth - Tablefixed.SCROLLW) + 'px; max-width:'+ (this.options.newWidth - Tablefixed.SCROLLW) +'px;"></table></div></div>')
  208. this.$fixed.append('<div class="resizeMarker" style="display:none; height:300px; left:57px;"></div><div class="resizeProxy" style="left:377px; display:none; height:300px;"></div>')
  209. }
  210. Tablefixed.prototype.initBody = function() {
  211. var that = this
  212. var $tbody = this.$fixed.find('> tbody')
  213. var styles = this.options.styles
  214. var style, height
  215. if (this.options.height) {
  216. height = (this.options.height - this.$fixed.find('.fixedtableHeader').height()) +'px'
  217. } else {
  218. height = '100%'
  219. var resizeH = function() {
  220. var _height = that.$fixed.parent().height()
  221. that.$fixed.parent().css('overflow', 'hidden')
  222. that.$fixed.height(_height)
  223. .find('.fixedtableScroller').height(_height - that.$fixed.find('.fixedtableHeader').height())
  224. }
  225. $(document).one(BJUI.eventType.afterInitUI, function(e) {
  226. resizeH()
  227. })
  228. }
  229. style = 'style="height:'+ height +'; overflow-y:auto;"'
  230. $tbody.wrap('<div class="fixedtableScroller"'+ style +' style="width:'+ (this.options.newWidth) +'px;"><div class="fixedtableTbody"><table style="width:'+ (this.options.newWidth - Tablefixed.SCROLLW) +'px; max-width:'+ (this.options.newWidth - Tablefixed.SCROLLW) +'px;"></table></div></div>')
  231. if (!this.$element.attr('class')) $tbody.parent().addClass('table table-striped table-bordered table-hover')
  232. else $tbody.parent().addClass(this.$element.attr('class'))
  233. if (typeof this.$element.attr('data-selected-multi') != 'undefined') $tbody.parent().attr('data-selected-multi', this.$element.attr('data-selected-multi'))
  234. $tbody.before('<thead><tr class="resize-head">'+ this.$fixed.find('thead > tr').html() +'</tr></thead>')
  235. this.options.$tds = $tbody.prev().find('> tr:first-child > th')
  236. if (this.options.nowrap) $tbody.parent().addClass('nowrap')
  237. $tbody.closest('.fixedtableScroller').scroll(function(e) {
  238. var $scroller = $(this)
  239. var scrollLeft = $scroller.scrollLeft()
  240. var $header = $scroller.prev().find('> .fixedtableThead')
  241. $header.css({ 'position':'relative', 'left':-scrollLeft })
  242. return false
  243. })
  244. }
  245. Tablefixed.prototype.resizeCol = function() {
  246. var that = this
  247. var $fixed = this.$fixed
  248. var $ths = this.options.$ths
  249. var $tds = this.options.$tds
  250. var tools = this.tools
  251. $fixed.find('thead > tr:gt(0) > th').each(function(i) {
  252. var $th = $(this)
  253. $th.mouseover(function(e) {
  254. var ofLeft = parseInt($fixed.find('.fixedtableThead').css('left')) || 0
  255. var offset = tools.getOffset($th, e).offsetX
  256. var $resizeTh = $ths.eq($th.attr('colsnum'))
  257. if ($th.outerWidth() - offset < 5) {
  258. $th.css('cursor', 'col-resize').off('mousedown.bjui.tablefixed.resize').on('mousedown.bjui.tablefixed.resize', function(event) {
  259. $fixed.find('> .resizeProxy')
  260. .show()
  261. .css({
  262. left: tools.getRight($resizeTh) + ofLeft + $fixed.position().left,
  263. top: $fixed.position().top,
  264. height: $fixed.height(),
  265. cursor: 'col-resize'
  266. })
  267. .basedrag({
  268. scop: true, cellMinW:20, relObj:$fixed.find('.resizeMarker'),
  269. move: 'horizontal',
  270. event: event,
  271. stop: function() {
  272. var pleft = $fixed.find('.resizeProxy').position().left
  273. var mleft = $fixed.find('.resizeMarker').position().left
  274. var move = pleft - mleft - $resizeTh.outerWidth() - 9
  275. var cellNum = tools.getCellNum($resizeTh)
  276. var oldW = $resizeTh.width(), newW = $resizeTh.width() + move
  277. var $dcell = $tds.eq(cellNum - 1)
  278. var tableW = $fixed.find('> .fixedtableHeader .table').width()
  279. $resizeTh.width(newW)
  280. $dcell.width(newW)
  281. $fixed.find('.table').width(tableW + move)
  282. $fixed.find('.resizeMarker, .resizeProxy').hide()
  283. if ((tableW + move + Tablefixed.SCROLLW) < that.options.newWidth) {
  284. $fixed.find('.fixedtableScroller').width(tableW + move + Tablefixed.SCROLLW)
  285. } else {
  286. var newW = $fixed.closest('.bjui-resizeGrid').innerWidth()
  287. if ((tableW + move + Tablefixed.SCROLLW) < newW) newW = (tableW + move + Tablefixed.SCROLLW)
  288. $fixed.find('.fixedtableHeader').width(newW - Tablefixed.SCROLLW)
  289. $fixed.find('.fixedtableScroller').width(newW)
  290. $fixed.width(newW)
  291. }
  292. $fixed.data('resizeGrid', true)
  293. }
  294. })
  295. $fixed
  296. .find('> .resizeMarker')
  297. .show()
  298. .css({
  299. left: tools.getLeft($resizeTh) + ofLeft + $fixed.position().left,
  300. top: $fixed.position().top,
  301. height: $fixed.height()
  302. })
  303. })
  304. } else {
  305. $th
  306. .css('cursor', 'default')
  307. .off('mousedown.bjui.tablefixed.resize')
  308. }
  309. return false
  310. })
  311. })
  312. }
  313. Tablefixed.prototype.setOrderBy = function(options) {
  314. var $th = this.$element,
  315. $orderBox = $th.find('.fixedtableCol'),
  316. $order = $(FRAG.orderby.replace('#asc#', BJUI.regional.orderby.asc).replace('#desc#', BJUI.regional.orderby.desc))
  317. options = options || this.options
  318. $th.addClass('orderby')
  319. if (options.orderDirection) {
  320. if (!BJUI.ui.clientPaging) $th.addClass(options.orderDirection)
  321. $th.pagination('setClientOrder', {orderField:options.orderField, orderDirection:options.orderDirection})
  322. }
  323. if (!$orderBox.length) {
  324. $orderBox = $('<div class="fixedtableCol">'+ $th.html() +'</div>')
  325. .appendTo($th.empty())
  326. }
  327. $order
  328. .data('orderField', options.orderField)
  329. .appendTo($orderBox)
  330. .pagination('orderBy')
  331. }
  332. Tablefixed.prototype.resizeGrid = function() {
  333. var that = this
  334. var _resizeGrid = function() {
  335. $('div.bjui-resizeGrid').each(function() {
  336. var $this = $(this), $navtab = $this.closest('.navtabPage'),
  337. width = $this.width(),
  338. height = $this.height(),
  339. $fixed = $this.find('.bjui-tablefixed'),
  340. fixedH = $fixed.find('.fixedtableThead').height(),
  341. newWidth = that.options.newWidth,
  342. realWidth
  343. if ($this.length && $this.is(':hidden')) {
  344. if (!$this.hasClass('tab-pane')) {
  345. $navtab.show()
  346. width = $this.innerWidth()
  347. height = $this.height()
  348. fixedH = $fixed.find('.fixedtableHeader').height()
  349. $navtab.hide()
  350. }
  351. }
  352. if (width) {
  353. $this.find('.bjui-tablefixed').each(function() {
  354. var $fixed = $(this)
  355. if (!$fixed.data('resizeGrid')) realWidth = width
  356. else realWidth = newWidth
  357. $fixed.width(realWidth)
  358. $fixed.find('.table').width(realWidth - Tablefixed.SCROLLW)
  359. $fixed.find('.fixedtableHeader').width(realWidth - Tablefixed.SCROLLW)
  360. $fixed.find('.fixedtableScroller').width(realWidth)
  361. })
  362. }
  363. /* resizeH */
  364. $this.css('overflow', 'hidden')
  365. $fixed.height(height)
  366. .find('.fixedtableScroller').height(height - fixedH)
  367. })
  368. var resizeH = function() {
  369. var _height = that.$fixed.parent().height()
  370. that.$fixed.parent().css('overflow', 'hidden')
  371. that.$fixed.height(_height)
  372. .find('.fixedtableScroller').height(_height - that.$fixed.find('.fixedtableHeader').height())
  373. }
  374. }
  375. $(window).on(BJUI.eventType.resizeGrid, _resizeGrid)
  376. }
  377. // TABLEFIXED PLUGIN DEFINITION
  378. // =======================
  379. function Plugin(option) {
  380. var args = arguments
  381. var property = option
  382. return this.each(function () {
  383. var $this = $(this)
  384. var options = $.extend({}, Tablefixed.DEFAULTS, $this.data(), typeof option == 'object' && option)
  385. var data = $this.data('bjui.tablefixed')
  386. if (!data) $this.data('bjui.tablefixed', (data = new Tablefixed(this, options)))
  387. if (typeof property == 'string' && $.isFunction(data[property])) {
  388. [].shift.apply(args)
  389. if (!args) data[property]()
  390. else data[property].apply(data, args)
  391. } else {
  392. data.init()
  393. }
  394. })
  395. }
  396. var old = $.fn.tablefixed
  397. $.fn.tablefixed = Plugin
  398. $.fn.tablefixed.Constructor = Tablefixed
  399. // TABLEFIXED NO CONFLICT
  400. // =================
  401. $.fn.tablefixed.noConflict = function () {
  402. $.fn.tablefixed = old
  403. return this
  404. }
  405. // TABLEFIXED DATA-API
  406. // ==============
  407. $(document).on(BJUI.eventType.initUI, function(e) {
  408. var $this = $(e.target).find('table[data-toggle="tablefixed"]')
  409. if (!$this.length) return
  410. Plugin.call($this)
  411. })
  412. /* orderby */
  413. $(document).on(BJUI.eventType.afterInitUI, function(e) {
  414. var $this = $(e.target).find('th[data-order-field]')
  415. if (!$this.length) return
  416. Plugin.call($this, 'setOrderBy')
  417. })
  418. /* selected tr */
  419. $(document).on('click.bjui.tr.data-api', 'tr[data-id]', function(e) {
  420. var $this = $(this),
  421. $table = $this.closest('table'),
  422. multi = $table.data('selectedMulti'),
  423. id = $this.attr('data-id'),
  424. clsName = 'selected',
  425. $selected = $table.closest('.unitBox').find('#bjui-selected')
  426. $this.toggleClass(clsName)
  427. if (multi) {
  428. id = []
  429. $this.siblings('.'+ clsName).add(($this.hasClass(clsName) ? $this : '')).each(function() {
  430. id.push($(this).attr('data-id'))
  431. })
  432. id = id.join(',')
  433. } else {
  434. $this.siblings().removeClass(clsName)
  435. if (!$this.hasClass(clsName)) id = ''
  436. }
  437. if ($selected && $selected.length) {
  438. $selected.val(id)
  439. } else {
  440. $selected = $('<input type="hidden" id="bjui-selected" value="'+ id +'">')
  441. $selected.appendTo($table.closest('.unitBox'))
  442. }
  443. })
  444. }(jQuery);