1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-29 10:12:41 +01:00

Herald JS basics.

This commit is contained in:
epriestley 2011-03-22 17:08:08 -07:00
parent 9c5e7bb71d
commit b060f0a80f
7 changed files with 598 additions and 28 deletions

View file

@ -101,6 +101,8 @@ foreach ($file_map as $path => $info) {
$provides = array_filter($provides); $provides = array_filter($provides);
$requires = array_filter($requires); $requires = array_filter($requires);
var_dump($requires);
if (count($provides) !== 1) { if (count($provides) !== 1) {
throw new Exception( throw new Exception(
"File {$path} must @provide exactly one Celerity target."); "File {$path} must @provide exactly one Celerity target.");

View file

@ -81,7 +81,7 @@ celerity_register_resource_map(array(
), ),
'aphront-side-nav-view-css' => 'aphront-side-nav-view-css' =>
array( array(
'uri' => '/res/09b7eb85/rsrc/css/aphront/side-nav-view.css', 'uri' => '/res/4f4c5ca8/rsrc/css/aphront/side-nav-view.css',
'type' => 'css', 'type' => 'css',
'requires' => 'requires' =>
array( array(
@ -199,7 +199,7 @@ celerity_register_resource_map(array(
), ),
'diffusion-commit-view-css' => 'diffusion-commit-view-css' =>
array( array(
'uri' => '/res/4593ecc8/rsrc/css/application/diffusion/commit-view.css', 'uri' => '/res/8c139192/rsrc/css/application/diffusion/commit-view.css',
'type' => 'css', 'type' => 'css',
'requires' => 'requires' =>
array( array(
@ -336,6 +336,16 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/application/core/behavior-workflow.js', 'disk' => '/rsrc/js/application/core/behavior-workflow.js',
), ),
'multirow-row-manager' =>
array(
'uri' => '/res/330d076b/rsrc/js/application/core/MultirowRowManager.js',
'type' => 'js',
'requires' =>
array(
0 => 'javelin-lib-dev',
),
'disk' => '/rsrc/js/application/core/MultirowRowManager.js',
),
'javelin-behavior-differential-add-reviewers' => 'javelin-behavior-differential-add-reviewers' =>
array( array(
'uri' => '/res/330154e4/rsrc/js/application/differential/behavior-add-reviewers.js', 'uri' => '/res/330154e4/rsrc/js/application/differential/behavior-add-reviewers.js',
@ -406,6 +416,26 @@ celerity_register_resource_map(array(
), ),
'disk' => '/rsrc/js/application/differential/behavior-show-more.js', 'disk' => '/rsrc/js/application/differential/behavior-show-more.js',
), ),
'javelin-behavior-herald-rule-editor' =>
array(
'uri' => '/res/f18bcd5e/rsrc/js/application/herald/herald-rule-editor.js',
'type' => 'js',
'requires' =>
array(
0 => 'herald-rule-editor',
),
'disk' => '/rsrc/js/application/herald/herald-rule-editor.js',
),
'herald-rule-editor' =>
array(
'uri' => '/res/e71d1d0e/rsrc/js/application/herald/HeraldRuleEditor.js',
'type' => 'js',
'requires' =>
array(
0 => 'multirow-row-manager',
),
'disk' => '/rsrc/js/application/herald/HeraldRuleEditor.js',
),
'javelin-behavior-maniphest-transaction-controls' => 'javelin-behavior-maniphest-transaction-controls' =>
array( array(
'uri' => '/res/fc6a8722/rsrc/js/application/maniphest/behavior-transaction-controls.js', 'uri' => '/res/fc6a8722/rsrc/js/application/maniphest/behavior-transaction-controls.js',
@ -491,7 +521,7 @@ celerity_register_resource_map(array(
), array ( ), array (
'packages' => 'packages' =>
array ( array (
73063447 => '848f4c9f' =>
array ( array (
'name' => 'core.pkg.css', 'name' => 'core.pkg.css',
'symbols' => 'symbols' =>
@ -511,7 +541,7 @@ celerity_register_resource_map(array(
12 => 'phabricator-remarkup-css', 12 => 'phabricator-remarkup-css',
13 => 'syntax-highlighting-css', 13 => 'syntax-highlighting-css',
), ),
'uri' => '/res/pkg/73063447/core.pkg.css', 'uri' => '/res/pkg/848f4c9f/core.pkg.css',
'type' => 'css', 'type' => 'css',
), ),
'76f3c1f8' => '76f3c1f8' =>
@ -545,33 +575,33 @@ celerity_register_resource_map(array(
'uri' => '/res/pkg/30d594cf/differential.pkg.js', 'uri' => '/res/pkg/30d594cf/differential.pkg.js',
'type' => 'js', 'type' => 'js',
), ),
'2393c3a4' => 'eadf6ec3' =>
array ( array (
'name' => 'diffusion.pkg.css', 'name' => 'diffusion.pkg.css',
'symbols' => 'symbols' =>
array ( array (
0 => 'diffusion-commit-view-css', 0 => 'diffusion-commit-view-css',
), ),
'uri' => '/res/pkg/2393c3a4/diffusion.pkg.css', 'uri' => '/res/pkg/eadf6ec3/diffusion.pkg.css',
'type' => 'css', 'type' => 'css',
), ),
), ),
'reverse' => 'reverse' =>
array ( array (
'phabricator-core-css' => '73063447', 'phabricator-core-css' => '848f4c9f',
'phabricator-core-buttons-css' => '73063447', 'phabricator-core-buttons-css' => '848f4c9f',
'phabricator-standard-page-view' => '73063447', 'phabricator-standard-page-view' => '848f4c9f',
'aphront-dialog-view-css' => '73063447', 'aphront-dialog-view-css' => '848f4c9f',
'aphront-form-view-css' => '73063447', 'aphront-form-view-css' => '848f4c9f',
'aphront-panel-view-css' => '73063447', 'aphront-panel-view-css' => '848f4c9f',
'aphront-side-nav-view-css' => '73063447', 'aphront-side-nav-view-css' => '848f4c9f',
'aphront-table-view-css' => '73063447', 'aphront-table-view-css' => '848f4c9f',
'aphront-crumbs-view-css' => '73063447', 'aphront-crumbs-view-css' => '848f4c9f',
'aphront-tokenizer-control-css' => '73063447', 'aphront-tokenizer-control-css' => '848f4c9f',
'aphront-typeahead-control-css' => '73063447', 'aphront-typeahead-control-css' => '848f4c9f',
'phabricator-directory-css' => '73063447', 'phabricator-directory-css' => '848f4c9f',
'phabricator-remarkup-css' => '73063447', 'phabricator-remarkup-css' => '848f4c9f',
'syntax-highlighting-css' => '73063447', 'syntax-highlighting-css' => '848f4c9f',
'differential-core-view-css' => '76f3c1f8', 'differential-core-view-css' => '76f3c1f8',
'differential-changeset-view-css' => '76f3c1f8', 'differential-changeset-view-css' => '76f3c1f8',
'differential-revision-detail-css' => '76f3c1f8', 'differential-revision-detail-css' => '76f3c1f8',
@ -585,6 +615,6 @@ celerity_register_resource_map(array(
'javelin-behavior-differential-populate' => '30d594cf', 'javelin-behavior-differential-populate' => '30d594cf',
'javelin-behavior-differential-show-more' => '30d594cf', 'javelin-behavior-differential-show-more' => '30d594cf',
'javelin-behavior-differential-diff-radios' => '30d594cf', 'javelin-behavior-differential-diff-radios' => '30d594cf',
'diffusion-commit-view-css' => '2393c3a4', 'diffusion-commit-view-css' => 'eadf6ec3',
), ),
)); ));

View file

@ -251,6 +251,7 @@ class HeraldRuleController extends HeraldController {
$form = id(new AphrontFormView()) $form = id(new AphrontFormView())
->setUser($user) ->setUser($user)
->setID('herald-rule-edit-form')
->addHiddenInput('type', $rule->getContentType()) ->addHiddenInput('type', $rule->getContentType())
->addHiddenInput('save', true) ->addHiddenInput('save', true)
->addHiddenInput('rule', '') ->addHiddenInput('rule', '')
@ -270,16 +271,33 @@ class HeraldRuleController extends HeraldController {
->appendChild( ->appendChild(
'<h1>Conditions</h1>'. '<h1>Conditions</h1>'.
'<div style="margin: .5em 0 1em; padding: .5em; background: #aaa;">'. '<div style="margin: .5em 0 1em; padding: .5em; background: #aaa;">'.
'<a href="#" class="button green">Create New Condition</a>'. javelin_render_tag(
'a',
array(
'href' => '#',
'class' => 'button green',
'sigil' => 'create-action',
),
'Create New Condition').
'<p>When '.$must_match.' these conditions are met:</p>'. '<p>When '.$must_match.' these conditions are met:</p>'.
'<table></table>'. javelin_render_tag(
'table',
array(
'sigil' => 'rule-conditions',
),
'').
'</div>') '</div>')
->appendChild( ->appendChild(
'<h1>Action</h1>'. '<h1>Action</h1>'.
'<div style="margin: .5em 0 1em; padding: .5em; background: #aaa;">'. '<div style="margin: .5em 0 1em; padding: .5em; background: #aaa;">'.
'<a href="#" class="button green">Create New Action</a>'. '<a href="#" class="button green">Create New Action</a>'.
'<p>Take these actions:</p>'. '<p>Take these actions:</p>'.
'<table></table>'. javelin_render_tag(
'table',
array(
'sigil' => 'rule-actions',
),
'').
'</div>') '</div>')
->appendChild( ->appendChild(
id(new AphrontFormSubmitControl()) id(new AphrontFormSubmitControl())
@ -439,11 +457,10 @@ class HeraldRuleController extends HeraldController {
HeraldValueTypeConfig::getValueTypeForAction($action); HeraldValueTypeConfig::getValueTypeForAction($action);
} }
/*
Javelin::initBehavior( Javelin::initBehavior(
'herald-rule-editor', 'herald-rule-editor',
array( array(
'root' => 'qq',//$form->requireUniqueId(), 'root' => 'herald-rule-edit-form',
'conditions' => (object) $serial_conditions, 'conditions' => (object) $serial_conditions,
'actions' => (object) $serial_actions, 'actions' => (object) $serial_actions,
'template' => $this->buildTokenizerTemplates() + array( 'template' => $this->buildTokenizerTemplates() + array(
@ -452,8 +469,6 @@ class HeraldRuleController extends HeraldController {
'info' => $config_info, 'info' => $config_info,
)); ));
*/
$panel = new AphrontPanelView(); $panel = new AphrontPanelView();
$panel->setHeader('Edit Herald Rule'); $panel->setHeader('Edit Herald Rule');
$panel->setWidth(AphrontPanelView::WIDTH_WIDE); $panel->setWidth(AphrontPanelView::WIDTH_WIDE);

View file

@ -25,6 +25,12 @@ final class AphrontFormView extends AphrontView {
private $encType; private $encType;
private $user; private $user;
private $workflow; private $workflow;
private $id;
public function setID($id) {
$this->id = $id;
return $this;
}
public function setUser(PhabricatorUser $user) { public function setUser(PhabricatorUser $user) {
$this->user = $user; $this->user = $user;
@ -66,6 +72,7 @@ final class AphrontFormView extends AphrontView {
'class' => 'aphront-form-view', 'class' => 'aphront-form-view',
'enctype' => $this->encType, 'enctype' => $this->encType,
'sigil' => $this->workflow ? 'workflow' : null, 'sigil' => $this->workflow ? 'workflow' : null,
'id' => $this->id,
), ),
$this->renderDataInputs(). $this->renderDataInputs().
$this->renderChildren()); $this->renderChildren());

View file

@ -0,0 +1,143 @@
/**
* @requires javelin-lib-dev
* @provides multirow-row-manager
* @javelin
*/
/**
* Give a MultirowRowManager a table DOM elem to manage.
* You can add rows, and provide a given ID if you like.
* You can update rows by ID.
* Rows are automatically equipped with a removal button.
* You can listen to the 'row-removed' event on the Manager to get
* notifications of these row removals, with the DOM id of the removed
* row as event data.
*/
JX.install('MultirowRowManager', {
/**
* @param DOM element <table> root Container for rows
*/
construct : function(root, minRows) {
this._root = root;
this._rows = [];
if (typeof minRows !== "undefined") {
this._minRows = minRows;
} else {
this._minRows = 1;
}
JX.DOM.listen(
this._root,
'click',
JX.MultirowRowManager._removeSigil,
JX.bind(this, this._onrowremoved));
},
members : {
_count : 0,
_nextID : 0,
_root : null,
_rows : null,
_generateRowID : function() {
return "" + this._nextID++;
},
_wrapRowContents : function(row_id, row_contents) {
var row = JX.$N('tr',
{ sigil : JX.MultirowRowManager.getRowSigil(),
meta : { multirow_row_manager_row_id : row_id }
},
row_contents);
var removeButton = JX.$N(
'td',
{},
JX.$N(
'a',
{ className: "button",
sigil: JX.MultirowRowManager._removeSigil
},
'-'));
JX.DOM.appendContent(row, removeButton);
return row;
},
getRowID : function(row) {
return JX.Stratcom.getData(row).multirow_row_manager_row_id;
},
/**
* @param row_contents [DOM elements] New contents of row
* @param row_id row ID to update, will throw if this row has been removed
*/
updateRow : function(row_id, row_contents) {
if (__DEV__) {
if (typeof this._rows[row_id] === "undefined") {
throw new Error("JX.MultirowRowManager.updateRow(row_id, " +
"row_contents): provided row id does not exist." +
" Use addRow to create a new row and make sure " +
"not to update rows that have been deleted.");
}
}
var old_row = this._rows[row_id];
var new_row = this._wrapRowContents(row_id, row_contents);
JX.copy(JX.Stratcom.getData(new_row), JX.Stratcom.getData(old_row));
JX.DOM.replace(old_row, new_row);
this._rows[row_id] = new_row;
this._oncountchanged(); // Fix the new button.
return new_row;
},
addRow : function(row_contents) {
var row_id = this._generateRowID();
var row = this._wrapRowContents(row_id, row_contents);
JX.DOM.appendContent(this._root, row);
this._count++;
this._oncountchanged();
this._rows[row_id] = row;
return row;
},
_onrowremoved : function(e) {
if (!JX.Stratcom.getData(e.getTarget()).enabled) {
return;
}
var row = e.getNode(JX.MultirowRowManager.getRowSigil());
var row_id = this.getRowID(row);
delete this._rows[row_id];
JX.DOM.remove(row);
this._count--;
this._oncountchanged();
this.invoke('row-removed', row_id);
},
_oncountchanged : function(e) {
var buttons = JX.DOM.scry(
this._root,
'a',
JX.MultirowRowManager._removeSigil);
var disable = (this._minRows >= 0 && this._count <= this._minRows);
for (var i = 0; i < buttons.length; i++) {
var button = buttons[i];
JX.DOM.alterClass(button, 'disabled', disable);
JX.Stratcom.getData(button).enabled = !disable;
}
}
},
events : ['row-removed'],
statics : {
getRowSigil : function() {
return "tools-multirow-row-manager-row";
},
_removeSigil : "tools-multirow-row-manager-row-remove"
}
});

View file

@ -0,0 +1,363 @@
/**
* @requires multirow-row-manager
* javelin-lib-dev
* javelin-typeahead-dev
* @provides herald-rule-editor
* @javelin
*/
JX.install('HeraldRuleEditor', {
construct : function(config) {
var root = JX.$(config.root);
this._root = root;
JX.DOM.listen(
root,
'click',
'create-condition',
JX.bind(this, this._onnewcondition));
JX.DOM.listen(
root,
'click',
'create-action',
JX.bind(this, this._onnewaction));
JX.DOM.listen(root, 'change', null, JX.bind(this, this._onchange));
JX.DOM.listen(root, 'submit', null, JX.bind(this, this._onsubmit));
var conditionsTable = JX.DOM.find(root, 'table', 'rule-conditions');
var actionsTable = JX.DOM.find(root, 'table', 'rule-actions');
this._conditionsRowManager = new JX.MultirowRowManager(conditionsTable);
this._conditionsRowManager.listen(
'row-removed',
JX.bind(this, function(row_id) {
delete this._config.conditions[row_id];
}));
this._actionsRowManager = new JX.MultirowRowManager(actionsTable);
this._actionsRowManager.listen(
'row-removed',
JX.bind(this, function(row_id) {
delete this._config.actions[row_id];
}));
this._conditionGetters = {};
this._conditionTypes = {};
this._actionGetters = {};
this._actionTypes = {};
this._config = config;
var conditions = this._config.conditions;
this._config.conditions = [];
var actions = this._config.actions;
this._config.actions = [];
this._renderConditions(conditions);
this._renderActions(actions);
},
members : {
_config : null,
_root : null,
_conditionGetters : null,
_conditionTypes : null,
_actionGetters : null,
_actionTypes : null,
_conditionsRowManager : null,
_actionsRowManager : null,
_onnewcondition : function(e) {
this._newCondition();
e.kill();
},
_onnewaction : function(e) {
this._newAction();
e.kill();
},
_onchange : function(e) {
var target = e.getTarget();
var row = e.getNode(JX.MultirowRowManager.getRowSigil());
if (!row) {
// Changing the "when all of / any of these..." dropdown.
return;
}
if (JX.Stratcom.hasSigil(target, 'field-select')) {
this._onfieldchange(row);
} else if (JX.Stratcom.hasSigil(target, 'condition-select')) {
this._onconditionchange(row);
} else if (JX.Stratcom.hasSigil(target, 'action-select')) {
this._onactionchange(row);
}
},
_onsubmit : function(e) {
var rule = JX.DOM.find(this._root, 'input', 'rule');
var k;
for (k in this._config.conditions) {
this._config.conditions[k][2] = this._getConditionValue(k);
}
var acts = this._config.actions;
for (k in this._config.actions) {
this._config.actions[k][1] = this._getActionTarget(k);
}
rule.value = JX.JSON.serialize({
conditions: this._config.conditions,
actions: this._config.actions
});
},
_getConditionValue : function(id) {
if (this._conditionGetters[id]) {
return this._conditionGetters[id]();
}
return this._config.conditions[id][2];
},
_getActionTarget : function(id) {
if (this._actionGetters[id]) {
return this._actionGetters[id]();
}
return this._config.actions[id][1];
},
_onactionchange : function(r) {
var target = JX.DOM.find(r, 'select', 'action-select');
var row_id = this._actionsRowManager.getRowID(r);
this._config.actions[row_id][0] = target.value;
var target_cell = JX.DOM.find(r, 'td', 'target-cell');
var target_input = this._renderTargetInputForRow(row_id);
JX.DOM.setContent(target_cell, target_input);
},
_onfieldchange : function(r) {
var target = JX.DOM.find(r, 'select', 'field-select');
var row_id = this._actionsRowManager.getRowID(r);
this._config.conditions[row_id][0] = target.value;
var condition_cell = JX.DOM.find(r, 'td', 'condition-cell');
var condition_select = this._renderSelect(
this._selectKeys(
this._config.info.conditions,
this._config.info.conditionMap[target.value]),
this._config.conditions[row_id][1],
'condition-select');
JX.DOM.setContent(condition_cell, condition_select);
this._onconditionchange(r);
},
_onconditionchange : function(r) {
var target = JX.DOM.find(r, 'select', 'condition-select');
var row_id = this._conditionsRowManager.getRowID(r);
this._config.conditions[row_id][1] = target.value;
var value_cell = JX.DOM.find(r, 'td', 'value-cell');
var value_input = this._renderValueInputForRow(row_id);
JX.DOM.setContent(value_cell, value_input);
},
_renderTargetInputForRow : function(row_id) {
var action = this._config.actions[row_id];
var type = this._config.info.targets[action[0]];
var input = this._buildInput(type);
var node = input[0];
var get_fn = input[1];
var set_fn = input[2];
if (node) {
JX.Stratcom.addSigil(node, 'action-target');
}
var old_type = this._actionTypes[row_id];
if (old_type == type || !old_type) {
set_fn(this._getActionTarget(row_id));
}
this._actionTypes[row_id] = type;
this._actionGetters[row_id] = get_fn;
return node;
},
_buildInput : function(type) {
var input;
var get_fn;
var set_fn;
switch (type) {
case 'rule':
input = this._renderSelect(this._config.template.rules);
get_fn = function() { return input.value; };
set_fn = function(v) { input.value = v; };
break;
case 'email':
case 'employee':
case 'repository':
case 'tag':
case 'package':
var tokenizer = this._newTokenizer(type);
input = tokenizer[0];
get_fn = tokenizer[1];
set_fn = tokenizer[2];
break;
case 'none':
input = '';
get_fn = JX.bag;
set_fn = JX.bag;
break;
default:
input = JX.$N('input');
get_fn = function() { return input.value; };
set_fn = function(v) { input.value = v; };
break;
}
return [input, get_fn, set_fn];
},
_renderValueInputForRow : function(row_id) {
var cond = this._config.conditions[row_id];
var type = this._config.info.values[cond[0]][cond[1]];
var input = this._buildInput(type);
var node = input[0];
var get_fn = input[1];
var set_fn = input[2];
if (node) {
JX.Stratcom.addSigil(node, 'condition-value');
}
var old_type = this._conditionTypes[row_id];
if (old_type == type || !old_type) {
set_fn(this._getConditionValue(row_id));
}
this._conditionTypes[row_id] = type;
this._conditionGetters[row_id] = get_fn;
return node;
},
_newTokenizer : function(type) {
var template = JX.$N(
'div',
new JX.HTML(this._config.template.markup));
template = template.firstChild;
template.id = '';
var datasource = new JX.TypeaheadPreloadedSource(
this._config.template.source[type]);
var typeahead = new JX.Typeahead(template);
typeahead.setDatasource(datasource);
var tokenizer = new JX.Tokenizer(template);
tokenizer.setTypeahead(typeahead);
tokenizer.start();
return [
template,
function() {
return tokenizer.getTokens();
},
function(map) {
for (var k in map) {
tokenizer.addToken(k, map[k]);
}
}];
},
_selectKeys : function(map, keys) {
var r = {};
for (var ii = 0; ii < keys.length; ii++) {
r[keys[ii]] = map[keys[ii]];
}
return r;
},
_renderConditions : function(conditions) {
for (var k in conditions) {
this._newCondition(conditions[k]);
}
},
_newCondition : function(data) {
var row = this._conditionsRowManager.addRow([]);
var row_id = this._conditionsRowManager.getRowID(row);
this._config.conditions[row_id] = data || [null, null, ''];
var r = this._conditionsRowManager.updateRow(
row_id,
this._renderCondition(row_id));
this._onfieldchange(r);
},
_renderCondition : function(row_id) {
var field_select = this._renderSelect(
this._config.info.fields,
this._config.conditions[row_id][0],
'field-select');
var field_cell = JX.$N('td', {sigil: 'field-cell'}, field_select);
var condition_cell = JX.$N('td', {sigil: 'condition-cell'});
var value_cell = JX.$N('td', {className : 'value', sigil: 'value-cell'});
return [field_cell, condition_cell, value_cell];
},
_renderActions : function(actions) {
for (var k in actions) {
this._newAction(actions[k]);
delete actions[k];
}
},
_newAction : function(data) {
data = data || [];
var temprow = this._actionsRowManager.addRow([]);
var row_id = this._actionsRowManager.getRowID(temprow);
this._config.actions[row_id] = data;
var r = this._actionsRowManager.updateRow(row_id,
this._renderAction(data));
this._onactionchange(r);
},
_renderAction : function(action) {
var action_select = this._renderSelect(
this._config.info.actions,
action[0],
'action-select');
var action_cell = JX.$N('td', {sigil: 'action-cell'}, action_select);
var target_cell = JX.$N(
'td',
{className : 'target', sigil : 'target-cell'});
return [action_cell, target_cell];
},
_renderSelect : function(map, selected, sigil) {
var select = JX.$N(
'select',
{
style : {width: '250px', margin: '0 .5em 0 0'},
sigil : sigil
});
for (var k in map) {
select.options[select.options.length] = new Option(map[k], k);
if (k == selected) {
select.value = k;
}
}
select.value = select.value || JX.keys(map)[0];
return select;
}
}
});

View file

@ -0,0 +1,10 @@
/**
* @requires herald-rule-editor
* javelin-behavior
* @provides javelin-behavior-herald-rule-editor
* @javelin
*/
JX.behavior('herald-rule-editor', function(config) {
new JX.HeraldRuleEditor(config);
});