mirror of
https://we.phorge.it/source/phorge.git
synced 2025-01-17 10:11:10 +01:00
fc795994f3
Summary: Depends on D20637. Ref T4900. This is some ancient dead code that nothing uses. Test Plan: Grepped for `updateCard()` to verify it's private. Searched for "options" and "dirtyColumn" and got no hits. Reviewers: amckinley Reviewed By: amckinley Maniphest Tasks: T4900 Differential Revision: https://secure.phabricator.com/D20638
667 lines
17 KiB
JavaScript
667 lines
17 KiB
JavaScript
/**
|
|
* @provides javelin-workboard-board
|
|
* @requires javelin-install
|
|
* javelin-dom
|
|
* javelin-util
|
|
* javelin-stratcom
|
|
* javelin-workflow
|
|
* phabricator-draggable-list
|
|
* javelin-workboard-column
|
|
* javelin-workboard-header-template
|
|
* javelin-workboard-card-template
|
|
* javelin-workboard-order-template
|
|
* @javelin
|
|
*/
|
|
|
|
JX.install('WorkboardBoard', {
|
|
|
|
construct: function(controller, phid, root) {
|
|
this._controller = controller;
|
|
this._phid = phid;
|
|
this._root = root;
|
|
|
|
this._headers = {};
|
|
this._cards = {};
|
|
this._orders = {};
|
|
|
|
this._buildColumns();
|
|
},
|
|
|
|
properties: {
|
|
order: null,
|
|
pointsEnabled: false
|
|
},
|
|
|
|
members: {
|
|
_controller: null,
|
|
_phid: null,
|
|
_root: null,
|
|
_columns: null,
|
|
_headers: null,
|
|
_cards: null,
|
|
_dropPreviewNode: null,
|
|
_dropPreviewListNode: null,
|
|
_previewPHID: null,
|
|
_hidePreivew: false,
|
|
_previewPositionVector: null,
|
|
_previewDimState: false,
|
|
|
|
getRoot: function() {
|
|
return this._root;
|
|
},
|
|
|
|
getColumns: function() {
|
|
return this._columns;
|
|
},
|
|
|
|
getColumn: function(k) {
|
|
return this._columns[k];
|
|
},
|
|
|
|
getPHID: function() {
|
|
return this._phid;
|
|
},
|
|
|
|
getCardTemplate: function(phid) {
|
|
if (!this._cards[phid]) {
|
|
this._cards[phid] = new JX.WorkboardCardTemplate(phid);
|
|
}
|
|
|
|
return this._cards[phid];
|
|
},
|
|
|
|
getHeaderTemplate: function(header_key) {
|
|
if (!this._headers[header_key]) {
|
|
this._headers[header_key] = new JX.WorkboardHeaderTemplate(header_key);
|
|
}
|
|
|
|
return this._headers[header_key];
|
|
},
|
|
|
|
getOrderTemplate: function(order_key) {
|
|
if (!this._orders[order_key]) {
|
|
this._orders[order_key] = new JX.WorkboardOrderTemplate(order_key);
|
|
}
|
|
|
|
return this._orders[order_key];
|
|
},
|
|
|
|
getHeaderTemplatesForOrder: function(order) {
|
|
var templates = [];
|
|
|
|
for (var k in this._headers) {
|
|
var header = this._headers[k];
|
|
|
|
if (header.getOrder() !== order) {
|
|
continue;
|
|
}
|
|
|
|
templates.push(header);
|
|
}
|
|
|
|
templates.sort(JX.bind(this, this._sortHeaderTemplates));
|
|
|
|
return templates;
|
|
},
|
|
|
|
_sortHeaderTemplates: function(u, v) {
|
|
return this.compareVectors(u.getVector(), v.getVector());
|
|
},
|
|
|
|
getController: function() {
|
|
return this._controller;
|
|
},
|
|
|
|
compareVectors: function(u_vec, v_vec) {
|
|
for (var ii = 0; ii < u_vec.length; ii++) {
|
|
if (u_vec[ii] > v_vec[ii]) {
|
|
return 1;
|
|
}
|
|
|
|
if (u_vec[ii] < v_vec[ii]) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
},
|
|
|
|
start: function() {
|
|
this._setupDragHandlers();
|
|
|
|
for (var k in this._columns) {
|
|
this._columns[k].redraw();
|
|
}
|
|
},
|
|
|
|
_buildColumns: function() {
|
|
var nodes = JX.DOM.scry(this.getRoot(), 'ul', 'project-column');
|
|
|
|
this._columns = {};
|
|
for (var ii = 0; ii < nodes.length; ii++) {
|
|
var node = nodes[ii];
|
|
var data = JX.Stratcom.getData(node);
|
|
var phid = data.columnPHID;
|
|
|
|
this._columns[phid] = new JX.WorkboardColumn(this, phid, node);
|
|
}
|
|
|
|
var on_over = JX.bind(this, this._showTriggerPreview);
|
|
var on_out = JX.bind(this, this._hideTriggerPreview);
|
|
JX.Stratcom.listen('mouseover', 'trigger-preview', on_over);
|
|
JX.Stratcom.listen('mouseout', 'trigger-preview', on_out);
|
|
|
|
var on_move = JX.bind(this, this._dimPreview);
|
|
JX.Stratcom.listen('mousemove', null, on_move);
|
|
},
|
|
|
|
_dimPreview: function(e) {
|
|
var p = this._previewPositionVector;
|
|
if (!p) {
|
|
return;
|
|
}
|
|
|
|
// When the mouse cursor gets near the drop preview element, fade it
|
|
// out so you can see through it. We can't do this with ":hover" because
|
|
// we disable cursor events.
|
|
|
|
var cursor = JX.$V(e);
|
|
var margin = 64;
|
|
|
|
var near_x = (cursor.x > (p.x - margin));
|
|
var near_y = (cursor.y > (p.y - margin));
|
|
var should_dim = (near_x && near_y);
|
|
|
|
this._setPreviewDimState(should_dim);
|
|
},
|
|
|
|
_setPreviewDimState: function(is_dim) {
|
|
if (is_dim === this._previewDimState) {
|
|
return;
|
|
}
|
|
|
|
this._previewDimState = is_dim;
|
|
var node = this._getDropPreviewNode();
|
|
JX.DOM.alterClass(node, 'workboard-drop-preview-fade', is_dim);
|
|
},
|
|
|
|
_showTriggerPreview: function(e) {
|
|
if (this._disablePreview) {
|
|
return;
|
|
}
|
|
|
|
var target = e.getTarget();
|
|
var node = e.getNode('trigger-preview');
|
|
|
|
if (target !== node) {
|
|
return;
|
|
}
|
|
|
|
var phid = JX.Stratcom.getData(node).columnPHID;
|
|
var column = this._columns[phid];
|
|
|
|
// Bail out if we don't know anything about this column.
|
|
if (!column) {
|
|
return;
|
|
}
|
|
|
|
if (phid === this._previewPHID) {
|
|
return;
|
|
}
|
|
|
|
this._previewPHID = phid;
|
|
|
|
var effects = column.getDropEffects();
|
|
|
|
var triggers = [];
|
|
for (var ii = 0; ii < effects.length; ii++) {
|
|
if (effects[ii].getIsTriggerEffect()) {
|
|
triggers.push(effects[ii]);
|
|
}
|
|
}
|
|
|
|
if (triggers.length) {
|
|
var header = column.getTriggerPreviewEffect();
|
|
triggers = [header].concat(triggers);
|
|
}
|
|
|
|
this._showEffects(triggers);
|
|
},
|
|
|
|
_hideTriggerPreview: function(e) {
|
|
if (this._disablePreview) {
|
|
return;
|
|
}
|
|
|
|
var target = e.getTarget();
|
|
|
|
if (target !== e.getNode('trigger-preview')) {
|
|
return;
|
|
}
|
|
|
|
this._removeTriggerPreview();
|
|
},
|
|
|
|
_removeTriggerPreview: function() {
|
|
this._showEffects([]);
|
|
this._previewPHID = null;
|
|
},
|
|
|
|
_beginDrag: function() {
|
|
this._disablePreview = true;
|
|
this._showEffects([]);
|
|
},
|
|
|
|
_endDrag: function() {
|
|
this._disablePreview = false;
|
|
},
|
|
|
|
_setupDragHandlers: function() {
|
|
var columns = this.getColumns();
|
|
|
|
var order_template = this.getOrderTemplate(this.getOrder());
|
|
var has_headers = order_template.getHasHeaders();
|
|
var can_reorder = order_template.getCanReorder();
|
|
|
|
var lists = [];
|
|
for (var k in columns) {
|
|
var column = columns[k];
|
|
|
|
var list = new JX.DraggableList('draggable-card', column.getRoot())
|
|
.setOuterContainer(this.getRoot())
|
|
.setFindItemsHandler(JX.bind(column, column.getDropTargetNodes))
|
|
.setCanDragX(true)
|
|
.setHasInfiniteHeight(true)
|
|
.setIsDropTargetHandler(JX.bind(column, column.setIsDropTarget));
|
|
|
|
var default_handler = list.getGhostHandler();
|
|
list.setGhostHandler(
|
|
JX.bind(column, column.handleDragGhost, default_handler));
|
|
|
|
// The "compare handler" locks cards into a specific position in the
|
|
// column.
|
|
list.setCompareHandler(JX.bind(column, column.compareHandler));
|
|
|
|
// If the view has group headers, we lock cards into the right position
|
|
// when moving them between columns, but not within a column.
|
|
if (has_headers) {
|
|
list.setCompareOnMove(true);
|
|
}
|
|
|
|
// If we can't reorder cards, we always lock them into their current
|
|
// position.
|
|
if (!can_reorder) {
|
|
list.setCompareOnMove(true);
|
|
list.setCompareOnReorder(true);
|
|
}
|
|
|
|
list.setTargetChangeHandler(JX.bind(this, this._didChangeDropTarget));
|
|
|
|
list.listen('didDrop', JX.bind(this, this._onmovecard, list));
|
|
|
|
list.listen('didBeginDrag', JX.bind(this, this._beginDrag));
|
|
list.listen('didEndDrag', JX.bind(this, this._endDrag));
|
|
|
|
lists.push(list);
|
|
}
|
|
|
|
for (var ii = 0; ii < lists.length; ii++) {
|
|
lists[ii].setGroup(lists);
|
|
}
|
|
},
|
|
|
|
_didChangeDropTarget: function(src_list, src_node, dst_list, dst_node) {
|
|
if (!dst_list) {
|
|
// The card is being dragged into a dead area, like the left menu.
|
|
this._showEffects([]);
|
|
return;
|
|
}
|
|
|
|
if (dst_node === false) {
|
|
// The card is being dragged over itself, so dropping it won't
|
|
// affect anything.
|
|
this._showEffects([]);
|
|
return;
|
|
}
|
|
|
|
var src_phid = JX.Stratcom.getData(src_list.getRootNode()).columnPHID;
|
|
var dst_phid = JX.Stratcom.getData(dst_list.getRootNode()).columnPHID;
|
|
|
|
var src_column = this.getColumn(src_phid);
|
|
var dst_column = this.getColumn(dst_phid);
|
|
|
|
var effects = [];
|
|
if (src_column !== dst_column) {
|
|
effects = effects.concat(dst_column.getDropEffects());
|
|
}
|
|
|
|
var context = this._getDropContext(dst_node);
|
|
if (context.headerKey) {
|
|
var header = this.getHeaderTemplate(context.headerKey);
|
|
effects = effects.concat(header.getDropEffects());
|
|
}
|
|
|
|
var card_phid = JX.Stratcom.getData(src_node).objectPHID;
|
|
var card = src_column.getCard(card_phid);
|
|
|
|
var visible = [];
|
|
for (var ii = 0; ii < effects.length; ii++) {
|
|
if (effects[ii].isEffectVisibleForCard(card)) {
|
|
visible.push(effects[ii]);
|
|
}
|
|
}
|
|
effects = visible;
|
|
|
|
this._showEffects(effects);
|
|
},
|
|
|
|
_showEffects: function(effects) {
|
|
var node = this._getDropPreviewNode();
|
|
|
|
if (!effects.length) {
|
|
JX.DOM.remove(node);
|
|
this._previewPositionVector = null;
|
|
return;
|
|
}
|
|
|
|
var items = [];
|
|
for (var ii = 0; ii < effects.length; ii++) {
|
|
var effect = effects[ii];
|
|
items.push(effect.newNode());
|
|
}
|
|
|
|
JX.DOM.setContent(this._getDropPreviewListNode(), items);
|
|
document.body.appendChild(node);
|
|
|
|
// Undim the drop preview element if it was previously dimmed.
|
|
this._setPreviewDimState(false);
|
|
this._previewPositionVector = JX.$V(node);
|
|
},
|
|
|
|
_getDropPreviewNode: function() {
|
|
if (!this._dropPreviewNode) {
|
|
var attributes = {
|
|
className: 'workboard-drop-preview'
|
|
};
|
|
|
|
var content = [
|
|
this._getDropPreviewListNode()
|
|
];
|
|
|
|
this._dropPreviewNode = JX.$N('div', attributes, content);
|
|
}
|
|
|
|
return this._dropPreviewNode;
|
|
},
|
|
|
|
_getDropPreviewListNode: function() {
|
|
if (!this._dropPreviewListNode) {
|
|
var attributes = {};
|
|
this._dropPreviewListNode = JX.$N('ul', attributes);
|
|
}
|
|
|
|
return this._dropPreviewListNode;
|
|
},
|
|
|
|
_findCardsInColumn: function(column_node) {
|
|
return JX.DOM.scry(column_node, 'li', 'project-card');
|
|
},
|
|
|
|
_getDropContext: function(after_node, item) {
|
|
var header_key;
|
|
var after_phids = [];
|
|
var before_phids = [];
|
|
|
|
// We're going to send an "afterPHID" and a "beforePHID" if the card
|
|
// was dropped immediately adjacent to another card. If a card was
|
|
// dropped before or after a header, we don't send a PHID for the card
|
|
// on the other side of the header.
|
|
|
|
// If the view has headers, we always send the header the card was
|
|
// dropped under.
|
|
|
|
var after_data;
|
|
var after_card = after_node;
|
|
while (after_card) {
|
|
after_data = JX.Stratcom.getData(after_card);
|
|
|
|
if (after_data.headerKey) {
|
|
break;
|
|
}
|
|
|
|
if (after_data.objectPHID) {
|
|
after_phids.push(after_data.objectPHID);
|
|
}
|
|
|
|
after_card = after_card.previousSibling;
|
|
}
|
|
|
|
if (item) {
|
|
var before_data;
|
|
var before_card = item.nextSibling;
|
|
while (before_card) {
|
|
before_data = JX.Stratcom.getData(before_card);
|
|
|
|
if (before_data.headerKey) {
|
|
break;
|
|
}
|
|
|
|
if (before_data.objectPHID) {
|
|
before_phids.push(before_data.objectPHID);
|
|
}
|
|
|
|
before_card = before_card.nextSibling;
|
|
}
|
|
}
|
|
|
|
var header_data;
|
|
var header_node = after_node;
|
|
while (header_node) {
|
|
header_data = JX.Stratcom.getData(header_node);
|
|
if (header_data.headerKey) {
|
|
break;
|
|
}
|
|
header_node = header_node.previousSibling;
|
|
}
|
|
|
|
if (header_data) {
|
|
header_key = header_data.headerKey;
|
|
}
|
|
|
|
return {
|
|
headerKey: header_key,
|
|
afterPHIDs: after_phids,
|
|
beforePHIDs: before_phids
|
|
};
|
|
},
|
|
|
|
_onmovecard: function(list, item, after_node, src_list) {
|
|
list.lock();
|
|
JX.DOM.alterClass(item, 'drag-sending', true);
|
|
|
|
var src_phid = JX.Stratcom.getData(src_list.getRootNode()).columnPHID;
|
|
var dst_phid = JX.Stratcom.getData(list.getRootNode()).columnPHID;
|
|
|
|
var item_phid = JX.Stratcom.getData(item).objectPHID;
|
|
var data = {
|
|
objectPHID: item_phid,
|
|
columnPHID: dst_phid,
|
|
order: this.getOrder()
|
|
};
|
|
|
|
var context = this._getDropContext(after_node, item);
|
|
data.afterPHIDs = context.afterPHIDs.join(',');
|
|
data.beforePHIDs = context.beforePHIDs.join(',');
|
|
|
|
if (context.headerKey) {
|
|
var properties = this.getHeaderTemplate(context.headerKey)
|
|
.getEditProperties();
|
|
data.header = JX.JSON.stringify(properties);
|
|
}
|
|
|
|
var visible_phids = [];
|
|
var column = this.getColumn(dst_phid);
|
|
for (var object_phid in column.getCards()) {
|
|
visible_phids.push(object_phid);
|
|
}
|
|
|
|
data.visiblePHIDs = visible_phids.join(',');
|
|
|
|
// If the user cancels the workflow (for example, by hitting an MFA
|
|
// prompt that they click "Cancel" on), put the card back where it was
|
|
// and reset the UI state.
|
|
var on_revert = JX.bind(
|
|
this,
|
|
this._revertCard,
|
|
list,
|
|
item,
|
|
src_phid,
|
|
dst_phid);
|
|
|
|
var after_phid = null;
|
|
if (data.afterPHIDs.length) {
|
|
after_phid = data.afterPHIDs[0];
|
|
}
|
|
|
|
var onupdate = JX.bind(
|
|
this,
|
|
this._oncardupdate,
|
|
list,
|
|
src_phid,
|
|
dst_phid,
|
|
after_phid);
|
|
|
|
new JX.Workflow(this.getController().getMoveURI(), data)
|
|
.setHandler(onupdate)
|
|
.setCloseHandler(on_revert)
|
|
.start();
|
|
},
|
|
|
|
_revertCard: function(list, item, src_phid, dst_phid) {
|
|
JX.DOM.alterClass(item, 'drag-sending', false);
|
|
|
|
var src_column = this.getColumn(src_phid);
|
|
var dst_column = this.getColumn(dst_phid);
|
|
|
|
src_column.markForRedraw();
|
|
dst_column.markForRedraw();
|
|
this._redrawColumns();
|
|
|
|
list.unlock();
|
|
},
|
|
|
|
_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);
|
|
|
|
var sounds = response.sounds || [];
|
|
for (var ii = 0; ii < sounds.length; ii++) {
|
|
JX.Sound.queue(sounds[ii]);
|
|
}
|
|
|
|
list.unlock();
|
|
},
|
|
|
|
updateCard: function(response) {
|
|
var columns = this.getColumns();
|
|
|
|
var phid = response.objectPHID;
|
|
|
|
for (var add_phid in response.columnMaps) {
|
|
var target_column = this.getColumn(add_phid);
|
|
|
|
if (!target_column) {
|
|
// If the column isn't visible, don't try to add a card to it.
|
|
continue;
|
|
}
|
|
|
|
target_column.newCard(phid);
|
|
}
|
|
|
|
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]);
|
|
}
|
|
|
|
for (var card_phid in response.cards) {
|
|
var card_data = response.cards[card_phid];
|
|
var card_template = this.getCardTemplate(card_phid);
|
|
|
|
if (card_data.nodeHTMLTemplate) {
|
|
card_template.setNodeHTMLTemplate(card_data.nodeHTMLTemplate);
|
|
}
|
|
|
|
var order;
|
|
for (order in card_data.vectors) {
|
|
card_template.setSortVector(order, card_data.vectors[order]);
|
|
}
|
|
|
|
for (order in card_data.headers) {
|
|
card_template.setHeaderKey(order, card_data.headers[order]);
|
|
}
|
|
|
|
for (var key in card_data.properties) {
|
|
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)
|
|
.setOrder(header.order)
|
|
.setNodeHTMLTemplate(header.template)
|
|
.setVector(header.vector)
|
|
.setEditProperties(header.editProperties);
|
|
}
|
|
|
|
for (var column_phid in columns) {
|
|
var column = columns[column_phid];
|
|
|
|
var cards = column.getCards();
|
|
for (var object_phid in cards) {
|
|
if (object_phid !== phid) {
|
|
continue;
|
|
}
|
|
|
|
var card = cards[object_phid];
|
|
card.redraw();
|
|
|
|
column.markForRedraw();
|
|
}
|
|
}
|
|
|
|
this._redrawColumns();
|
|
},
|
|
|
|
_redrawColumns: function() {
|
|
var columns = this.getColumns();
|
|
for (var k in columns) {
|
|
if (columns[k].isMarkedForRedraw()) {
|
|
columns[k].redraw();
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
});
|