mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-18 19:40:55 +01:00
Basic stacked action support for EditEngine
Summary: Ref T9132. This still has a lot of rough edges but the basics seem to work OK. Test Plan: {F1012627} Reviewers: chad Reviewed By: chad Maniphest Tasks: T9132 Differential Revision: https://secure.phabricator.com/D14653
This commit is contained in:
parent
b82863d972
commit
dc0d914134
14 changed files with 532 additions and 8 deletions
|
@ -420,6 +420,7 @@ return array(
|
|||
'rsrc/js/application/repository/repository-crossreference.js' => 'e5339c43',
|
||||
'rsrc/js/application/search/behavior-reorder-queries.js' => 'e9581f08',
|
||||
'rsrc/js/application/slowvote/behavior-slowvote-embed.js' => '887ad43f',
|
||||
'rsrc/js/application/transactions/behavior-comment-actions.js' => 'f2c64202',
|
||||
'rsrc/js/application/transactions/behavior-reorder-fields.js' => 'b59e1e96',
|
||||
'rsrc/js/application/transactions/behavior-show-older-transactions.js' => 'dbbf48b6',
|
||||
'rsrc/js/application/transactions/behavior-transaction-comment-form.js' => 'b23b49e6',
|
||||
|
@ -498,6 +499,8 @@ return array(
|
|||
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
|
||||
'rsrc/js/phuix/PHUIXActionView.js' => '8cf6d262',
|
||||
'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca',
|
||||
'rsrc/js/phuix/PHUIXFormControl.js' => 'f9fba5ee',
|
||||
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
|
||||
),
|
||||
'symbols' => array(
|
||||
'almanac-css' => 'dbb9b3af',
|
||||
|
@ -561,6 +564,7 @@ return array(
|
|||
'javelin-behavior-audit-preview' => 'd835b03a',
|
||||
'javelin-behavior-bulk-job-reload' => 'edf8a145',
|
||||
'javelin-behavior-choose-control' => '6153c708',
|
||||
'javelin-behavior-comment-actions' => 'f2c64202',
|
||||
'javelin-behavior-config-reorder-fields' => 'b6993408',
|
||||
'javelin-behavior-conpherence-drag-and-drop-photo' => 'cf86d16a',
|
||||
'javelin-behavior-conpherence-menu' => '1d45c74d',
|
||||
|
@ -823,6 +827,8 @@ return array(
|
|||
'phuix-action-list-view' => 'b5c256b8',
|
||||
'phuix-action-view' => '8cf6d262',
|
||||
'phuix-dropdown-menu' => 'bd4c8dca',
|
||||
'phuix-form-control-view' => 'f9fba5ee',
|
||||
'phuix-icon-view' => 'bff6884b',
|
||||
'policy-css' => '957ea14c',
|
||||
'policy-edit-css' => '815c66f7',
|
||||
'policy-transaction-detail-css' => '82100a43',
|
||||
|
@ -1767,6 +1773,10 @@ return array(
|
|||
'javelin-util',
|
||||
'javelin-request',
|
||||
),
|
||||
'bff6884b' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'c1700f6f' => array(
|
||||
'javelin-install',
|
||||
'javelin-util',
|
||||
|
@ -1973,6 +1983,14 @@ return array(
|
|||
'javelin-workflow',
|
||||
'javelin-json',
|
||||
),
|
||||
'f2c64202' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-stratcom',
|
||||
'javelin-workflow',
|
||||
'javelin-dom',
|
||||
'phuix-form-control-view',
|
||||
'phuix-icon-view',
|
||||
),
|
||||
'f36e01af' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-behavior-device',
|
||||
|
@ -2029,6 +2047,10 @@ return array(
|
|||
'javelin-util',
|
||||
'phabricator-busy',
|
||||
),
|
||||
'f9fba5ee' => array(
|
||||
'javelin-install',
|
||||
'javelin-dom',
|
||||
),
|
||||
'fa0f4fc2' => array(
|
||||
'javelin-behavior',
|
||||
'javelin-dom',
|
||||
|
|
|
@ -34,6 +34,7 @@ final class PhabricatorPasteViewController extends PhabricatorPasteController {
|
|||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->needContent(true)
|
||||
->needRawContent(true)
|
||||
->executeOne();
|
||||
if (!$paste) {
|
||||
return new Aphront404Response();
|
||||
|
|
|
@ -53,6 +53,7 @@ final class PhabricatorProjectsEditEngineExtension
|
|||
pht('Add projects.'),
|
||||
pht('Remove projects.'),
|
||||
pht('Set associated projects, overwriting current value.'))
|
||||
->setCommentActionLabel(pht('Add Projects'))
|
||||
->setTransactionType($edge_type)
|
||||
->setMetadataValue('edge:type', $project_edge_type)
|
||||
->setValue($project_phids);
|
||||
|
|
|
@ -50,6 +50,7 @@ final class PhabricatorSubscriptionsEditEngineExtension
|
|||
pht('Add subscribers.'),
|
||||
pht('Remove subscribers.'),
|
||||
pht('Set subscribers, overwriting current value.'))
|
||||
->setCommentActionLabel(pht('Add Subscribers'))
|
||||
->setTransactionType($subscribers_type)
|
||||
->setValue($sub_phids);
|
||||
|
||||
|
|
|
@ -873,6 +873,8 @@ abstract class PhabricatorEditEngine
|
|||
}
|
||||
|
||||
final public function buildEditEngineCommentView($object) {
|
||||
$config = $this->loadEditEngineConfiguration(null);
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$object_phid = $object->getPHID();
|
||||
|
||||
|
@ -897,6 +899,19 @@ abstract class PhabricatorEditEngine
|
|||
|
||||
$view->setCurrentVersion($this->loadDraftVersion($object));
|
||||
|
||||
$fields = $this->buildEditFields($object);
|
||||
|
||||
$all_types = array();
|
||||
foreach ($fields as $field) {
|
||||
// TODO: Load draft stuff.
|
||||
$types = $field->getCommentEditTypes();
|
||||
foreach ($types as $type) {
|
||||
$all_types[] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
$view->setEditTypes($all_types);
|
||||
|
||||
return $view;
|
||||
}
|
||||
|
||||
|
@ -999,6 +1014,9 @@ abstract class PhabricatorEditEngine
|
|||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
$config = $this->loadEditEngineConfiguration(null);
|
||||
$fields = $this->buildEditFields($object);
|
||||
|
||||
$is_preview = $request->isPreviewRequest();
|
||||
$view_uri = $this->getObjectViewURI($object);
|
||||
|
||||
|
@ -1025,11 +1043,46 @@ abstract class PhabricatorEditEngine
|
|||
|
||||
$xactions = array();
|
||||
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
->attachComment(
|
||||
id(clone $comment_template)
|
||||
->setContent($comment_text));
|
||||
$actions = $request->getStr('editengine.actions');
|
||||
if ($actions) {
|
||||
$type_map = array();
|
||||
foreach ($fields as $field) {
|
||||
$types = $field->getCommentEditTypes();
|
||||
foreach ($types as $type) {
|
||||
$type_map[$type->getEditType()] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
$actions = phutil_json_decode($actions);
|
||||
foreach ($actions as $action) {
|
||||
$type = idx($action, 'type');
|
||||
if (!$type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$edit_type = idx($type_map, $type);
|
||||
if (!$edit_type) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type_xactions = $edit_type->generateTransactions(
|
||||
$template,
|
||||
array(
|
||||
'value' => idx($action, 'value'),
|
||||
));
|
||||
foreach ($type_xactions as $type_xaction) {
|
||||
$xactions[] = $type_xaction;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strlen($comment_text) || !$xactions) {
|
||||
$xactions[] = id(clone $template)
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
->attachComment(
|
||||
id(clone $comment_template)
|
||||
->setContent($comment_text));
|
||||
}
|
||||
|
||||
$editor = $object->getApplicationTransactionEditor()
|
||||
->setActor($viewer)
|
||||
|
|
|
@ -494,4 +494,8 @@ abstract class PhabricatorEditField extends Phobject {
|
|||
return array($edit_type);
|
||||
}
|
||||
|
||||
public function getCommentEditTypes() {
|
||||
return array();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -3,8 +3,19 @@
|
|||
abstract class PhabricatorTokenizerEditField
|
||||
extends PhabricatorPHIDListEditField {
|
||||
|
||||
private $commentActionLabel;
|
||||
|
||||
abstract protected function newDatasource();
|
||||
|
||||
public function setCommentActionLabel($label) {
|
||||
$this->commentActionLabel = $label;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCommentActionLabel() {
|
||||
return $this->commentActionLabel;
|
||||
}
|
||||
|
||||
protected function newControl() {
|
||||
$control = id(new AphrontFormTokenizerControl())
|
||||
->setDatasource($this->newDatasource());
|
||||
|
@ -21,4 +32,42 @@ abstract class PhabricatorTokenizerEditField
|
|||
return $request->getArr($key.'.original');
|
||||
}
|
||||
|
||||
protected function newEditType() {
|
||||
$type = parent::newEditType();
|
||||
|
||||
if ($this->getUseEdgeTransactions()) {
|
||||
$datasource = $this->newDatasource()
|
||||
->setViewer($this->getViewer());
|
||||
$type->setDatasource($datasource);
|
||||
}
|
||||
|
||||
return $type;
|
||||
}
|
||||
|
||||
public function getCommentEditTypes() {
|
||||
if (!$this->getUseEdgeTransactions()) {
|
||||
return parent::getCommentEditTypes();
|
||||
}
|
||||
|
||||
$transaction_type = $this->getTransactionType();
|
||||
if ($transaction_type === null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$label = $this->getCommentActionLabel();
|
||||
if ($label === null) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$type_key = $this->getEditTypeKey();
|
||||
$base = $this->getEditType();
|
||||
|
||||
$add = id(clone $base)
|
||||
->setEditType($type_key.'.add')
|
||||
->setEdgeOperation('+')
|
||||
->setLabel($label);
|
||||
|
||||
return array($add);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -811,7 +811,17 @@ abstract class PhabricatorApplicationTransactionEditor
|
|||
$this->adjustTransactionValues($object, $xaction);
|
||||
}
|
||||
|
||||
$xactions = $this->filterTransactions($object, $xactions);
|
||||
try {
|
||||
$xactions = $this->filterTransactions($object, $xactions);
|
||||
} catch (Exception $ex) {
|
||||
if ($read_locking) {
|
||||
$object->endReadLocking();
|
||||
}
|
||||
if ($transaction_open) {
|
||||
$object->killTransaction();
|
||||
}
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
// Now that we've merged, filtered, and combined transactions, check for
|
||||
// required capabilities.
|
||||
|
|
|
@ -4,6 +4,7 @@ final class PhabricatorEdgeEditType extends PhabricatorEditType {
|
|||
|
||||
private $edgeOperation;
|
||||
private $valueDescription;
|
||||
private $datasource;
|
||||
|
||||
public function setEdgeOperation($edge_operation) {
|
||||
$this->edgeOperation = $edge_operation;
|
||||
|
@ -14,6 +15,15 @@ final class PhabricatorEdgeEditType extends PhabricatorEditType {
|
|||
return $this->edgeOperation;
|
||||
}
|
||||
|
||||
public function setDatasource($datasource) {
|
||||
$this->datasource = $datasource;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDatasource() {
|
||||
return $this->datasource;
|
||||
}
|
||||
|
||||
public function getValueType() {
|
||||
return 'list<phid>';
|
||||
}
|
||||
|
@ -46,4 +56,33 @@ final class PhabricatorEdgeEditType extends PhabricatorEditType {
|
|||
return $this->valueDescription;
|
||||
}
|
||||
|
||||
public function getPHUIXControlType() {
|
||||
$datasource = $this->getDatasource();
|
||||
|
||||
if (!$datasource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return 'tokenizer';
|
||||
}
|
||||
|
||||
public function getPHUIXControlSpecification() {
|
||||
$datasource = $this->getDatasource();
|
||||
|
||||
if (!$datasource) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$template = new AphrontTokenizerTemplateView();
|
||||
|
||||
return array(
|
||||
'markup' => $template->render(),
|
||||
'config' => array(
|
||||
'src' => $datasource->getDatasourceURI(),
|
||||
'browseURI' => $datasource->getBrowseURI(),
|
||||
'placeholder' => $datasource->getPlaceholderText(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ abstract class PhabricatorEditType extends Phobject {
|
|||
|
||||
private $editType;
|
||||
private $transactionType;
|
||||
private $label;
|
||||
private $field;
|
||||
private $description;
|
||||
private $summary;
|
||||
|
@ -30,6 +31,15 @@ abstract class PhabricatorEditType extends Phobject {
|
|||
return $this->summary;
|
||||
}
|
||||
|
||||
public function setLabel($label) {
|
||||
$this->label = $label;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLabel() {
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setField(PhabricatorEditField $field) {
|
||||
$this->field = $field;
|
||||
return $this;
|
||||
|
@ -86,4 +96,12 @@ abstract class PhabricatorEditType extends Phobject {
|
|||
return $xaction;
|
||||
}
|
||||
|
||||
public function getPHUIXControlType() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPHUIXControlSpecification() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
|||
|
||||
private $currentVersion;
|
||||
private $versionedDraft;
|
||||
private $editTypes;
|
||||
|
||||
public function setObjectPHID($object_phid) {
|
||||
$this->objectPHID = $object_phid;
|
||||
|
@ -100,6 +101,15 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
|||
return $this;
|
||||
}
|
||||
|
||||
public function setEditTypes($edit_types) {
|
||||
$this->editTypes = $edit_types;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getEditTypes() {
|
||||
return $this->editTypes;
|
||||
}
|
||||
|
||||
public function render() {
|
||||
|
||||
$user = $this->getUser();
|
||||
|
@ -182,7 +192,7 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
|||
$version_key = PhabricatorVersionedDraft::KEY_VERSION;
|
||||
$version_value = $this->getCurrentVersion();
|
||||
|
||||
return id(new AphrontFormView())
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($this->getUser())
|
||||
->addSigil('transaction-append')
|
||||
->setWorkflow(true)
|
||||
|
@ -193,7 +203,57 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
|||
->setAction($this->getAction())
|
||||
->setID($this->getFormID())
|
||||
->addHiddenInput('__draft__', $draft_key)
|
||||
->addHiddenInput($version_key, $version_value)
|
||||
->addHiddenInput($version_key, $version_value);
|
||||
|
||||
$edit_types = $this->getEditTypes();
|
||||
if ($edit_types) {
|
||||
|
||||
$action_map = array();
|
||||
foreach ($edit_types as $edit_type) {
|
||||
$key = $edit_type->getEditType();
|
||||
$action_map[$key] = array(
|
||||
'key' => $key,
|
||||
'label' => $edit_type->getLabel(),
|
||||
'type' => $edit_type->getPHUIXControlType(),
|
||||
'spec' => $edit_type->getPHUIXControlSpecification(),
|
||||
);
|
||||
}
|
||||
|
||||
$options = array();
|
||||
$options['+'] = pht('Add Action...');
|
||||
foreach ($action_map as $key => $item) {
|
||||
$options[$key] = $item['label'];
|
||||
}
|
||||
|
||||
$action_id = celerity_generate_unique_node_id();
|
||||
$input_id = celerity_generate_unique_node_id();
|
||||
|
||||
$form->appendChild(
|
||||
phutil_tag(
|
||||
'input',
|
||||
array(
|
||||
'type' => 'hidden',
|
||||
'name' => 'editengine.actions',
|
||||
'id' => $input_id,
|
||||
)));
|
||||
|
||||
$form->appendChild(
|
||||
id(new AphrontFormSelectControl())
|
||||
->setLabel(pht('Actions'))
|
||||
->setID($action_id)
|
||||
->setOptions($options));
|
||||
|
||||
Javelin::initBehavior(
|
||||
'comment-actions',
|
||||
array(
|
||||
'actionID' => $action_id,
|
||||
'inputID' => $input_id,
|
||||
'formID' => $this->getFormID(),
|
||||
'actions' => $action_map,
|
||||
));
|
||||
}
|
||||
|
||||
$form
|
||||
->appendChild(
|
||||
id(new PhabricatorRemarkupControl())
|
||||
->setID($this->getCommentID())
|
||||
|
@ -207,6 +267,8 @@ class PhabricatorApplicationTransactionCommentView extends AphrontView {
|
|||
->appendChild(
|
||||
id(new AphrontFormMarkupControl())
|
||||
->setValue($status));
|
||||
|
||||
return $form;
|
||||
}
|
||||
|
||||
private function renderPreviewPanel() {
|
||||
|
|
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @provides javelin-behavior-comment-actions
|
||||
* @requires javelin-behavior
|
||||
* javelin-stratcom
|
||||
* javelin-workflow
|
||||
* javelin-dom
|
||||
* phuix-form-control-view
|
||||
* phuix-icon-view
|
||||
*/
|
||||
|
||||
JX.behavior('comment-actions', function(config) {
|
||||
var action_map = config.actions;
|
||||
|
||||
var action_node = JX.$(config.actionID);
|
||||
var form_node = JX.$(config.formID);
|
||||
var input_node = JX.$(config.inputID);
|
||||
|
||||
var rows = {};
|
||||
|
||||
JX.DOM.listen(action_node, 'change', null, function() {
|
||||
var options = action_node.options;
|
||||
var option;
|
||||
|
||||
var selected = action_node.value;
|
||||
action_node.value = '+';
|
||||
|
||||
for (var ii = 0; ii < options.length; ii++) {
|
||||
option = options[ii];
|
||||
if (option.value == selected) {
|
||||
add_row(option);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
JX.DOM.listen(form_node, 'submit', null, function() {
|
||||
var data = [];
|
||||
|
||||
for (var k in rows) {
|
||||
data.push({
|
||||
type: k,
|
||||
value: rows[k].getValue()
|
||||
});
|
||||
}
|
||||
|
||||
input_node.value = JX.JSON.stringify(data);
|
||||
});
|
||||
|
||||
function add_row(option) {
|
||||
var action = action_map[option.value];
|
||||
if (!action) {
|
||||
return;
|
||||
}
|
||||
|
||||
option.disabled = true;
|
||||
|
||||
var icon = new JX.PHUIXIconView()
|
||||
.setIcon('fa-times-circle');
|
||||
var remove = JX.$N('a', {href: '#'}, icon.getNode());
|
||||
|
||||
var control = new JX.PHUIXFormControl()
|
||||
.setLabel(action.label)
|
||||
.setError(remove)
|
||||
.setControl('tokenizer', action.spec);
|
||||
var node = control.getNode();
|
||||
|
||||
rows[action.key] = control;
|
||||
|
||||
JX.DOM.listen(remove, 'click', null, function(e) {
|
||||
e.kill();
|
||||
JX.DOM.remove(node);
|
||||
delete rows[action.key];
|
||||
option.disabled = false;
|
||||
});
|
||||
|
||||
// TODO: Grotesque.
|
||||
action_node
|
||||
.parentNode
|
||||
.parentNode
|
||||
.parentNode
|
||||
.insertBefore(node, action_node.parentNode.parentNode.nextSibling);
|
||||
}
|
||||
|
||||
});
|
133
webroot/rsrc/js/phuix/PHUIXFormControl.js
Normal file
133
webroot/rsrc/js/phuix/PHUIXFormControl.js
Normal file
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* @provides phuix-form-control-view
|
||||
* @requires javelin-install
|
||||
* javelin-dom
|
||||
*/
|
||||
|
||||
JX.install('PHUIXFormControl', {
|
||||
|
||||
members: {
|
||||
_node: null,
|
||||
_labelNode: null,
|
||||
_errorNode: null,
|
||||
_inputNode: null,
|
||||
_valueSetCallback: null,
|
||||
_valueGetCallback: null,
|
||||
|
||||
setLabel: function(label) {
|
||||
JX.DOM.setContent(this._getLabelNode(), label);
|
||||
return this;
|
||||
},
|
||||
|
||||
setError: function(error) {
|
||||
JX.DOM.setContent(this._getErrorNode(), error);
|
||||
return this;
|
||||
},
|
||||
|
||||
setControl: function(type, spec) {
|
||||
var node = this._getInputNode();
|
||||
|
||||
var input;
|
||||
switch (type) {
|
||||
case 'tokenizer':
|
||||
input = this._newTokenizer(spec);
|
||||
break;
|
||||
default:
|
||||
// TODO: Default or better error?
|
||||
JX.$E('Bad Input Type');
|
||||
return;
|
||||
}
|
||||
|
||||
JX.DOM.setContent(node, input.node);
|
||||
this._valueGetCallback = input.get;
|
||||
this._valueSetCallback = input.set;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setValue: function(value) {
|
||||
this._valueSetCallback(value);
|
||||
return this;
|
||||
},
|
||||
|
||||
getValue: function() {
|
||||
return this._valueGetCallback();
|
||||
},
|
||||
|
||||
getNode: function() {
|
||||
if (!this._node) {
|
||||
|
||||
var attrs = {
|
||||
className: 'aphront-form-control grouped'
|
||||
};
|
||||
|
||||
var content = [
|
||||
this._getLabelNode(),
|
||||
this._getErrorNode(),
|
||||
this._getInputNode()
|
||||
];
|
||||
|
||||
this._node = JX.$N('div', attrs, content);
|
||||
}
|
||||
|
||||
return this._node;
|
||||
},
|
||||
|
||||
_getLabelNode: function() {
|
||||
if (!this._labelNode) {
|
||||
var attrs = {
|
||||
className: 'aphront-form-label'
|
||||
};
|
||||
|
||||
this._labelNode = JX.$N('label', attrs);
|
||||
}
|
||||
|
||||
return this._labelNode;
|
||||
},
|
||||
|
||||
_getErrorNode: function() {
|
||||
if (!this._errorNode) {
|
||||
var attrs = {
|
||||
className: 'aphront-form-error'
|
||||
};
|
||||
|
||||
this._errorNode = JX.$N('span', attrs);
|
||||
}
|
||||
|
||||
return this._errorNode;
|
||||
},
|
||||
|
||||
_getInputNode: function() {
|
||||
if (!this._inputNode) {
|
||||
var attrs = {
|
||||
className: 'aphront-form-input'
|
||||
};
|
||||
|
||||
this._inputNode = JX.$N('div', attrs);
|
||||
}
|
||||
|
||||
return this._inputNode;
|
||||
},
|
||||
|
||||
_newTokenizer: function(spec) {
|
||||
var build = JX.Prefab.newTokenizerFromTemplate(
|
||||
spec.markup,
|
||||
spec.config);
|
||||
build.tokenizer.start();
|
||||
|
||||
return {
|
||||
node: build.node,
|
||||
get: function() {
|
||||
return JX.keys(build.tokenizer.getTokens());
|
||||
},
|
||||
set: function(map) {
|
||||
for (var k in map) {
|
||||
build.tokenizer.addToken(k, map[k]);
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
});
|
47
webroot/rsrc/js/phuix/PHUIXIconView.js
Normal file
47
webroot/rsrc/js/phuix/PHUIXIconView.js
Normal file
|
@ -0,0 +1,47 @@
|
|||
/**
|
||||
* @provides phuix-icon-view
|
||||
* @requires javelin-install
|
||||
* javelin-dom
|
||||
*/
|
||||
|
||||
JX.install('PHUIXIconView', {
|
||||
|
||||
members: {
|
||||
_node: null,
|
||||
_icon: null,
|
||||
_color: null,
|
||||
|
||||
setIcon: function(icon) {
|
||||
var node = this.getNode();
|
||||
if (this._icon) {
|
||||
JX.DOM.alterClass(node, this._icon, false);
|
||||
}
|
||||
this._icon = icon;
|
||||
JX.DOM.alterClass(node, this._icon, true);
|
||||
return this;
|
||||
},
|
||||
|
||||
setColor: function(color) {
|
||||
var node = this.getNode();
|
||||
if (this._color) {
|
||||
JX.DOM.alterClass(node, this._color, false);
|
||||
}
|
||||
this._color = color;
|
||||
JX.DOM.alterClass(node, this._color, true);
|
||||
return this;
|
||||
},
|
||||
|
||||
getNode: function() {
|
||||
if (!this._node) {
|
||||
var attrs = {
|
||||
className: 'phui-icon-view phui-font-fa'
|
||||
};
|
||||
|
||||
this._node = JX.$N('span', attrs);
|
||||
}
|
||||
|
||||
return this._node;
|
||||
}
|
||||
}
|
||||
|
||||
});
|
Loading…
Reference in a new issue