field_sorter.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. // jQuery UI style "widget" for selecting and sorting "fields"
  2. $(function()
  3. {
  4. // the widget definition, where "itop" is the namespace,
  5. // "fieldsorter" the widget name
  6. $.widget( "itop.fieldsorter",
  7. {
  8. // default options
  9. options:
  10. {
  11. fields: {},
  12. labels: { moveup: 'Move Up', movedown: 'Move Down' },
  13. onChange: null
  14. },
  15. // the constructor
  16. _create: function()
  17. {
  18. var me = this;
  19. this.element
  20. .addClass('itop-fieldsorter');
  21. var me = this;
  22. this._initFields();
  23. var width = 10+this.element.width();
  24. this.moveup_btn = $('<button type="button" disabled style="position: absolute; top: 0; left: '+width+'px;">'+this.options.labels.moveup+'</button>');
  25. this.movedown_btn = $('<button type="button" disabled style="position: absolute; top: 30px; left: '+width+'px;">'+this.options.labels.movedown+'</button>');
  26. this.element.wrap('<div style="position:relative;"></div>');
  27. this.element.parent().append(this.moveup_btn).append(this.movedown_btn);
  28. this.moveup_btn.click(function() { me._moveUp(); });
  29. this.movedown_btn.click(function() { me._moveDown(); });
  30. },
  31. // called when created, and later when changing options
  32. _refresh: function()
  33. {
  34. this.element.find('li').remove();
  35. this._initFields();
  36. },
  37. _initFields: function()
  38. {
  39. var me = this;
  40. for(alias in this.options.fields)
  41. {
  42. for(k in this.options.fields[alias])
  43. {
  44. var f = this.options.fields[alias][k];
  45. if (f.label != '')
  46. {
  47. var sChecked = '';
  48. if (f.checked) sChecked = ' checked';
  49. var sDisabled = '';
  50. if (f.disabled) sDisabled = ' disabled';
  51. var sSortOrder = '';
  52. if (f.sort)
  53. {
  54. var sHidden = ' sort_hidden';
  55. if (f.checked) sHidden = '';
  56. if (f.sort == 'none')
  57. {
  58. sSortOrder = '&nbsp;<span sort="none" class="sort_order sort_none' + sHidden + '"/>&nbsp;</span>';
  59. }
  60. else if (f.sort == 'asc')
  61. {
  62. sSortOrder = '&nbsp;<span sort="none" class="sort_order sort_asc' + sHidden + '"/>&nbsp;</span>';
  63. }
  64. else if (f.sort == 'desc')
  65. {
  66. sSortOrder = '&nbsp;<span sort="none" class="sort_order sort_desc' + sHidden + '">&nbsp;</span>';
  67. }
  68. }
  69. var field = $('<li name="' + k + '" alias="' + f.alias + '" code="' + f.code + '"><input type="checkbox"' + sChecked + sDisabled + '/>&nbsp;' + f.label + sSortOrder + '</li>');
  70. field.click(function() { me._selectItem(this); });
  71. field.find('input').click(function() { me._checkboxClicked(this); } );
  72. field.find('span').click(function() { me._sortOrderClicked(this); } );
  73. this.element.append(field);
  74. }
  75. }
  76. }
  77. this.element.sortable({items: 'li:not(.ui-state-disabled)', start: function(event, ui) { me._selectItem(ui.item.get(0)); }, stop: function(event, ui) { me._onSortStop(event, ui); } });
  78. },
  79. // events bound via _bind are removed automatically
  80. // revert other modifications here
  81. _destroy: function()
  82. {
  83. this.element
  84. .removeClass('itop-fieldsorter');
  85. this.moveup_btn.remove();
  86. this.movedown_btn.remove();
  87. this.element.sortable('destroy').html('');
  88. },
  89. // _setOptions is called with a hash of all options that are changing
  90. _setOptions: function()
  91. {
  92. // in 1.9 would use _superApply
  93. this._superApply(arguments);
  94. },
  95. // _setOption is called for each individual option that is changing
  96. _setOption: function( key, value )
  97. {
  98. // in 1.9 would use _super
  99. this._superApply(arguments);
  100. if (key == 'fields') this._refresh();
  101. },
  102. _selectItem: function(item)
  103. {
  104. this.element.find('li').each(function() {
  105. if (this == item)
  106. {
  107. $(this).addClass('selected');
  108. }
  109. else
  110. {
  111. $(this).removeClass('selected');
  112. }
  113. });
  114. this.moveup_btn.removeAttr('disabled');
  115. this.movedown_btn.removeAttr('disabled');
  116. },
  117. _moveUp: function()
  118. {
  119. var oSelected = this.element.find('li.selected');
  120. if (oSelected.length == 0) return;
  121. var oPrev = oSelected.prev();
  122. if (oPrev.length != 0)
  123. {
  124. if (!oPrev.hasClass('ui-state-disabled'))
  125. {
  126. // Not at the top, let's move up
  127. var oNew = oSelected.clone(true);
  128. oPrev.before(oNew);
  129. oSelected.remove();
  130. this._scrollIntoView(oNew);
  131. this._notifyChange();
  132. }
  133. }
  134. this._notifyChange();
  135. },
  136. _moveDown: function()
  137. {
  138. var oSelected = this.element.find('li.selected');
  139. if (oSelected.length == 0) return;
  140. if (oSelected.hasClass('ui-state-disabled')) return; // not moveable
  141. var oNext = oSelected.next();
  142. if (oNext.length != 0)
  143. {
  144. // Not at the top, let's move up
  145. var oNew = oSelected.clone(true);
  146. oNext.after(oNew);
  147. oSelected.remove();
  148. this._scrollIntoView(oNew);
  149. }
  150. this._notifyChange();
  151. },
  152. _scrollIntoView: function(item)
  153. {
  154. var containerTop = this.element.scrollTop();
  155. var containerHeight = this.element.height();
  156. var itemTop = item.position().top;
  157. var itemBottom = itemTop + item.height();
  158. if (itemTop < 0)
  159. {
  160. this.element.scrollTop(containerTop + itemTop);
  161. }
  162. else if (itemBottom > containerHeight)
  163. {
  164. this.element.scrollTop(containerTop + itemBottom - this.element.height());
  165. }
  166. },
  167. _onSortStop: function(event, ui)
  168. {
  169. this._notifyChange();
  170. },
  171. _checkboxClicked: function(elt)
  172. {
  173. if (elt.checked)
  174. {
  175. $(elt).parent().find('span.sort_order').removeClass('sort_hidden');
  176. }
  177. else
  178. {
  179. $(elt).parent().find('span.sort_order').addClass('sort_hidden');
  180. }
  181. this._notifyChange();
  182. },
  183. _sortOrderClicked: function(elt)
  184. {
  185. // Reset all other sort orders
  186. var oElt = $(elt);
  187. this.element.find('span.sort_order').each(function(){
  188. if (this != elt)
  189. {
  190. $(this).attr('sort', 'none').removeClass('sort_asc').removeClass('sort_desc').addClass('sort_none');
  191. }
  192. });
  193. var sSortOrder = oElt.attr('sort');
  194. if (sSortOrder == 'none')
  195. {
  196. oElt.attr('sort', 'asc').removeClass('sort_none').addClass('sort_asc');
  197. }
  198. else if (sSortOrder == 'asc')
  199. {
  200. oElt.attr('sort', 'desc').removeClass('sort_asc').addClass('sort_desc');
  201. }
  202. else if (sSortOrder == 'desc')
  203. {
  204. oElt.attr('sort', 'none').removeClass('sort_desc').addClass('sort_none');
  205. }
  206. this._notifyChange();
  207. },
  208. _notifyChange: function()
  209. {
  210. if (this.options.onChange)
  211. {
  212. this.options.onChange();
  213. }
  214. },
  215. get_params: function()
  216. {
  217. var oParams = {};
  218. var me = this;
  219. this.element.find('li').each(function() {
  220. var oItem = $(this);
  221. var sName = oItem.attr('name');
  222. var sCode, sAlias;
  223. if (sName == undefined)
  224. {
  225. sName = '_key_'; // By convention the unnamed first column is the key
  226. sCode = 'id';
  227. sAlias = '';
  228. sLabel = '';
  229. }
  230. else
  231. {
  232. sCode = oItem.attr('code');
  233. sAlias = oItem.attr('alias');
  234. sLabel = me.options.fields[sAlias][sCode].label;
  235. }
  236. var oCheckbox = oItem.find('input[type=checkbox]');
  237. var bChecked = false;
  238. if (oCheckbox.attr('checked'))
  239. {
  240. bChecked = true;
  241. }
  242. var bDisabled = false;
  243. if (oCheckbox.attr('disabled'))
  244. {
  245. bDisabled = true;
  246. }
  247. var sSort = undefined;
  248. var oSort = oItem.find('span.sort_order');
  249. if (oSort.length > 0)
  250. {
  251. sSort = oSort.attr('sort');
  252. }
  253. var oData = { checked: bChecked, disabled: bDisabled, sort: sSort, code:sCode, alias: sAlias, label: sLabel };
  254. if (oParams[sAlias] == undefined) oParams[sAlias] = {};
  255. oParams[sAlias][sCode] = oData;
  256. });
  257. return oParams;
  258. }
  259. });
  260. });