Changeset View
Standalone View
webroot/rsrc/js/application/projects/WorkboardBoard.js
Show First 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | compareVectors: function(u_vec, v_vec) { | ||||
} | } | ||||
return 0; | return 0; | ||||
}, | }, | ||||
start: function() { | start: function() { | ||||
this._setupDragHandlers(); | this._setupDragHandlers(); | ||||
// TODO: This is temporary code to make it easier to debug this workflow | |||||
// by pressing the "R" key. | |||||
var on_reload = JX.bind(this, this._reloadCards); | |||||
new JX.KeyboardShortcut('R', 'Reload Card State (Prototype)') | |||||
.setHandler(on_reload) | |||||
.register(); | |||||
amckinley: We're definitely going to get rid of this, right? https://xkcd.com/1172/ | |||||
for (var k in this._columns) { | for (var k in this._columns) { | ||||
this._columns[k].redraw(); | this._columns[k].redraw(); | ||||
} | } | ||||
}, | }, | ||||
_buildColumns: function() { | _buildColumns: function() { | ||||
var nodes = JX.DOM.scry(this.getRoot(), 'ul', 'project-column'); | var nodes = JX.DOM.scry(this.getRoot(), 'ul', 'project-column'); | ||||
▲ Show 20 Lines • Show All 406 Lines • ▼ Show 20 Lines | _revertCard: function(list, item, src_phid, dst_phid) { | ||||
src_column.markForRedraw(); | src_column.markForRedraw(); | ||||
dst_column.markForRedraw(); | dst_column.markForRedraw(); | ||||
this._redrawColumns(); | this._redrawColumns(); | ||||
list.unlock(); | list.unlock(); | ||||
}, | }, | ||||
_oncardupdate: function(list, src_phid, dst_phid, after_phid, response) { | _oncardupdate: function(list, src_phid, dst_phid, after_phid, response) { | ||||
var src_column = this.getColumn(src_phid); | |||||
var dst_column = this.getColumn(dst_phid); | |||||
var card = src_column.removeCard(response.objectPHID); | |||||
dst_column.addCard(card, after_phid); | |||||
src_column.markForRedraw(); | |||||
dst_column.markForRedraw(); | |||||
this.updateCard(response); | this.updateCard(response); | ||||
var sounds = response.sounds || []; | var sounds = response.sounds || []; | ||||
for (var ii = 0; ii < sounds.length; ii++) { | for (var ii = 0; ii < sounds.length; ii++) { | ||||
JX.Sound.queue(sounds[ii]); | JX.Sound.queue(sounds[ii]); | ||||
} | } | ||||
list.unlock(); | list.unlock(); | ||||
}, | }, | ||||
updateCard: function(response) { | updateCard: function(response) { | ||||
var columns = this.getColumns(); | var columns = this.getColumns(); | ||||
var column_phid; | |||||
var phid = response.objectPHID; | var card_phid; | ||||
var card_data; | |||||
for (var add_phid in response.columnMaps) { | |||||
var target_column = this.getColumn(add_phid); | // The server may send us a full or partial update for a card. If we've | ||||
// received a full update, we're going to redraw the entire card and may | |||||
// need to change which columns it appears in. | |||||
Not Done Inline ActionsCan any of this interact weirdly with policy? If a card already rendered by my browser becomes not-visible to me, could I engage in silly buggers to disclose information about the now-restricted task? I'm guessing "no" since we're doing viewer checks server-side in PhabricatorProjectBoardReloadController, but stale information on the task will presumably stick around until I reload the page. I can't really call this an attack because at best it just means I can see the state of an object as of the last time I was legitimately able to view it. Actually, won't the hidden card just stick around until I reload the page? If I can't see it, PhabricatorProjectBoardReloadController just won't return it in the reload result set, and it should stay where it is. amckinley: Can any of this interact weirdly with policy? If a card already rendered by my browser becomes… | |||||
Done Inline ActionsIt definitely won't disclose any information, since the Query on the server side won't pull it. You're right that we do end up with a ghosting issue though, see below... epriestley: It definitely won't disclose any information, since the `Query` on the server side won't pull… | |||||
// For a partial update, we've just received supplemental sorting or | |||||
// property information and do not need to perform a full redraw. | |||||
// When we reload card state, edit a card, or move a card, we get a full | |||||
// update for the card. | |||||
// Ween we move a card in a column, we may get a partial update for other | |||||
Not Done Inline ActionsOui oui! amckinley: Oui oui! | |||||
// visible cards in the column. | |||||
// Figure out which columns each card now appears in. For cards that | |||||
// have received a full update, we'll use this map to move them into | |||||
// the correct columns. | |||||
var update_map = {}; | |||||
for (column_phid in response.columnMaps) { | |||||
var target_column = this.getColumn(column_phid); | |||||
if (!target_column) { | if (!target_column) { | ||||
// If the column isn't visible, don't try to add a card to it. | // If the column isn't visible, don't try to add a card to it. | ||||
continue; | continue; | ||||
} | } | ||||
target_column.newCard(phid); | var column_map = response.columnMaps[column_phid]; | ||||
} | |||||
var column_maps = response.columnMaps; | for (var ii = 0; ii < column_map.length; ii++) { | ||||
var natural_column; | card_phid = column_map[ii]; | ||||
for (var natural_phid in column_maps) { | if (!update_map[card_phid]) { | ||||
natural_column = this.getColumn(natural_phid); | update_map[card_phid] = {}; | ||||
if (!natural_column) { | } | ||||
// Our view of the board may be out of date, so we might get back | update_map[card_phid][column_phid] = true; | ||||
// information about columns that aren't visible. Just ignore the | |||||
// position information for any columns we aren't displaying on the | |||||
// client. | |||||
continue; | |||||
} | } | ||||
natural_column.setNaturalOrder(column_maps[natural_phid]); | |||||
} | } | ||||
for (var card_phid in response.cards) { | // Process partial updates for cards. This is supplemental data which | ||||
var card_data = response.cards[card_phid]; | // we can just merge in without any special handling. | ||||
for (card_phid in response.cards) { | |||||
card_data = response.cards[card_phid]; | |||||
var card_template = this.getCardTemplate(card_phid); | var card_template = this.getCardTemplate(card_phid); | ||||
if (card_data.nodeHTMLTemplate) { | if (card_data.nodeHTMLTemplate) { | ||||
card_template.setNodeHTMLTemplate(card_data.nodeHTMLTemplate); | card_template.setNodeHTMLTemplate(card_data.nodeHTMLTemplate); | ||||
} | } | ||||
var order; | var order; | ||||
for (order in card_data.vectors) { | for (order in card_data.vectors) { | ||||
card_template.setSortVector(order, card_data.vectors[order]); | card_template.setSortVector(order, card_data.vectors[order]); | ||||
} | } | ||||
for (order in card_data.headers) { | for (order in card_data.headers) { | ||||
card_template.setHeaderKey(order, card_data.headers[order]); | card_template.setHeaderKey(order, card_data.headers[order]); | ||||
} | } | ||||
for (var key in card_data.properties) { | for (var key in card_data.properties) { | ||||
card_template.setObjectProperty(key, card_data.properties[key]); | card_template.setObjectProperty(key, card_data.properties[key]); | ||||
} | } | ||||
} | } | ||||
var headers = response.headers; | |||||
for (var jj = 0; jj < headers.length; jj++) { | |||||
var header = headers[jj]; | |||||
this.getHeaderTemplate(header.key) | // Process full updates for cards which we have a full update for. This | ||||
.setOrder(header.order) | // may involve moving them between columns. | ||||
.setNodeHTMLTemplate(header.template) | for (card_phid in response.cards) { | ||||
.setVector(header.vector) | card_data = response.cards[card_phid]; | ||||
.setEditProperties(header.editProperties); | |||||
if (!card_data.update) { | |||||
continue; | |||||
} | } | ||||
for (var column_phid in columns) { | for (column_phid in columns) { | ||||
var column = columns[column_phid]; | var column = columns[column_phid]; | ||||
var card = column.getCard(card_phid); | |||||
var cards = column.getCards(); | if (card) { | ||||
for (var object_phid in cards) { | card.redraw(); | ||||
if (object_phid !== phid) { | column.markForRedraw(); | ||||
continue; | |||||
} | } | ||||
var card = cards[object_phid]; | // Compare the server state to the client state, and add or remove | ||||
card.redraw(); | // cards on the client as necessary to synchronize them. | ||||
if (update_map[card_phid][column_phid]) { | |||||
if (!card) { | |||||
column.newCard(card_phid); | |||||
column.markForRedraw(); | |||||
} | |||||
} else { | |||||
if (card) { | |||||
column.removeCard(card_phid); | |||||
Not Done Inline ActionsOh, re: my above, this will presumably remove cards from the UI if they weren't present in the result set. amckinley: Oh, re: my above, this will presumably remove cards from the UI if they weren't present in the… | |||||
Done Inline ActionsWe don't actually make it here since we're iterating over card_phid in response.cards, which no longer includes the deleted/hidden card! I'll tweak things here to check both all the cards the client knows about and the cards the server gave us information about. This also has a slightly tricky interaction with edit flows if you move the card off the board by changing projects, or by dropping it into a column which kicks it off the board (which is silly, but I think currently allowed). epriestley: We don't actually make it here since we're iterating over `card_phid in response.cards`, which… | |||||
column.markForRedraw(); | column.markForRedraw(); | ||||
} | } | ||||
} | } | ||||
} | |||||
} | |||||
var column_maps = response.columnMaps; | |||||
var natural_column; | |||||
for (var natural_phid in column_maps) { | |||||
natural_column = this.getColumn(natural_phid); | |||||
if (!natural_column) { | |||||
// Our view of the board may be out of date, so we might get back | |||||
// information about columns that aren't visible. Just ignore the | |||||
// position information for any columns we aren't displaying on the | |||||
// client. | |||||
continue; | |||||
} | |||||
natural_column.setNaturalOrder(column_maps[natural_phid]); | |||||
} | |||||
var headers = response.headers; | |||||
for (var jj = 0; jj < headers.length; jj++) { | |||||
var header = headers[jj]; | |||||
this.getHeaderTemplate(header.key) | |||||
.setOrder(header.order) | |||||
.setNodeHTMLTemplate(header.template) | |||||
.setVector(header.vector) | |||||
.setEditProperties(header.editProperties); | |||||
} | |||||
this._redrawColumns(); | this._redrawColumns(); | ||||
}, | }, | ||||
_redrawColumns: function() { | _redrawColumns: function() { | ||||
var columns = this.getColumns(); | var columns = this.getColumns(); | ||||
for (var k in columns) { | for (var k in columns) { | ||||
if (columns[k].isMarkedForRedraw()) { | if (columns[k].isMarkedForRedraw()) { | ||||
columns[k].redraw(); | columns[k].redraw(); | ||||
} | } | ||||
} | } | ||||
}, | |||||
_reloadCards: function() { | |||||
var data = {}; | |||||
var on_reload = JX.bind(this, this._onReloadResponse); | |||||
new JX.Request(this.getController().getReloadURI(), on_reload) | |||||
.setData(data) | |||||
.send(); | |||||
}, | |||||
_onReloadResponse: function(response) { | |||||
this.updateCard(response); | |||||
} | } | ||||
} | } | ||||
}); | }); |
We're definitely going to get rid of this, right? https://xkcd.com/1172/