linksdirectwidget.js 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531
  1. // jQuery UI style "widget" for managing 1:n links "in-place"
  2. $(function()
  3. {
  4. // the widget definition, where "itop" is the namespace,
  5. // "directlinks" the widget name
  6. $.widget( "itop.directlinks",
  7. {
  8. // default options
  9. options:
  10. {
  11. input_name: '',
  12. class_name: '',
  13. att_code: '',
  14. submit_to: '../pages/ajax.render.php',
  15. submit_parameters: {},
  16. labels: { 'delete': 'Delete',
  17. modify: 'Modify...' ,
  18. creation_title: 'Creation of a new object...' ,
  19. create: 'Create...',
  20. add: 'Add...',
  21. remove: 'Remove',
  22. selection_title: 'Objects selection'
  23. },
  24. buttons: ['create', 'delete'],
  25. oWizardHelper: null
  26. },
  27. // the constructor
  28. _create: function()
  29. {
  30. var me = this;
  31. this.id = this.element.attr('id');
  32. this.element
  33. .addClass('itop-directlinks');
  34. this.datatable = this.element.find('table.listResults');
  35. var aButtonsTypes = ['delete', 'remove', 'modify', 'add', 'create'];
  36. this.oButtons = {};
  37. for(k in aButtonsTypes)
  38. {
  39. this.oButtons[aButtonsTypes[k]] = $('<button type="button">' + this.options.labels[aButtonsTypes[k]] + '</button>');
  40. }
  41. this.indicator = $('<span></span>');
  42. this.inputToBeCreated = $('<input type="hidden" name="'+this.options.input_name+'_tbc" value="{}">');
  43. this.toBeCreated = {};
  44. this.inputToBeDeleted = $('<input type="hidden" name="'+this.options.input_name+'_tbd" value="[]">');
  45. this.toBeDeleted = [];
  46. this.inputToBeAdded = $('<input type="hidden" name="'+this.options.input_name+'_tba" value="[]">');
  47. this.toBeAdded = [];
  48. this.inputToBeRemoved = $('<input type="hidden" name="'+this.options.input_name+'_tbr" value="[]">');
  49. this.toBeRemoved = [];
  50. this.element
  51. .after(this.inputToBeCreated)
  52. .after(this.inputToBeDeleted)
  53. .after(this.inputToBeAdded)
  54. .after(this.inputToBeRemoved)
  55. .after('<span style="float:left">&nbsp;&nbsp;&nbsp;<img src="../images/tv-item-last.gif">&nbsp;&nbsp;&nbsp;')
  56. .after(this.indicator);
  57. for(k in this.options.buttons)
  58. {
  59. this.element.after(this.oButtons[this.options.buttons[k]]).after('&nbsp;&nbsp;&nbsp;');
  60. }
  61. this.element.find('.selectList'+this.id).bind('change', function() { me._updateButtons(); });
  62. this.oButtons['delete'].click(function() {
  63. $('.selectList'+me.id+':checked', me.element).each( function() { me._deleteRow($(this)); });
  64. });
  65. this.oButtons['create'].click(function() {
  66. me._createRow();
  67. });
  68. this.oButtons['remove'].click(function() {
  69. $('.selectList'+me.id+':checked', me.element).each( function() { me._removeRow($(this)); });
  70. });
  71. this.oButtons['add'].click(function() {
  72. me._selectToAdd();
  73. });
  74. this._updateButtons();
  75. },
  76. // called when created, and later when changing options
  77. _refresh: function()
  78. {
  79. this._updateButtons();
  80. },
  81. // events bound via _bind are removed automatically
  82. // revert other modifications here
  83. _destroy: function()
  84. {
  85. this.element
  86. .removeClass('itop-directlinks');
  87. },
  88. // _setOptions is called with a hash of all options that are changing
  89. _setOptions: function()
  90. {
  91. // in 1.9 would use _superApply
  92. this._superApply(arguments);
  93. },
  94. // _setOption is called for each individual option that is changing
  95. _setOption: function( key, value )
  96. {
  97. // in 1.9 would use _super
  98. this._superApply(arguments);
  99. if (key == 'fields') this._refresh();
  100. },
  101. _updateButtons: function()
  102. {
  103. var oChecked = $('.selectList'+this.id+':checked', this.element);
  104. switch(oChecked.length)
  105. {
  106. case 0:
  107. this.oButtons['delete'].attr('disabled', 'disabled');
  108. this.oButtons['remove'].attr('disabled', 'disabled');
  109. this.oButtons['modify'].attr('disabled', 'disabled');
  110. break;
  111. case 1:
  112. this.oButtons['delete'].removeAttr('disabled');
  113. this.oButtons['remove'].removeAttr('disabled');
  114. this.oButtons['modify'].removeAttr('disabled');
  115. break;
  116. default:
  117. this.oButtons['delete'].removeAttr('disabled');
  118. this.oButtons['remove'].removeAttr('disabled');
  119. this.oButtons['modify'].attr('disabled', 'disabled');
  120. break;
  121. }
  122. },
  123. _updateTable: function()
  124. {
  125. var me = this;
  126. this.datatable.trigger("update").trigger("applyWidgets");
  127. this.datatable.tableHover();
  128. this.datatable.find('.selectList'+this.id).bind('change', function() { me._updateButtons(); });
  129. },
  130. _updateDlgPosition: function()
  131. {
  132. this.oDlg.dialog('option', { position: { my: "center", at: "center", of: window }});
  133. },
  134. _createRow: function()
  135. {
  136. this.oButtons['create'].attr('disabled', 'disabled');
  137. this.indicator.html('<img src="../images/indicator.gif">');
  138. oParams = this.options.submit_parameters;
  139. oParams.operation = 'createObject';
  140. oParams['class'] = this.options.class_name;
  141. oParams.real_class = '';
  142. oParams.att_code = this.options.att_code;
  143. oParams.iInputId = this.id;
  144. var me = this;
  145. $.post(this.options.submit_to, oParams, function(data){
  146. me.oDlg = $('<div></div>');
  147. $('body').append(me.oDlg);
  148. me.oDlg.html(data);
  149. me.oDlg.find('form').removeAttr('onsubmit').bind('submit', function() { me._onCreateRow(); return false; } );
  150. me.oDlg.find('button.cancel').unbind('click').click( function() { me.oDlg.dialog('close'); } );
  151. me.oDlg.dialog({
  152. title: me.options.labels['creation_title'],
  153. modal: true,
  154. width: 'auto',
  155. height: 'auto',
  156. position: { my: "center", at: "center", of: window },
  157. close: function() { me._onDlgClose(); }
  158. });
  159. me.indicator.html('');
  160. me.oButtons['create'].removeAttr('disabled');
  161. me._updateDlgPosition();
  162. });
  163. },
  164. _selectToAdd: function()
  165. {
  166. this.oButtons['add'].attr('disabled', 'disabled');
  167. this.indicator.html('<img src="../images/indicator.gif">');
  168. oParams = this.options.submit_parameters;
  169. oParams.operation = 'selectObjectsToAdd';
  170. oParams['class'] = this.options.class_name;
  171. oParams.real_class = '';
  172. oParams.att_code = this.options.att_code;
  173. oParams.iInputId = this.id;
  174. if (this.options.oWizardHelper)
  175. {
  176. this.options.oWizardHelper.UpdateWizard();
  177. oParams.json = this.options.oWizardHelper.ToJSON();
  178. }
  179. var me = this;
  180. $.post(this.options.submit_to, oParams, function(data){
  181. me.oDlg = $('<div></div>');
  182. $('body').append(me.oDlg);
  183. me.oDlg.html(data);
  184. me.oDlg.find('form').removeAttr('onsubmit').bind('submit', function() { me._onSearchToAdd(); return false; } );
  185. me.oDlg.find('button.cancel').unbind('click').click( function() { me.oDlg.dialog('close'); } );
  186. me.oDlg.find('button.ok').unbind('click').click( function() { me._onDoAdd(); } );
  187. $('#SearchFormToAdd_'+me.id).resize(function() { me._onSearchDlgUpdateSize(); });
  188. me.oDlg.dialog({
  189. title: me.options.labels['selection_title'],
  190. modal: true,
  191. width: $(window).width()*0.8,
  192. height: $(window).height()*0.8,
  193. maxHeight: $(window).height() - 50,
  194. position: { my: "center", at: "center", of: window },
  195. close: function() { me._onDlgClose(); },
  196. resizeStop: function() { me._onSearchDlgUpdateSize(); }
  197. });
  198. me.indicator.html('');
  199. me.oButtons['add'].removeAttr('disabled');
  200. me._onSearchToAdd();
  201. me._updateDlgPosition();
  202. me._onSearchDlgUpdateSize();
  203. });
  204. },
  205. _onSearchToAdd: function()
  206. {
  207. var oParams = {};
  208. // Gather the parameters from the search form
  209. $('#SearchFormToAdd_'+this.id+' :input').each( function() {
  210. if (this.name != '')
  211. {
  212. var val = $(this).val(); // supports multiselect as well
  213. if (val !== null)
  214. {
  215. oParams[this.name] = val;
  216. }
  217. }
  218. });
  219. // Gather the already linked target objects
  220. oParams.aAlreadyLinked = new Array();
  221. $('#'+this.id+' .listResults td input:checkbox').each(function(){
  222. iKey = parseInt(this.value, 10); // Numbers are in base 10
  223. oParams.aAlreadyLinked.push(iKey);
  224. }
  225. );
  226. oParams.operation = 'searchObjectsToAdd2';
  227. oParams.real_class = '';
  228. if ((oParams['class'] != undefined) && (oParams['class'] != ''))
  229. {
  230. oParams.real_class = oParams['class'];
  231. }
  232. oParams['class'] = this.options.class_name;
  233. oParams.att_code = this.options.att_code;
  234. oParams.iInputId = this.id;
  235. if (this.options.oWizardHelper)
  236. {
  237. this.options.oWizardHelper.UpdateWizard();
  238. oParams.json = this.options.oWizardHelper.ToJSON();
  239. }
  240. var me = this;
  241. $('#SearchResultsToAdd_'+me.id).block();
  242. $.post(this.options.submit_to, oParams, function(data) {
  243. $('#SearchResultsToAdd_'+me.id).html(data);
  244. $('#SearchResultsToAdd_'+me.id+' .listResults').tableHover();
  245. $('#count_'+me.id).change(function() {
  246. var c = this.value;
  247. me._onUpdateDlgButtons(c);
  248. });
  249. FixSearchFormsDisposition();
  250. $('#SearchResultsToAdd_'+me.id).unblock();
  251. me._onSearchDlgUpdateSize();
  252. });
  253. return false; // Stay on the page, no submit
  254. },
  255. _getSelection: function(sName)
  256. {
  257. // Gather the parameters from the search form
  258. var oMap = {};
  259. var oContext = $('#SearchResultsToAdd_'+this.id);
  260. var selectionMode = $(':input[name=selectionMode]', oContext);
  261. if (selectionMode.length > 0)
  262. {
  263. // Paginated table retrieve the mode and the exceptions
  264. var sMode = selectionMode.val();
  265. oMap['selectionMode'] = sMode;
  266. $('#fs_SearchFormToAdd_'+this.id+' :input').each(
  267. function(i)
  268. {
  269. oMap[this.name] = this.value;
  270. }
  271. );
  272. $(':input[name^=storedSelection]', oContext).each(function() {
  273. if (oMap[this.name] == undefined)
  274. {
  275. oMap[this.name] = new Array();
  276. }
  277. oMap[this.name].push(this.value);
  278. });
  279. // Retrieve the 'filter' definition
  280. var table = $('#ResultsToAdd_'+this.id).find('table.listResults')[0];
  281. oMap['filter'] = table.config.filter;
  282. oMap['extra_params'] = table.config.extra_params;
  283. }
  284. // Normal table, retrieve all the checked check-boxes
  285. $(':checked[name^=selectObject]', oContext).each(
  286. function(i)
  287. {
  288. if ( (this.name != '') && ((this.type != 'checkbox') || (this.checked)) )
  289. {
  290. arrayExpr = /\[\]$/;
  291. if (arrayExpr.test(this.name))
  292. {
  293. // Array
  294. if (oMap[this.name] == undefined)
  295. {
  296. oMap[this.name] = new Array();
  297. }
  298. oMap[this.name].push(this.value);
  299. }
  300. else
  301. {
  302. oMap[this.name] = this.value;
  303. }
  304. }
  305. }
  306. );
  307. return oMap;
  308. },
  309. _onUpdateDlgButtons: function(iCount)
  310. {
  311. if (iCount > 0)
  312. {
  313. this.oDlg.find('button.ok').removeAttr('disabled');
  314. }
  315. else
  316. {
  317. this.oDlg.find('button.ok').attr('disabled', 'disabled');
  318. }
  319. },
  320. _onDoAdd:function()
  321. {
  322. var oParams = this._getSelection('selectObject');
  323. oParams.operation = 'doAddObjects2';
  324. oParams['class'] = this.options.class_name;
  325. oParams.att_code = this.options.att_code;
  326. oParams.iInputId = this.id;
  327. // Retrieve the 'filter' definition, BEFORE closing the dialog and destroying its contents
  328. var table = $('#ResultsToAdd_'+this.id).find('table.listResults')[0];
  329. oParams.filter = table.config.filter;
  330. oParams.extra_params = table.config.extra_params;
  331. this.oDlg.dialog('close');
  332. var me = this;
  333. $.post(this.options.submit_to, oParams, function(data) {
  334. var oInserted = $(data);
  335. oInserted.find('input:checkbox').each(function() {
  336. var iKey = parseInt($(this).val(), 10); // Number in base 10
  337. me.toBeAdded.push(iKey);
  338. me.toBeRemoved = me._ArrayRemove(me.toBeRemoved, iKey);
  339. me.toBeDeleted = me._ArrayRemove(me.toBeDeleted, iKey);
  340. });
  341. me.inputToBeAdded.val(JSON.stringify(me.toBeAdded));
  342. me.inputToBeRemoved.val(JSON.stringify(me.toBeRemoved));
  343. me.inputToBeDeleted.val(JSON.stringify(me.toBeDeleted));
  344. me.datatable.find('tbody').append(data);
  345. me._updateTable();
  346. me.indicator.html('');
  347. me.oButtons['add'].removeAttr('disabled');
  348. });
  349. },
  350. subclassSelected: function()
  351. {
  352. var sRealClass = this.oDlg.find('select[name="class"]').val();
  353. oParams = this.options.submit_parameters;
  354. oParams.operation = 'createObject';
  355. oParams['class'] = this.options.class_name;
  356. oParams.real_class = sRealClass;
  357. oParams.att_code = this.options.att_code;
  358. oParams.iInputId = this.id;
  359. var me = this;
  360. me.oDlg.find('button').attr('disabled', 'disabled');
  361. me.oDlg.find('span.indicator').html('<img src="../images/indicator.gif">');
  362. $.post(this.options.submit_to, oParams, function(data){
  363. me.oDlg.html(data);
  364. me.oDlg.find('form').removeAttr('onsubmit').bind('submit', function() { me._onCreateRow(); return false; } );
  365. me.oDlg.find('button.cancel').unbind('click').click( function() { me.oDlg.dialog('close'); } );
  366. me._updateDlgPosition();
  367. });
  368. },
  369. _onCreateRow: function()
  370. {
  371. // Validate the form
  372. var sFormId = this.oDlg.find('form').attr('id');
  373. if (CheckFields(sFormId, true))
  374. {
  375. // Gather the values from the form
  376. oParams = this.options.submit_parameters;
  377. var oValues = {};
  378. this.oDlg.find(':input').each( function() {
  379. if (this.name != '')
  380. {
  381. oParams[this.name] = this.value;
  382. oValues[this.name] = this.value;
  383. }
  384. });
  385. var nextIdx = 0;
  386. for(k in this.toBeCreated)
  387. {
  388. nextIdx++;
  389. }
  390. nextIdx++;
  391. this.toBeCreated[nextIdx] = oValues;
  392. this.inputToBeCreated.val(JSON.stringify(this.toBeCreated));
  393. this.oDlg.dialog('close');
  394. oParams = this.options.submit_parameters;
  395. oParams.operation = 'getLinksetRow';
  396. oParams['class'] = this.options.class_name;
  397. oParams.att_code = this.options.att_code;
  398. oParams.iInputId = this.id;
  399. oParams.tempId = nextIdx;
  400. var me = this;
  401. this.oButtons['create'].attr('disabled', 'disabled');
  402. this.indicator.html('<img src="../images/indicator.gif">');
  403. $.post(this.options.submit_to, oParams, function(data){
  404. me.datatable.find('tbody').append(data);
  405. me._updateTable();
  406. me.indicator.html('');
  407. me.oButtons['create'].removeAttr('disabled');
  408. });
  409. }
  410. },
  411. _onDlgClose: function()
  412. {
  413. this.oDlg.remove();
  414. this.oDlg = null;
  415. },
  416. _onSearchDlgUpdateSize: function()
  417. {
  418. var searchHeight = $('#SearchFormToAdd_'+this.id).outerHeight();
  419. var dlgHeight = this.oDlg.height();
  420. $('.wizContainer', this.oDlg).height(dlgHeight - 20);
  421. $('#SearchResultsToAdd_'+this.id).height(dlgHeight - 50 - searchHeight);
  422. },
  423. _deleteRow: function(oCheckbox)
  424. {
  425. var iObjKey = parseInt(oCheckbox.val(), 10); // Number in base 10
  426. if (iObjKey > 0)
  427. {
  428. // Existing objet: add it to the "to be deleted" list
  429. // if it has not just been added now
  430. if (this._InArray(this.toBeAdded, iObjKey))
  431. {
  432. this.toBeAdded = this._ArrayRemove(this.toBeAdded, iObjKey);
  433. this.inputToBeAdded.val(JSON.stringify(this.toBeAdded));
  434. }
  435. else
  436. {
  437. this.toBeDeleted.push(iObjKey);
  438. this.inputToBeDeleted.val(JSON.stringify(this.toBeDeleted));
  439. }
  440. }
  441. else
  442. {
  443. // Object to be created, just remove it from the "to be created" list
  444. this.toBeCreated = this._ArrayRemove(this.toBeCreated, iObjKey);
  445. this.inputToBeCreated.val(JSON.stringify(this.toBeCreated));
  446. }
  447. // Now remove the row from the table
  448. oRow = oCheckbox.closest('tr');
  449. oRow.remove();
  450. this._updateButtons();
  451. this._updateTable();
  452. },
  453. _removeRow: function(oCheckbox)
  454. {
  455. var iObjKey = parseInt(oCheckbox.val(), 10); // Number in base 10
  456. if (iObjKey > 0)
  457. {
  458. // Existing objet: add it to the "to be removed" list
  459. // if it has not just been added now
  460. if (this._InArray(this.toBeAdded, iObjKey))
  461. {
  462. this.toBeAdded = this._ArrayRemove(this.toBeAdded, iObjKey);
  463. this.inputToBeAdded.val(JSON.stringify(this.toBeAdded));
  464. }
  465. else
  466. {
  467. this.toBeRemoved.push(iObjKey);
  468. this.inputToBeRemoved.val(JSON.stringify(this.toBeRemoved));
  469. }
  470. }
  471. else
  472. {
  473. // Object to be created, just remove it from the "to be created" list
  474. this.toBeCreated = this._ArrayRemove(this.toBeCreated, iObjKey);
  475. this.inputToBeCreated.val(JSON.stringify(this.toBeCreated));
  476. }
  477. // Now remove the row from the table
  478. oRow = oCheckbox.closest('tr');
  479. oRow.remove();
  480. this._updateButtons();
  481. this._updateTable();
  482. },
  483. _InArray: function(aArrayToSearch, needle)
  484. {
  485. aRes = [];
  486. for(k in aArrayToSearch)
  487. {
  488. if (aArrayToSearch[k] == needle)
  489. {
  490. return true;
  491. }
  492. }
  493. return false;
  494. },
  495. _ArrayRemove: function(aArrayToFilter, needle)
  496. {
  497. aRes = [];
  498. for(k in aArrayToFilter)
  499. {
  500. if (aArrayToFilter[k] != needle)
  501. {
  502. aRes.push(aArrayToFilter[k]);
  503. }
  504. }
  505. return aRes;
  506. }
  507. });
  508. });