@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.)
hq.recaptime.dev/wiki/Phorge
phorge
phabricator
1/**
2 * @requires javelin-install
3 * javelin-stratcom
4 * javelin-dom
5 * javelin-util
6 * @provides multirow-row-manager
7 *
8 * @javelin-installs JX.MultirowRowManager
9 *
10 * @javelin
11 */
12
13
14/**
15 * Give a MultirowRowManager a table DOM elem to manage.
16 * You can add rows, and provide a given ID if you like.
17 * You can update rows by ID.
18 * Rows are automatically equipped with a removal button.
19 * You can listen to the 'row-removed' event on the Manager to get
20 * notifications of these row removals, with the DOM id of the removed
21 * row as event data.
22 */
23JX.install('MultirowRowManager', {
24 /**
25 * @param DOM element <table> root Container for rows
26 */
27 construct : function(root, minRows) {
28 this._root = root;
29 this._rows = [];
30
31 if (typeof minRows !== 'undefined') {
32 this._minRows = minRows;
33 } else {
34 this._minRows = 1;
35 }
36
37 JX.DOM.listen(
38 this._root,
39 'click',
40 JX.MultirowRowManager._removeSigil,
41 JX.bind(this, this._onrowremoved));
42 },
43
44 members : {
45 _count : 0,
46 _nextID : 0,
47 _root : null,
48 _rows : null,
49
50 _generateRowID : function() {
51 return '' + this._nextID++;
52 },
53
54 _wrapRowContents : function(row_id, row_contents) {
55 var row = JX.$N('tr',
56 { sigil : JX.MultirowRowManager.getRowSigil(),
57 meta : { multirow_row_manager_row_id : row_id }
58 },
59 row_contents);
60
61 var removeButton = JX.$N(
62 'td',
63 { className: 'remove-column' },
64 JX.$N(
65 'a',
66 { className: 'button simple',
67 sigil: JX.MultirowRowManager._removeSigil
68 },
69 'Remove'));
70
71 JX.DOM.appendContent(row, removeButton);
72 return row;
73 },
74
75 getRowID : function(row) {
76 return JX.Stratcom.getData(row).multirow_row_manager_row_id;
77 },
78 /**
79 * @param row_contents [DOM elements] New contents of row
80 * @param row_id row ID to update, will throw if this row has been removed
81 */
82 updateRow : function(row_id, row_contents) {
83 if (__DEV__) {
84 if (typeof this._rows[row_id] === 'undefined') {
85 throw new Error('JX.MultirowRowManager.updateRow(row_id, ' +
86 'row_contents): provided row id does not exist.' +
87 ' Use addRow to create a new row and make sure ' +
88 'not to update rows that have been deleted.');
89 }
90 }
91 var old_row = this._rows[row_id];
92 var new_row = this._wrapRowContents(row_id, row_contents);
93 JX.copy(JX.Stratcom.getData(new_row), JX.Stratcom.getData(old_row));
94
95 JX.DOM.replace(old_row, new_row);
96 this._rows[row_id] = new_row;
97
98 this._oncountchanged(); // Fix the new button.
99 return new_row;
100 },
101
102 addRow : function(row_contents) {
103 var row_id = this._generateRowID();
104 var row = this._wrapRowContents(row_id, row_contents);
105 JX.DOM.appendContent(this._root, row);
106
107 this._count++;
108 this._oncountchanged();
109
110 this._rows[row_id] = row;
111 return row;
112 },
113 _onrowremoved : function(e) {
114 if (!JX.Stratcom.getData(e.getTarget()).enabled) {
115 return;
116 }
117 var row = e.getNode(JX.MultirowRowManager.getRowSigil());
118 var row_id = this.getRowID(row);
119 delete this._rows[row_id];
120 JX.DOM.remove(row);
121
122 this._count--;
123 this._oncountchanged();
124 this.invoke('row-removed', row_id);
125 },
126
127 _oncountchanged : function() {
128 var buttons = JX.DOM.scry(
129 this._root,
130 'a',
131 JX.MultirowRowManager._removeSigil);
132
133 var disable = (this._minRows >= 0 && this._count <= this._minRows);
134 for (var i = 0; i < buttons.length; i++) {
135 var button = buttons[i];
136 JX.DOM.alterClass(button, 'disabled', disable);
137 JX.Stratcom.getData(button).enabled = !disable;
138 }
139 }
140 },
141 events : ['row-removed'],
142 statics : {
143 getRowSigil : function() {
144 return 'tools-multirow-row-manager-row';
145 },
146 _removeSigil : 'tools-multirow-row-manager-row-remove'
147 }
148});