field_sorter.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277
  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. // call the original destroy method since we overwrote it
  89. $.Widget.prototype.destroy.call( this );
  90. },
  91. // _setOptions is called with a hash of all options that are changing
  92. _setOptions: function()
  93. {
  94. // in 1.9 would use _superApply
  95. $.Widget.prototype._setOptions.apply( this, arguments );
  96. },
  97. // _setOption is called for each individual option that is changing
  98. _setOption: function( key, value )
  99. {
  100. // in 1.9 would use _super
  101. $.Widget.prototype._setOption.call( this, key, value );
  102. if (key == 'fields') this._refresh();
  103. },
  104. _selectItem: function(item)
  105. {
  106. this.element.find('li').each(function() {
  107. if (this == item)
  108. {
  109. $(this).addClass('selected');
  110. }
  111. else
  112. {
  113. $(this).removeClass('selected');
  114. }
  115. });
  116. this.moveup_btn.removeAttr('disabled');
  117. this.movedown_btn.removeAttr('disabled');
  118. },
  119. _moveUp: function()
  120. {
  121. var oSelected = this.element.find('li.selected');
  122. if (oSelected.length == 0) return;
  123. var oPrev = oSelected.prev();
  124. if (oPrev.length != 0)
  125. {
  126. if (!oPrev.hasClass('ui-state-disabled'))
  127. {
  128. // Not at the top, let's move up
  129. var oNew = oSelected.clone(true);
  130. oPrev.before(oNew);
  131. oSelected.remove();
  132. this._scrollIntoView(oNew);
  133. this._notifyChange();
  134. }
  135. }
  136. this._notifyChange();
  137. },
  138. _moveDown: function()
  139. {
  140. var oSelected = this.element.find('li.selected');
  141. if (oSelected.length == 0) return;
  142. if (oSelected.hasClass('ui-state-disabled')) return; // not moveable
  143. var oNext = oSelected.next();
  144. if (oNext.length != 0)
  145. {
  146. // Not at the top, let's move up
  147. var oNew = oSelected.clone(true);
  148. oNext.after(oNew);
  149. oSelected.remove();
  150. this._scrollIntoView(oNew);
  151. }
  152. this._notifyChange();
  153. },
  154. _scrollIntoView: function(item)
  155. {
  156. var containerTop = this.element.scrollTop();
  157. var containerHeight = this.element.height();
  158. var itemTop = item.position().top;
  159. var itemBottom = itemTop + item.height();
  160. if (itemTop < 0)
  161. {
  162. this.element.scrollTop(containerTop + itemTop);
  163. }
  164. else if (itemBottom > containerHeight)
  165. {
  166. this.element.scrollTop(containerTop + itemBottom - this.element.height());
  167. }
  168. },
  169. _onSortStop: function(event, ui)
  170. {
  171. this._notifyChange();
  172. },
  173. _checkboxClicked: function(elt)
  174. {
  175. if (elt.checked)
  176. {
  177. $(elt).parent().find('span.sort_order').removeClass('sort_hidden');
  178. }
  179. else
  180. {
  181. $(elt).parent().find('span.sort_order').addClass('sort_hidden');
  182. }
  183. this._notifyChange();
  184. },
  185. _sortOrderClicked: function(elt)
  186. {
  187. // Reset all other sort orders
  188. var oElt = $(elt);
  189. this.element.find('span.sort_order').each(function(){
  190. if (this != elt)
  191. {
  192. $(this).attr('sort', 'none').removeClass('sort_asc').removeClass('sort_desc').addClass('sort_none');
  193. }
  194. });
  195. var sSortOrder = oElt.attr('sort');
  196. if (sSortOrder == 'none')
  197. {
  198. oElt.attr('sort', 'asc').removeClass('sort_none').addClass('sort_asc');
  199. }
  200. else if (sSortOrder == 'asc')
  201. {
  202. oElt.attr('sort', 'desc').removeClass('sort_asc').addClass('sort_desc');
  203. }
  204. else if (sSortOrder == 'desc')
  205. {
  206. oElt.attr('sort', 'none').removeClass('sort_desc').addClass('sort_none');
  207. }
  208. this._notifyChange();
  209. },
  210. _notifyChange: function()
  211. {
  212. if (this.options.onChange)
  213. {
  214. this.options.onChange();
  215. }
  216. },
  217. get_params: function()
  218. {
  219. var oParams = {};
  220. var me = this;
  221. this.element.find('li').each(function() {
  222. var oItem = $(this);
  223. var sName = oItem.attr('name');
  224. var sCode, sAlias;
  225. if (sName == undefined)
  226. {
  227. sName = '_key_'; // By convention the unnamed first column is the key
  228. sCode = 'id';
  229. sAlias = '';
  230. sLabel = '';
  231. }
  232. else
  233. {
  234. sCode = oItem.attr('code');
  235. sAlias = oItem.attr('alias');
  236. sLabel = me.options.fields[sAlias][sCode].label;
  237. }
  238. var oCheckbox = oItem.find('input[type=checkbox]');
  239. var bChecked = false;
  240. if (oCheckbox.attr('checked'))
  241. {
  242. bChecked = true;
  243. }
  244. var bDisabled = false;
  245. if (oCheckbox.attr('disabled'))
  246. {
  247. bDisabled = true;
  248. }
  249. var sSort = undefined;
  250. var oSort = oItem.find('span.sort_order');
  251. if (oSort.length > 0)
  252. {
  253. sSort = oSort.attr('sort');
  254. }
  255. var oData = { checked: bChecked, disabled: bDisabled, sort: sSort, code:sCode, alias: sAlias, label: sLabel };
  256. if (oParams[sAlias] == undefined) oParams[sAlias] = {};
  257. oParams[sAlias][sCode] = oData;
  258. });
  259. return oParams;
  260. }
  261. });
  262. });