PageRenderTime 47ms CodeModel.GetById 18ms RepoModel.GetById 1ms app.codeStats 0ms

/auiplugin/src/main/resources/experimental/js/atlassian/restfultable/restfultable.js

https://bitbucket.org/puxlit/aui-archive
JavaScript | 857 lines | 520 code | 138 blank | 199 comment | 54 complexity | 708898920c90ce5110e4755f85585788 MD5 | raw file
  1. (function ($) {
  2. /**
  3. * A table who's entries/rows are can be retrieved, added and updated via rest (CRUD).
  4. * It uses backbone.js to sync the tables state back to the server and vice versa, avoiding page refreshes.
  5. *
  6. * @class RestfulTable
  7. */
  8. AJS.RestfulTable = Backbone.View.extend({
  9. /**
  10. * @constructor
  11. * @param {Object} options
  12. * ... {String} id - The id for the table. This id will be used to fire events specific to this instance.
  13. * ... {boolean} editable - Is the table editable. If true, clicking row will switch it to edit state.
  14. * ... {boolean} createDisabled - Can new entries be added to the table.
  15. * ... {boolean} reorderable - Can we drag rows to reorder them.
  16. * ... {String} noEntriesMsg - Message that will be displayed under the table header if it is empty.
  17. * ... {Array} entries - initial data set to be rendered. Each item in the array will be used to create a new instance of options.model.
  18. * ... {AJS.RestfulTable.EntryModel} model - backbone model representing a row.
  19. * ... {Object} views
  20. * ... ... {AJS.RestfulTable.EditRow} editRow - Backbone view that renders the edit & create row. Your view MUST extend AJS.RestfulTable.EditRow.
  21. * ... ... {AJS.RestfulTable.Row} row - Backbone view that renders the readonly row. Your view MUST extend AJS.RestfulTable.Row.
  22. */
  23. initialize: function (options) {
  24. var instance = this;
  25. // combine default and user options
  26. instance.options = $.extend(true, instance._getDefaultOptions(options), options);
  27. // Prefix events for this instance with this id.
  28. instance.id = this.options.id;
  29. // faster lookup
  30. instance._events = AJS.RestfulTable.Events;
  31. instance.classNames = AJS.RestfulTable.ClassNames;
  32. instance.dataKeys = AJS.RestfulTable.DataKeys;
  33. // shortcuts to popular elements
  34. this.$table = $(options.el)
  35. .addClass(this.classNames.RESTFUL_TABLE)
  36. .addClass(this.classNames.ALLOW_HOVER)
  37. .addClass("aui")
  38. .addClass(instance.classNames.LOADING);
  39. this.$table.wrapAll("<form class='aui' action='#' />");
  40. this.$thead = $("<thead/>");
  41. this.$theadRow = $("<tr />").appendTo(this.$thead);
  42. this.$tbody = $("<tbody/>");
  43. if (!this.options.columns) {
  44. throw new Error("AJS.RestfulTable: Init failed! You haven't provided any columns to render.")
  45. }
  46. // Let user know the table is loading
  47. this.showGlobalLoading();
  48. $.each(this.options.columns, function (i, column) {
  49. var header = $.isFunction(column.header) ? column.header() : column.header;
  50. if (typeof header === "undefined") {
  51. console.warn("You have not specified [header] for column [" + column.id + "]. Using id for now...");
  52. header = column.id;
  53. }
  54. instance.$theadRow.append("<th>" + header + "</th>");
  55. });
  56. // columns for submit buttons and loading indicator used when editing
  57. instance.$theadRow.append("<th></th><th></th>");
  58. // create a new Backbone collection to represent rows (http://documentcloud.github.com/backbone/#Collection)
  59. this._models = new this.options.Collection([], {
  60. comparator: function (row) { // sort models in colleciton based on dom ordering
  61. var index;
  62. $.each(instance.getRows(), function (i) {
  63. if (this.model.id === row.id) {
  64. index = i;
  65. return false;
  66. }
  67. });
  68. return index;
  69. }
  70. });
  71. // shortcut to the class we use to create rows
  72. this._rowClass = this.options.views.row;
  73. if (this.options.editable !== false) {
  74. this.editRows = []; // keep track of rows that are being edited concurrently
  75. if (!this.options.createDisabled) {
  76. // Create row responsible for adding new entries ...
  77. this._createRow = new this.options.views.editRow({
  78. columns: this.options.columns,
  79. model: this.options.model.extend({
  80. url: function () {
  81. return instance.options.resources.self;
  82. }
  83. }),
  84. cancelAccessKey: this.options.cancelAccessKey,
  85. submitAccessKey: this.options.submitAccessKey,
  86. reorderable: this.options.reorderable
  87. })
  88. .bind(this._events.CREATED, function (values) {
  89. instance.addRow(values, 0);
  90. })
  91. .bind(this._events.VALIDATION_ERROR, function () {
  92. this.trigger(instance._events.FOCUS);
  93. })
  94. .render({
  95. errors: {},
  96. values: {}
  97. });
  98. // ... and appends it as the first row
  99. this.$create = $('<tbody class="' + this.classNames.CREATE + '" />')
  100. .append(this._createRow.el);
  101. // Manage which row has focus
  102. this._applyFocusCoordinator(this._createRow);
  103. // focus create row
  104. this._createRow.trigger(this._events.FOCUS);
  105. }
  106. this.$table.closest("form").submit(function (e) {
  107. if (instance.focusedRow) {
  108. // Delegates saving of row. See AJS.RestfulTable.EditRow.submit
  109. instance.focusedRow.trigger(instance._events.SAVE);
  110. }
  111. e.preventDefault();
  112. });
  113. if (this.options.reorderable) {
  114. // Add allowance for another cell to the thead
  115. this.$theadRow.prepend("<th />")
  116. // Allow drag and drop reordering of rows
  117. this.$tbody.sortable({
  118. handle: "." +this.classNames.DRAG_HANDLE,
  119. start: function (event, ui) {
  120. var $this = instance._createRow.$el.find("td");
  121. // Make sure that when we start dragging widths do not change
  122. ui.item
  123. .addClass(instance.classNames.MOVEABLE)
  124. .children().each(function (i) {
  125. $(this).width($this.eq(i).width());
  126. });
  127. // Add a <td> to the placeholder <tr> to inherit CSS styles.
  128. ui.placeholder
  129. .html('<td colspan="' + instance.getColumnCount() + '">&nbsp;</td>')
  130. .css("visibility", "visible");
  131. // Stop hover effects etc from occuring as we move the mouse (while dragging) over other rows
  132. instance.getRowFromElement(ui.item[0]).trigger(instance._events.MODAL);
  133. },
  134. stop: function (event, ui) {
  135. ui.item
  136. .removeClass(instance.classNames.MOVEABLE)
  137. .children().attr("style", "");
  138. ui.placeholder.removeClass(instance.classNames.ROW);
  139. // Return table to a normal state
  140. instance.getRowFromElement(ui.item[0]).trigger(instance._events.MODELESS);
  141. },
  142. update: function (event, ui) {
  143. var nextModel,
  144. nextRow,
  145. data = {},
  146. row = instance.getRowFromElement(ui.item[0])
  147. if (row) {
  148. nextRow = ui.item.next()[0];
  149. if (nextRow) {
  150. nextModel = instance.getRowFromElement(nextRow).model;
  151. // Get the url of the for the entry befores rest endpoint.
  152. // The server will use this to determine position.
  153. data.after = nextModel.url();
  154. } else {
  155. data.position = "First";
  156. }
  157. $.ajax({
  158. url: row.model.url() + "/move",
  159. type: "POST",
  160. dataType: "json",
  161. contentType: "application/json",
  162. data: JSON.stringify(data),
  163. complete: function () {
  164. // hides loading indicator (spinner)
  165. row.hideLoading();
  166. },
  167. success: function (xhr) {
  168. AJS.triggerEvtForInst(instance._events.REORDER_SUCCESS, instance, [xhr]);
  169. },
  170. error: function (xhr) {
  171. var responseData = $.parseJSON(xhr.responseText || xhr.data);
  172. AJS.triggerEvtForInst(instance._events.SERVER_ERROR, instance, [responseData, xhr]);
  173. }
  174. });
  175. // shows loading indicator (spinner)
  176. row.showLoading();
  177. }
  178. },
  179. axis: "y",
  180. delay: 0,
  181. containment: "document",
  182. cursor: "move",
  183. scroll: true,
  184. zIndex: 8000
  185. });
  186. // Prevent text selection while reordering.
  187. this.$tbody.bind("selectstart mousedown", function (event) {
  188. return !$(event.target).is("." + instance.classNames.DRAG_HANDLE);
  189. });
  190. }
  191. }
  192. // when a model is removed from the collection, remove it from the viewport also
  193. this._models.bind("remove", function (model) {
  194. $.each(instance.getRows(), function (i, row) {
  195. if (row.model === model) {
  196. if (row.hasFocus() && instance._createRow) {
  197. instance._createRow.trigger(instance._events.FOCUS);
  198. }
  199. instance.removeRow(row);
  200. }
  201. });
  202. });
  203. if ($.isFunction(this.options.resources.all)) {
  204. this.options.resources.all(function (entries) {
  205. instance.populate(entries);
  206. });
  207. } else {
  208. $.get(this.options.resources.all, function (entries) {
  209. instance.populate(entries);
  210. });
  211. }
  212. },
  213. /**
  214. * Refreshes table with entries
  215. *
  216. * @param entries
  217. */
  218. populate: function (entries) {
  219. if (this.options.reverseOrder) {
  220. entries.reverse();
  221. }
  222. this.hideGlobalLoading();
  223. if (entries && entries.length) {
  224. // Empty the models collection
  225. this._models.refresh([], { silent: true });
  226. // Add all the entries to collection and render them
  227. this.renderRows(entries);
  228. // show message to user if we have no entries
  229. if (this.isEmpty()) {
  230. this.showNoEntriesMsg();
  231. }
  232. } else {
  233. this.showNoEntriesMsg();
  234. }
  235. // Ok, lets let everyone know that we are done...
  236. this.$table
  237. .append(this.$thead)
  238. .append(this.$create)
  239. .append(this.$tbody)
  240. .removeClass(this.classNames.LOADING)
  241. .trigger(this._events.INITIALIZED, [this]);
  242. AJS.triggerEvtForInst(this._events.INITIALIZED, this, [this]);
  243. if (this.options.autoFocus) {
  244. this.$table.find(":input:text:first").focus(); // set focus to first field
  245. }
  246. },
  247. /**
  248. * Shows loading indicator and text
  249. *
  250. * @return {AJS.RestfulTable}
  251. */
  252. showGlobalLoading: function () {
  253. if (!this.$loading) {
  254. this.$loading = $('<div class="aui-restfultable-init"><span class="aui-restfultable-throbber">' +
  255. '</span><span class="aui-restfultable-loading">' + this.options.loadingMsg + '</span></div>');
  256. }
  257. if (!this.$loading.is(":visible")) {
  258. this.$loading.insertAfter(this.$table);
  259. }
  260. return this
  261. },
  262. /**
  263. * Hides loading indicator and text
  264. * @return {AJS.RestfulTable}
  265. */
  266. hideGlobalLoading: function () {
  267. if (this.$loading) {
  268. this.$loading.remove();
  269. }
  270. return this;
  271. },
  272. /**
  273. * Adds row to collection and renders it
  274. *
  275. * @param {Object} values
  276. * @param {number} index
  277. * @return {AJS.RestfulTable}
  278. */
  279. addRow: function (values, index) {
  280. var view,
  281. model;
  282. if (!values.id) {
  283. throw new Error("AJS.RestfulTable.addRow: to add a row values object must contain an id. "
  284. + "Maybe you are not returning it from your restend point?"
  285. + "Recieved:" + JSON.stringify(values));
  286. }
  287. model = new this.options.model(values);
  288. view = this._renderRow(model, index);
  289. this._models.add(model);
  290. this.removeNoEntriesMsg();
  291. // Let everyone know we added a row
  292. AJS.triggerEvtForInst(this._events.ROW_ADDED, this, [view, this]);
  293. return this;
  294. },
  295. /**
  296. * Provided a view, removes it from display and backbone collection
  297. *
  298. * @param {AJS.RestfulTable.Row}
  299. */
  300. removeRow: function (row) {
  301. this._models.remove(row.model);
  302. row.remove();
  303. if (this.isEmpty()) {
  304. this.showNoEntriesMsg();
  305. }
  306. // Let everyone know we removed a row
  307. AJS.triggerEvtForInst(this._events.ROW_REMOVED, this, [row, this]);
  308. },
  309. /**
  310. * Is there any entries in the table
  311. *
  312. * @return {Boolean}
  313. */
  314. isEmpty: function () {
  315. return this._models.length === 0;
  316. },
  317. /**
  318. * Gets all models
  319. *
  320. * @return {Backbone.Collection}
  321. */
  322. getModels: function () {
  323. return this._models;
  324. },
  325. /**
  326. * Gets table body
  327. *
  328. * @return {jQuery}
  329. */
  330. getTable: function () {
  331. return this.$table;
  332. },
  333. /**
  334. * Gets table body
  335. *
  336. * @return {jQuery}
  337. */
  338. getTableBody: function () {
  339. return this.$tbody;
  340. },
  341. /**
  342. * Gets create Row
  343. *
  344. * @return {B
  345. */
  346. getCreateRow: function () {
  347. return this._createRow;
  348. },
  349. /**
  350. * Gets the number of table colums
  351. *
  352. * @return {Number}
  353. */
  354. getColumnCount: function () {
  355. return this.options.columns.length + 2; // plus 2 accounts for the columns allocated to submit buttons and loading indicator
  356. },
  357. /**
  358. * Get the AJS.RestfulTable.Row that corresponds to the given <tr> element.
  359. *
  360. * @param {HTMLElement} tr
  361. * @return {?AJS.RestfulTable.Row}
  362. */
  363. getRowFromElement: function (tr) {
  364. return $(tr).data(this.dataKeys.ROW_VIEW);
  365. },
  366. /**
  367. * Shows message {options.noEntriesMsg} to the user if there are no entries
  368. *
  369. * @return {AJS.RestfulTable}
  370. */
  371. showNoEntriesMsg: function () {
  372. if (this.$noEntries) {
  373. this.$noEntries.remove();
  374. }
  375. this.$noEntries = $("<tr>")
  376. .addClass(this.classNames.NO_ENTRIES)
  377. .append($("<td>")
  378. .attr("colspan", this.getColumnCount())
  379. .text(this.options.noEntriesMsg)
  380. )
  381. .appendTo(this.$tbody);
  382. return this;
  383. },
  384. /**
  385. * Removes message {options.noEntriesMsg} to the user if there ARE entries
  386. *
  387. * @return {AJS.RestfulTable}
  388. */
  389. removeNoEntriesMsg: function () {
  390. if (this.$noEntries && this._models.length > 0) {
  391. this.$noEntries.remove();
  392. }
  393. return this;
  394. },
  395. /**
  396. * Gets the AJS.RestfulTable.Row from their associated <tr> elements
  397. *
  398. * @return {Array<AJS.RestfulTable.Row>}
  399. */
  400. getRows: function () {
  401. var instance = this,
  402. views = [];
  403. this.$tbody.find("." + this.classNames.READ_ONLY).each(function () {
  404. var $row = $(this),
  405. view = $row.data(instance.dataKeys.ROW_VIEW);
  406. if (view) {
  407. views.push(view);
  408. }
  409. });
  410. return views;
  411. },
  412. /**
  413. * Appends entry to end or specified index of table
  414. *
  415. * @param {AJS.RestfulTable.EntryModel} model
  416. * @param index
  417. * @return {jQuery}
  418. */
  419. _renderRow: function (model, index) {
  420. var instance = this,
  421. $rows = this.$tbody.find("." + this.classNames.READ_ONLY),
  422. $row,
  423. view;
  424. view = new this._rowClass({
  425. model: model,
  426. columns: this.options.columns,
  427. reorderable: this.options.reorderable
  428. });
  429. this.removeNoEntriesMsg();
  430. view.bind(this._events.EDIT_ROW, function (field) {
  431. instance.edit(this, field);
  432. });
  433. $row = view.render().$el;
  434. if (index !== -1) {
  435. if (typeof index === "number" && $rows.length !== 0) {
  436. $row.insertBefore($rows[index]);
  437. } else {
  438. this.$tbody.append($row);
  439. }
  440. }
  441. $row.data(this.dataKeys.ROW_VIEW, view);
  442. // deactivate all rows - used in the cases, such as opening a dropdown where you do not want the table editable
  443. // or any interactions
  444. view.bind(this._events.MODAL, function () {
  445. instance.$table.removeClass(instance.classNames.ALLOW_HOVER);
  446. instance.$tbody.sortable("disable");
  447. $.each(instance.getRows(), function () {
  448. if (!instance.isRowBeingEdited(this)) {
  449. this.delegateEvents({}); // clear all events
  450. }
  451. });
  452. });
  453. view.bind(this._events.ANIMATION_STARTED, function () {
  454. instance.$table.removeClass(instance.classNames.ALLOW_HOVER);
  455. });
  456. view.bind(this._events.ANIMATION_FINISHED, function () {
  457. instance.$table.addClass(instance.classNames.ALLOW_HOVER);
  458. });
  459. // activate all rows - used in the cases, such as opening a dropdown where you do not want the table editable
  460. // or any interactions
  461. view.bind(this._events.MODELESS, function () {
  462. instance.$table.addClass(instance.classNames.ALLOW_HOVER);
  463. instance.$tbody.sortable("enable");
  464. $.each(instance.getRows(), function () {
  465. if (!instance.isRowBeingEdited(this)) {
  466. this.delegateEvents(); // rebind all events
  467. }
  468. });
  469. });
  470. // ensure that when this row is focused no other are
  471. this._applyFocusCoordinator(view);
  472. this.trigger(this._events.ROW_INITIALIZED, view);
  473. return view;
  474. },
  475. /**
  476. * Returns if the row is edit mode or note
  477. *
  478. * @param {AJS.RestfulTable.Row} - read onyl row to check if being edited
  479. * @return {Boolean}
  480. */
  481. isRowBeingEdited: function (row) {
  482. var isBeingEdited = false;
  483. $.each(this.editRows, function () {
  484. if (this.el === row.el) {
  485. isBeingEdited = true;
  486. return false;
  487. }
  488. });
  489. return isBeingEdited;
  490. },
  491. /**
  492. * Ensures that when supplied view is focused no others are
  493. *
  494. * @param {Backbone.View} view
  495. * @return {AJS.RestfulTable}
  496. */
  497. _applyFocusCoordinator: function (view) {
  498. var instance = this;
  499. if (!view.hasFocusBound) {
  500. view.hasFocusBound = true;
  501. view.bind(this._events.FOCUS, function () {
  502. if (instance.focusedRow && instance.focusedRow !== view) {
  503. instance.focusedRow.trigger(instance._events.BLUR);
  504. }
  505. instance.focusedRow = view;
  506. if (view instanceof AJS.RestfulTable.Row && instance._createRow) {
  507. instance._createRow.enable();
  508. }
  509. });
  510. }
  511. return this;
  512. },
  513. /**
  514. * Remove specificed row from collection holding rows being concurrently edited
  515. *
  516. * @param {AJS.RestfulTable.EditRow} editView
  517. * @return {AJS.RestfulTable}
  518. */
  519. _removeEditRow: function (editView) {
  520. var index = $.inArray(editView, this.editRows);
  521. this.editRows.splice(index, 1);
  522. return this;
  523. },
  524. /**
  525. * Focuses last row still being edited or create row (if it exists)
  526. *
  527. * @return {AJS.RestfulTable}
  528. */
  529. _shiftFocusAfterEdit: function () {
  530. if (this.editRows.length > 0) {
  531. this.editRows[this.editRows.length-1].trigger(this._events.FOCUS);
  532. } else if (this._createRow) {
  533. this._createRow.trigger(this._events.FOCUS);
  534. }
  535. return this;
  536. },
  537. /**
  538. * Evaluate if we save row when we blur. We can only do this when there is one row being edited at a time, otherwise
  539. * it causes an infinate loop JRADEV-5325
  540. *
  541. * @return {boolean}
  542. */
  543. _saveEditRowOnBlur: function () {
  544. return this.editRows.length <= 1;
  545. },
  546. /**
  547. * Dismisses rows being edited concurrently that have no changes
  548. */
  549. dismissEditRows: function () {
  550. var instance = this;
  551. $.each(this.editRows, function () {
  552. if (!this.hasUpdates()) {
  553. this.trigger(instance._events.FINISHED_EDITING);
  554. }
  555. });
  556. },
  557. /**
  558. * Converts readonly row to editable view
  559. *
  560. * @param {Backbone.View} row
  561. * @param {String} field - field name to focus
  562. * @return {Backbone.View} editRow
  563. */
  564. edit: function (row, field) {
  565. var instance = this,
  566. editRow = new this.options.views.editRow({
  567. el: row.el,
  568. columns: this.options.columns,
  569. isUpdateMode: true,
  570. reorderable: this.options.reorderable,
  571. model: row.model,
  572. cancelAccessKey: this.options.cancelAccessKey,
  573. submitAccessKey: this.options.submitAccessKey
  574. }),
  575. values = row.model.toJSON();
  576. values.update = true;
  577. editRow.render({
  578. errors: {},
  579. update: true,
  580. values: values
  581. })
  582. .bind(instance._events.UPDATED, function (model, focusUpdated) {
  583. instance._removeEditRow (this);
  584. this.unbind();
  585. row.render().delegateEvents(); // render and rebind events
  586. row.trigger(instance._events.UPDATED); // trigger blur fade out
  587. if (focusUpdated !== false) {
  588. instance._shiftFocusAfterEdit();
  589. }
  590. })
  591. .bind(instance._events.VALIDATION_ERROR, function () {
  592. this.trigger(instance._events.FOCUS);
  593. })
  594. .bind(instance._events.FINISHED_EDITING, function () {
  595. instance._removeEditRow(this);
  596. row.render().delegateEvents();
  597. this.unbind(); // avoid any other updating, blurring, finished editing, cancel events being fired
  598. })
  599. .bind(instance._events.CANCEL, function () {
  600. instance._removeEditRow(this);
  601. this.unbind(); // avoid any other updating, blurring, finished editing, cancel events being fired
  602. row.render().delegateEvents(); // render and rebind events
  603. instance._shiftFocusAfterEdit();
  604. })
  605. .bind(instance._events.BLUR, function () {
  606. instance.dismissEditRows(); // dismiss edit rows that have no changes
  607. if (instance._saveEditRowOnBlur()) {
  608. this.trigger(instance._events.SAVE, false); // save row, which if successful will call the updated event above
  609. }
  610. });
  611. // Ensure that if focus is pulled to another row, we blur the edit row
  612. this._applyFocusCoordinator(editRow);
  613. // focus edit row, which has the flow on effect of blurring current focused row
  614. editRow.trigger(instance._events.FOCUS, field);
  615. // disables form fields
  616. if (instance._createRow) {
  617. instance._createRow.disable();
  618. }
  619. this.editRows.push(editRow);
  620. return editRow;
  621. },
  622. /**
  623. * Renders all specified rows
  624. *
  625. * @param {Array} array of objects describing Backbone.Model's to render
  626. * @return {AJS.RestfulTable}
  627. */
  628. renderRows: function (rows) {
  629. var model,
  630. $els = $();
  631. // Insert prepopulated entries
  632. for (var i = 0; i < rows.length; i++) {
  633. model = new this.options.model(rows[i]);
  634. $els = $els.add(this._renderRow(model, -1).el);
  635. this._models.add(model)
  636. }
  637. this.removeNoEntriesMsg();
  638. this.$tbody.append($els);
  639. return this;
  640. },
  641. /**
  642. * Gets default options
  643. *
  644. * @param {Object} options
  645. */
  646. _getDefaultOptions: function (options) {
  647. return {
  648. model: options.model || AJS.RestfulTable.EntryModel,
  649. views: {
  650. editRow: AJS.RestfulTable.EditRow,
  651. row: AJS.RestfulTable.Row
  652. },
  653. Collection: Backbone.Collection.extend({
  654. url: options.resources.self,
  655. model: options.model || AJS.RestfulTable.EntryModel
  656. }),
  657. reorderable: false,
  658. loadingMsg: options.loadingMsg || AJS.I18n.getText("aui.words.loading")
  659. }
  660. }
  661. });
  662. // jQuery data keys (http://api.jquery.com/jQuery.data/)
  663. AJS.RestfulTable.DataKeys = {
  664. ENABLED_SUBMIT: "enabledSubmit",
  665. ROW_VIEW: "RestfulTable_Row_View"
  666. };
  667. // CSS style classes. DON'T hard code
  668. AJS.RestfulTable.ClassNames = {
  669. NO_VALUE: "aui-restfultable-editable-no-value",
  670. NO_ENTRIES: "aui-restfultable-no-entires",
  671. RESTFUL_TABLE: "aui-restfultable",
  672. ROW: "aui-restfultable-row",
  673. READ_ONLY: "aui-restfultable-readonly",
  674. ACTIVE: "aui-restfultable-active",
  675. ALLOW_HOVER: "aui-restfultable-allowhover",
  676. FOCUSED: "aui-restfultable-focused",
  677. MOVEABLE: "aui-restfultable-movable",
  678. ANIMATING: "aui-restfultable-animate",
  679. DISABLED: "aui-resfultable-disabled",
  680. SUBMIT: "aui-restfultable-submit",
  681. EDIT_ROW: "aui-restfultable-editrow",
  682. CREATE: "aui-restfultable-create",
  683. DRAG_HANDLE: "aui-restfultable-draghandle",
  684. ORDER: "aui-restfultable-order",
  685. EDITABLE: "aui-restfultable-editable",
  686. ERROR: "error",
  687. DELETE: "aui-resfultable-delete",
  688. LOADING: "loading"
  689. };
  690. // Custom events
  691. AJS.RestfulTable.Events = {
  692. // AJS events
  693. REORDER_SUCCESS: "RestfulTable.reorderSuccess",
  694. ROW_ADDED: "RestfulTable.rowAdded",
  695. ROW_REMOVED: "RestfulTable.rowRemoved",
  696. EDIT_ROW: "RestfulTable.switchedToEditMode",
  697. SERVER_ERROR: "RestfulTable.serverError",
  698. // backbone events
  699. CREATED: "created",
  700. UPDATED: "updated",
  701. FOCUS: "focus",
  702. BLUR: "blur",
  703. SUBMIT: "submit",
  704. SAVE: "save",
  705. MODAL: "modal",
  706. MODELESS: "modeless",
  707. CANCEL: "cancel",
  708. CONTENT_REFRESHED: "contentRefreshed",
  709. RENDER: "render",
  710. FINISHED_EDITING: "finishedEditing",
  711. VALIDATION_ERROR: "validationError",
  712. SUBMIT_STARTED: "submitStarted",
  713. SUBMIT_FINISHED: "submitFinished",
  714. ANIMATION_STARTED: "animationStarted",
  715. ANIMATION_FINISHED: "animationFinisehd",
  716. INITIALIZED: "initialized",
  717. ROW_INITIALIZED: "rowInitialized"
  718. };
  719. })(AJS.$);