nodequeue.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425
  1. /**
  2. * Nodequeue object
  3. *
  4. * Settings:
  5. *
  6. * container
  7. * up
  8. * down
  9. * top
  10. * bottom:
  11. * delete: input image
  12. * order: input hidden
  13. * add: input to add items
  14. * path: path to add items
  15. * tr: the base id of the tr
  16. */
  17. Drupal.nodequeue = function(base, settings) {
  18. // Set the properties for this object.
  19. if (settings.container == null) {
  20. settings.container = settings.row_class;
  21. }
  22. var max = function(array) {
  23. return Math.max.apply(Math, array);
  24. };
  25. var array_rand = function(array) {
  26. var i = array.length;
  27. if (i == 0) return false;
  28. while (--i) {
  29. var j = Math.floor(Math.random() * ( i + 1 ));
  30. var tempi = array[i];
  31. var tempj = array[j];
  32. array[i] = tempj;
  33. array[j] = tempi;
  34. }
  35. }
  36. var maxPosition = max($(settings.order).val().split(','));
  37. this.settings = settings;
  38. this.base = '#' + base;
  39. // helper function to swap items in an array
  40. var swap = function(array, a, b) {
  41. var temp = array[a];
  42. array[a] = array[b];
  43. array[b] = temp;
  44. }
  45. var saveOrder = function(order) {
  46. var new_order = '';
  47. for (i in order) {
  48. if (new_order) {
  49. new_order += ',';
  50. }
  51. new_order += order[i];
  52. }
  53. $(settings.order).val(new_order);
  54. $(settings.hidden).show();
  55. }
  56. var changeOrder = function(item, how) {
  57. var order = $(settings.order).val().split(',');
  58. if (how != 'add' && how != 'insert') {
  59. var tr = $(item).parents('tr').get(0);
  60. var id = $(tr).attr('id').replace(settings.tr, '');
  61. var index = -1;
  62. for (var i in order) {
  63. if (order[i] == id) {
  64. index = parseInt(i);
  65. break;
  66. }
  67. }
  68. }
  69. switch (how) {
  70. case 'add':
  71. order.push(item);
  72. break;
  73. case 'insert':
  74. order.unshift(item);
  75. break;
  76. case 'delete':
  77. order.splice(index, 1);
  78. break;
  79. case 'top':
  80. var temp = order[index];
  81. order.splice(index, 1);
  82. order.unshift(temp);
  83. break;
  84. case 'up':
  85. swap(order, index, index - 1);
  86. break;
  87. case 'down':
  88. swap(order, index, index + 1);
  89. break;
  90. case 'bottom':
  91. var temp = order[index];
  92. order.splice(index, 1);
  93. order.push(temp);
  94. break;
  95. }
  96. saveOrder(order);
  97. }
  98. var makeOrder = function(order) {
  99. // Go through the new order and move each item to the bottom.
  100. // Then everything will be where it was meant to be.
  101. var last = $(settings.row_class + ':last');
  102. for (var i in order) {
  103. var item = $('#' + settings.tr + order[i]);
  104. last.after(item);
  105. changed($(item));
  106. last = item;
  107. }
  108. restripeTable('#' + base);
  109. }
  110. this.changeOrder = changeOrder;
  111. var restripeTable = function(table) {
  112. // :even and :odd are reversed because jquery counts from 0 and
  113. // we count from 1, so we're out of sync.
  114. $('tbody tr:not(:hidden)', $(table))
  115. .removeClass('even')
  116. .removeClass('odd')
  117. .filter(':even')
  118. .addClass('odd')
  119. .end()
  120. .filter(':odd')
  121. .addClass('even');
  122. }
  123. var changed = function(item) {
  124. if (!item.is('.changed')) {
  125. item.addClass('changed').css('color', 'red');
  126. item.children('td:first').prepend(' <b>*</b> ');
  127. $('p.nodequeue-warning').css('color', 'red');
  128. }
  129. }
  130. this.restripeTable = restripeTable;
  131. // Set as a function so we can be both a closure and called later
  132. // when more items get added.
  133. var bindButtons = function() {
  134. if (settings.remove) {
  135. $(settings.remove + ':not(.nodequeue-processed)')
  136. .addClass('nodequeue-processed')
  137. .click(function() { return false; })
  138. .click(function(e) {
  139. var item = $(this).parents(settings.container);
  140. changeOrder(this, 'delete');
  141. item.remove();
  142. restripeTable('#' + base);
  143. return false;
  144. });
  145. }
  146. if (settings.clear_list) {
  147. $(settings.clear_list + ':not(.nodequeue-processed)')
  148. .addClass('nodequeue-processed')
  149. .click(function() { return false; })
  150. .click(function(e) {
  151. $(settings.row_class).each(function() { $(this).remove() });
  152. saveOrder([]);
  153. });
  154. }
  155. if (settings.shuffle) {
  156. $(settings.shuffle + ':not(.nodequeue-processed)')
  157. .addClass('nodequeue-processed')
  158. .click(function() { return false; })
  159. .click(function(e) {
  160. // randomize the order
  161. var order = $(settings.order).val().split(',');
  162. array_rand(order);
  163. saveOrder(order);
  164. makeOrder(order);
  165. });
  166. }
  167. if (settings.reverse) {
  168. $(settings.reverse + ':not(.nodequeue-processed)')
  169. .addClass('nodequeue-processed')
  170. .click(function() { return false; })
  171. .click(function(e) {
  172. // reverse the order
  173. var order = $(settings.order).val().split(',');
  174. order.reverse();
  175. saveOrder(order);
  176. makeOrder(order);
  177. });
  178. }
  179. if (settings.up) {
  180. $(settings.up + ':not(.nodequeue-processed)')
  181. .addClass('nodequeue-processed')
  182. .click(function() { return false; })
  183. .click(function(e) {
  184. var item = $(this).parents(settings.container);
  185. var prev = $(item).prev();
  186. if (prev.html() != null && item != prev) {
  187. // move item
  188. prev.before(item);
  189. restripeTable('#' + base);
  190. changed(item);
  191. changeOrder(this, 'up');
  192. }
  193. return false;
  194. });
  195. }
  196. if (settings.top) {
  197. $(settings.top + ':not(.nodequeue-processed)')
  198. .addClass('nodequeue-processed')
  199. .click(function() { return false; })
  200. .click(function(e) {
  201. var item = $(this).parents(settings.container);
  202. var first = $(item).siblings(':first');
  203. first.before(item);
  204. restripeTable('#' + base);
  205. changeOrder(this, 'top');
  206. changed(item);
  207. return false;
  208. });
  209. }
  210. if (settings.down) {
  211. $(settings.down + ':not(.nodequeue-processed)')
  212. .addClass('nodequeue-processed')
  213. .click(function() { return false; })
  214. .click(function(e) {
  215. var item = $(this).parents(settings.container);
  216. var next = $(item).next();
  217. if (next.html() != null && item != next) {
  218. // move item
  219. next.after(item);
  220. restripeTable('#' + base);
  221. changeOrder(this, 'down');
  222. changed(item);
  223. }
  224. return false;
  225. });
  226. }
  227. if (settings.bottom) {
  228. $(settings.bottom + ':not(.nodequeue-processed)')
  229. .addClass('nodequeue-processed')
  230. .click(function() { return false; })
  231. .click(function(e) {
  232. var item = $(this).parents(settings.container);
  233. var last = $(item).siblings(':last');
  234. // move item
  235. last.after(item);
  236. restripeTable('#' + base);
  237. changeOrder(this, 'bottom');
  238. changed(item);
  239. return false;
  240. });
  241. }
  242. if (settings.add) {
  243. $(settings.add + ':not(.nodequeue-processed)')
  244. .addClass('nodequeue-processed')
  245. .click(function() { return false; })
  246. .click(function(e) {
  247. var input = this;
  248. $(input).attr('disabled', true);
  249. $(input).parent().addClass('throbbing');
  250. var data = { position: maxPosition + 1 };
  251. for (i in settings.post) {
  252. data[$(settings.post[i]).attr('name')] = $(settings.post[i]).val();
  253. }
  254. $.ajax({
  255. type: 'POST',
  256. data: data,
  257. url: settings.path,
  258. global: true,
  259. success: function (data) {
  260. // Parse response
  261. $(input).parent().removeClass('throbbing');
  262. $(input).attr('disabled', false);
  263. data = Drupal.parseJson(data);
  264. if (data.status) {
  265. // add new data
  266. var new_content = $(data.data);
  267. Drupal.freezeHeight();
  268. // Hide the new content before adding to page.
  269. maxPosition++;
  270. // Add the form and re-attach behavior.
  271. if (settings.add_location != 'top') {
  272. $('#' + base + ' tbody').append(new_content);
  273. changeOrder(maxPosition, 'add');
  274. }
  275. else {
  276. $('#' + base + ' tbody').prepend(new_content);
  277. changeOrder(maxPosition, 'insert');
  278. }
  279. changed(new_content);
  280. bindButtons();
  281. Drupal.unfreezeHeight();
  282. // Add the extra data, if necessary
  283. if (data.extra && settings.extra) {
  284. var val = $(settings.extra).val();
  285. if (val) {
  286. val += ',';
  287. }
  288. val += data.extra;
  289. $(settings.extra).val(val);
  290. }
  291. if (settings.clear) {
  292. for (i in settings.clear) {
  293. $(settings.clear[i]).val('');
  294. }
  295. }
  296. return;
  297. }
  298. else {
  299. // report the error
  300. alert(data.error, 'Error');
  301. }
  302. },
  303. error: function(data) {
  304. alert(Drupal.t('An error occurred'));
  305. $(input).parent().removeClass('throbbing');
  306. $(input).attr('disabled', false);
  307. }
  308. });
  309. return false;
  310. });
  311. }
  312. }
  313. // Focus if we're told to.
  314. if (settings.focus) {
  315. $(settings.focus).get(0).focus();
  316. }
  317. this.bindButtons = bindButtons();
  318. }
  319. Drupal.nodequeue.autoAttach = function() {
  320. if (Drupal.settings && Drupal.settings.nodequeue) {
  321. for (var base in Drupal.settings.nodequeue) {
  322. if (!$('#'+ base + '.nodequeue-processed').size()) {
  323. var settings = Drupal.settings.nodequeue[base];
  324. var list = new Drupal.nodequeue(base, settings);
  325. $('#'+ base).addClass('nodequeue-processed');
  326. }
  327. }
  328. }
  329. $('a.nodequeue-ajax-toggle').click(function() {
  330. var a = this;
  331. href = $(this).attr('href');
  332. $(a).addClass('throbbing');
  333. $.ajax({
  334. type: 'POST',
  335. data: { js: 1 },
  336. url: href,
  337. global: true,
  338. dataType: 'json',
  339. success: function (data) {
  340. // Parse response
  341. $(a).removeClass('throbbing');
  342. // Change text on success
  343. if (data.status) {
  344. // Change label back
  345. $(a).attr('href', data.href);
  346. $(a).html(data.label);
  347. if (data.sqid) {
  348. $('#nodequeue-count-' + data.sqid).html(data.count);
  349. }
  350. if (data.href.search('remove-node') > -1) {
  351. $(a).removeClass('toggle-add');
  352. $(a).addClass('toggle-remove');
  353. }
  354. else {
  355. $(a).removeClass('toggle-remove');
  356. $(a).addClass('toggle-add');
  357. }
  358. return;
  359. }
  360. },
  361. error: function(data) {
  362. $(a).removeClass('throbbing');
  363. }
  364. });
  365. return false;
  366. });
  367. }
  368. if (Drupal.jsEnabled) {
  369. $(document).ready(Drupal.nodequeue.autoAttach);
  370. }