2015-12-02 23:38:11 +01:00
|
|
|
/**
|
|
|
|
* @provides phuix-form-control-view
|
|
|
|
* @requires javelin-install
|
|
|
|
* javelin-dom
|
|
|
|
*/
|
|
|
|
|
|
|
|
JX.install('PHUIXFormControl', {
|
|
|
|
|
|
|
|
members: {
|
|
|
|
_node: null,
|
|
|
|
_labelNode: null,
|
|
|
|
_errorNode: null,
|
|
|
|
_inputNode: null,
|
2016-11-09 19:33:05 +01:00
|
|
|
_className: null,
|
2015-12-02 23:38:11 +01:00
|
|
|
_valueSetCallback: null,
|
|
|
|
_valueGetCallback: null,
|
2018-01-10 20:23:55 +01:00
|
|
|
_rawInputNode: null,
|
Use a tokenizer, not a gigantic poorly-ordered "<select />", to choose repositories in Owners
Summary: Depends on D19190. Fixes T12590. Ref T13099. Replaces the barely-usable, gigantic, poorly ordered "<select />" control with a tokenizer. Attempts to fix various minor issues.
Test Plan:
- Edited paths: include/exclude paths, from different repositories, different actual paths.
- Used "Add New Path" to add rows, got repository selector prepopulated with last value.
- Used "remove".
- Used validation typeahead, got reasonable behaviors?
The error behavior if you delete the repository for a path is a little sketchy still, but roughly okay.
Maniphest Tasks: T13099, T12590
Differential Revision: https://secure.phabricator.com/D19191
2018-03-08 02:29:06 +01:00
|
|
|
_tokenizer: null,
|
2015-12-02 23:38:11 +01:00
|
|
|
|
|
|
|
setLabel: function(label) {
|
|
|
|
JX.DOM.setContent(this._getLabelNode(), label);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setError: function(error) {
|
|
|
|
JX.DOM.setContent(this._getErrorNode(), error);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2016-11-09 19:33:05 +01:00
|
|
|
setClass: function(className) {
|
|
|
|
this._className = className;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
2015-12-02 23:38:11 +01:00
|
|
|
setControl: function(type, spec) {
|
|
|
|
var node = this._getInputNode();
|
|
|
|
|
|
|
|
var input;
|
|
|
|
switch (type) {
|
|
|
|
case 'tokenizer':
|
|
|
|
input = this._newTokenizer(spec);
|
|
|
|
break;
|
2015-12-04 16:56:03 +01:00
|
|
|
case 'select':
|
|
|
|
input = this._newSelect(spec);
|
|
|
|
break;
|
2016-02-09 00:24:52 +01:00
|
|
|
case 'points':
|
|
|
|
input = this._newPoints(spec);
|
|
|
|
break;
|
2016-04-06 14:59:09 +02:00
|
|
|
case 'optgroups':
|
|
|
|
input = this._newOptgroups(spec);
|
|
|
|
break;
|
2016-12-28 19:21:54 +01:00
|
|
|
case 'static':
|
|
|
|
input = this._newStatic(spec);
|
|
|
|
break;
|
When accepting revisions, allow users to accept on behalf of a subset of reviewers
Summary:
Ref T12271. Currenty, when you "Accept" a revision, you always accept it for all reviewers you have authority over.
There are some situations where communication can be more clear if users can accept as only themselves, or for only some packages, etc. T12271 discusses some of these use cases in more depth.
Instead of making "Accept" a blanket action, default it to doing what it does now but let the user uncheck reviewers.
In cases where project/package reviewers aren't in use, this doesn't change anything.
For now, "reject" still acts the old way (reject everything). We could make that use checkboxes too, but I'm not sure there's as much of a use case for it, and I generally want users who are blocking stuff to have more direct accountability in a product sense.
Test Plan:
- Accepted normally.
- Accepted a subset.
- Tried to accept none.
- Tried to accept bogus reviewers.
- Accepted with myself not a reviewer
- Accepted with only one reviewer (just got normal "this will be accepted" text).
{F4251255}
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T12271
Differential Revision: https://secure.phabricator.com/D17533
2017-03-22 17:28:36 +01:00
|
|
|
case 'checkboxes':
|
|
|
|
input = this._newCheckboxes(spec);
|
|
|
|
break;
|
2018-01-10 20:23:55 +01:00
|
|
|
case 'text':
|
|
|
|
input = this._newText(spec);
|
|
|
|
break;
|
Restore bulk edit support for remarkup fields (description, add comment)
Summary:
Depends on D18866. Ref T13025. Fixes T12415. This makes the old "Add Comment" action work, and adds support for a new "Set description to" action (possibly, I could imagine "append description" being useful some day, maybe).
The implementation is just a `<textarea />`, not a whole fancy remarkup box with `[Bold] [Italic] ...` buttons, preview, typeaheads, etc. It would be nice to enrich this eventually but doing the rendering in pure JS is currently very involved.
This requires a little bit of gymnastics to get the transaction populated properly, and adds some extra validation since we need some code there anyway.
Test Plan:
- Changed the description of a task via bulk editor.
- Added a comment to a task via bulk editor.
Reviewers: amckinley
Reviewed By: amckinley
Maniphest Tasks: T13025, T12415
Differential Revision: https://secure.phabricator.com/D18867
2018-01-11 18:48:33 +01:00
|
|
|
case 'remarkup':
|
|
|
|
input = this._newRemarkup(spec);
|
|
|
|
break;
|
2015-12-02 23:38:11 +01:00
|
|
|
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;
|
2018-01-10 20:23:55 +01:00
|
|
|
this._rawInputNode = input.node;
|
Use a tokenizer, not a gigantic poorly-ordered "<select />", to choose repositories in Owners
Summary: Depends on D19190. Fixes T12590. Ref T13099. Replaces the barely-usable, gigantic, poorly ordered "<select />" control with a tokenizer. Attempts to fix various minor issues.
Test Plan:
- Edited paths: include/exclude paths, from different repositories, different actual paths.
- Used "Add New Path" to add rows, got repository selector prepopulated with last value.
- Used "remove".
- Used validation typeahead, got reasonable behaviors?
The error behavior if you delete the repository for a path is a little sketchy still, but roughly okay.
Maniphest Tasks: T13099, T12590
Differential Revision: https://secure.phabricator.com/D19191
2018-03-08 02:29:06 +01:00
|
|
|
this._tokenizer = input.tokenizer || null;
|
2015-12-02 23:38:11 +01:00
|
|
|
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
setValue: function(value) {
|
|
|
|
this._valueSetCallback(value);
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
|
|
|
|
getValue: function() {
|
|
|
|
return this._valueGetCallback();
|
|
|
|
},
|
|
|
|
|
2018-01-10 20:23:55 +01:00
|
|
|
getRawInputNode: function() {
|
|
|
|
return this._rawInputNode;
|
|
|
|
},
|
|
|
|
|
Use a tokenizer, not a gigantic poorly-ordered "<select />", to choose repositories in Owners
Summary: Depends on D19190. Fixes T12590. Ref T13099. Replaces the barely-usable, gigantic, poorly ordered "<select />" control with a tokenizer. Attempts to fix various minor issues.
Test Plan:
- Edited paths: include/exclude paths, from different repositories, different actual paths.
- Used "Add New Path" to add rows, got repository selector prepopulated with last value.
- Used "remove".
- Used validation typeahead, got reasonable behaviors?
The error behavior if you delete the repository for a path is a little sketchy still, but roughly okay.
Maniphest Tasks: T13099, T12590
Differential Revision: https://secure.phabricator.com/D19191
2018-03-08 02:29:06 +01:00
|
|
|
getTokenizer: function() {
|
|
|
|
return this._tokenizer;
|
|
|
|
},
|
|
|
|
|
2015-12-02 23:38:11 +01:00
|
|
|
getNode: function() {
|
|
|
|
if (!this._node) {
|
|
|
|
|
|
|
|
var attrs = {
|
2016-11-09 19:33:05 +01:00
|
|
|
className: 'aphront-form-control ' + this._className + ' grouped'
|
2015-12-02 23:38:11 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
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();
|
|
|
|
|
2015-12-04 23:37:27 +01:00
|
|
|
function get_value() {
|
|
|
|
return JX.keys(build.tokenizer.getTokens());
|
|
|
|
}
|
|
|
|
|
2015-12-04 18:30:53 +01:00
|
|
|
function set_value(map) {
|
2015-12-04 23:37:27 +01:00
|
|
|
var tokens = get_value();
|
|
|
|
for (var ii = 0; ii < tokens.length; ii++) {
|
|
|
|
build.tokenizer.removeToken(tokens[ii]);
|
|
|
|
}
|
2015-12-04 18:30:53 +01:00
|
|
|
for (var k in map) {
|
|
|
|
var v = JX.Prefab.transformDatasourceResults(map[k]);
|
|
|
|
build.tokenizer.addToken(k, v);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
set_value(spec.value || {});
|
|
|
|
|
2015-12-02 23:38:11 +01:00
|
|
|
return {
|
|
|
|
node: build.node,
|
2015-12-04 23:37:27 +01:00
|
|
|
get: get_value,
|
Use a tokenizer, not a gigantic poorly-ordered "<select />", to choose repositories in Owners
Summary: Depends on D19190. Fixes T12590. Ref T13099. Replaces the barely-usable, gigantic, poorly ordered "<select />" control with a tokenizer. Attempts to fix various minor issues.
Test Plan:
- Edited paths: include/exclude paths, from different repositories, different actual paths.
- Used "Add New Path" to add rows, got repository selector prepopulated with last value.
- Used "remove".
- Used validation typeahead, got reasonable behaviors?
The error behavior if you delete the repository for a path is a little sketchy still, but roughly okay.
Maniphest Tasks: T13099, T12590
Differential Revision: https://secure.phabricator.com/D19191
2018-03-08 02:29:06 +01:00
|
|
|
set: set_value,
|
|
|
|
tokenizer: build.tokenizer
|
2015-12-02 23:38:11 +01:00
|
|
|
};
|
2015-12-04 16:56:03 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
_newSelect: function(spec) {
|
2015-12-04 23:37:27 +01:00
|
|
|
var node = JX.Prefab.renderSelect(
|
|
|
|
spec.options,
|
|
|
|
spec.value,
|
|
|
|
{},
|
|
|
|
spec.order);
|
2015-12-04 16:56:03 +01:00
|
|
|
|
2016-02-09 00:24:52 +01:00
|
|
|
return {
|
|
|
|
node: node,
|
|
|
|
get: function() {
|
|
|
|
return node.value;
|
|
|
|
},
|
|
|
|
set: function(value) {
|
|
|
|
node.value = value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2016-12-28 19:21:54 +01:00
|
|
|
_newStatic: function(spec) {
|
|
|
|
var node = JX.$N(
|
|
|
|
'div',
|
|
|
|
{
|
|
|
|
className: 'phui-form-static-action'
|
|
|
|
},
|
|
|
|
spec.description || '');
|
|
|
|
|
|
|
|
return {
|
|
|
|
node: node,
|
|
|
|
get: function() {
|
|
|
|
return true;
|
|
|
|
},
|
|
|
|
set: function() {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
When accepting revisions, allow users to accept on behalf of a subset of reviewers
Summary:
Ref T12271. Currenty, when you "Accept" a revision, you always accept it for all reviewers you have authority over.
There are some situations where communication can be more clear if users can accept as only themselves, or for only some packages, etc. T12271 discusses some of these use cases in more depth.
Instead of making "Accept" a blanket action, default it to doing what it does now but let the user uncheck reviewers.
In cases where project/package reviewers aren't in use, this doesn't change anything.
For now, "reject" still acts the old way (reject everything). We could make that use checkboxes too, but I'm not sure there's as much of a use case for it, and I generally want users who are blocking stuff to have more direct accountability in a product sense.
Test Plan:
- Accepted normally.
- Accepted a subset.
- Tried to accept none.
- Tried to accept bogus reviewers.
- Accepted with myself not a reviewer
- Accepted with only one reviewer (just got normal "this will be accepted" text).
{F4251255}
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T12271
Differential Revision: https://secure.phabricator.com/D17533
2017-03-22 17:28:36 +01:00
|
|
|
_newCheckboxes: function(spec) {
|
|
|
|
var checkboxes = [];
|
|
|
|
var checkbox_list = [];
|
|
|
|
for (var ii = 0; ii < spec.keys.length; ii++) {
|
|
|
|
var key = spec.keys[ii];
|
|
|
|
var checkbox_id = 'checkbox-' + Math.floor(Math.random() * 1000000);
|
|
|
|
|
|
|
|
var checkbox = JX.$N(
|
|
|
|
'input',
|
|
|
|
{
|
|
|
|
type: 'checkbox',
|
|
|
|
value: key,
|
|
|
|
id: checkbox_id
|
|
|
|
});
|
|
|
|
|
|
|
|
checkboxes.push(checkbox);
|
|
|
|
|
|
|
|
var label = JX.$N(
|
|
|
|
'label',
|
|
|
|
{
|
|
|
|
className: 'phuix-form-checkbox-label',
|
|
|
|
htmlFor: checkbox_id
|
|
|
|
},
|
|
|
|
JX.$H(spec.labels[key] || ''));
|
|
|
|
|
|
|
|
var display = JX.$N(
|
|
|
|
'div',
|
|
|
|
{
|
|
|
|
className: 'phuix-form-checkbox-item'
|
|
|
|
},
|
|
|
|
[checkbox, label]);
|
|
|
|
|
|
|
|
checkbox_list.push(display);
|
|
|
|
}
|
|
|
|
|
|
|
|
var node = JX.$N(
|
|
|
|
'div',
|
|
|
|
{
|
|
|
|
className: 'phuix-form-checkbox-action'
|
|
|
|
},
|
|
|
|
checkbox_list);
|
|
|
|
|
|
|
|
var get_value = function() {
|
|
|
|
var list = [];
|
|
|
|
for (var ii = 0; ii < checkboxes.length; ii++) {
|
|
|
|
if (checkboxes[ii].checked) {
|
|
|
|
list.push(checkboxes[ii].value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
};
|
|
|
|
|
|
|
|
var set_value = function(value) {
|
|
|
|
value = value || [];
|
|
|
|
|
|
|
|
if (!value.length) {
|
|
|
|
value = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
var map = {};
|
|
|
|
var ii;
|
|
|
|
for (ii = 0; ii < value.length; ii++) {
|
|
|
|
map[value[ii]] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (ii = 0; ii < checkboxes.length; ii++) {
|
|
|
|
if (map.hasOwnProperty(checkboxes[ii].value)) {
|
|
|
|
checkboxes[ii].checked = 'checked';
|
|
|
|
} else {
|
|
|
|
checkboxes[ii].checked = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
set_value(spec.value);
|
|
|
|
|
|
|
|
return {
|
|
|
|
node: node,
|
|
|
|
get: get_value,
|
|
|
|
set: set_value
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2016-02-09 00:24:52 +01:00
|
|
|
_newPoints: function(spec) {
|
2018-01-31 19:37:38 +01:00
|
|
|
return this._newText(spec);
|
2018-01-10 20:23:55 +01:00
|
|
|
},
|
|
|
|
|
|
|
|
_newText: function(spec) {
|
2016-02-09 00:24:52 +01:00
|
|
|
var attrs = {
|
|
|
|
type: 'text',
|
|
|
|
value: spec.value
|
|
|
|
};
|
|
|
|
|
|
|
|
var node = JX.$N('input', attrs);
|
|
|
|
|
2016-04-06 14:59:09 +02:00
|
|
|
return {
|
|
|
|
node: node,
|
Restore bulk edit support for remarkup fields (description, add comment)
Summary:
Depends on D18866. Ref T13025. Fixes T12415. This makes the old "Add Comment" action work, and adds support for a new "Set description to" action (possibly, I could imagine "append description" being useful some day, maybe).
The implementation is just a `<textarea />`, not a whole fancy remarkup box with `[Bold] [Italic] ...` buttons, preview, typeaheads, etc. It would be nice to enrich this eventually but doing the rendering in pure JS is currently very involved.
This requires a little bit of gymnastics to get the transaction populated properly, and adds some extra validation since we need some code there anyway.
Test Plan:
- Changed the description of a task via bulk editor.
- Added a comment to a task via bulk editor.
Reviewers: amckinley
Reviewed By: amckinley
Maniphest Tasks: T13025, T12415
Differential Revision: https://secure.phabricator.com/D18867
2018-01-11 18:48:33 +01:00
|
|
|
get: function() {
|
|
|
|
return node.value;
|
|
|
|
},
|
|
|
|
set: function(value) {
|
|
|
|
node.value = value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
_newRemarkup: function(spec) {
|
|
|
|
var attrs = {};
|
|
|
|
|
|
|
|
// We could imagine a world where this renders a full remarkup control
|
|
|
|
// with all the hint buttons and client behaviors, but today much of that
|
|
|
|
// behavior is defined server-side and thus this isn't a world we
|
|
|
|
// currently live in.
|
|
|
|
|
|
|
|
var node = JX.$N('textarea', attrs);
|
|
|
|
node.value = spec.value || '';
|
|
|
|
|
|
|
|
return {
|
|
|
|
node: node,
|
2016-04-06 14:59:09 +02:00
|
|
|
get: function() {
|
|
|
|
return node.value;
|
|
|
|
},
|
|
|
|
set: function(value) {
|
|
|
|
node.value = value;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
|
|
|
_newOptgroups: function(spec) {
|
|
|
|
var value = spec.value || null;
|
|
|
|
|
|
|
|
var optgroups = [];
|
|
|
|
for (var ii = 0; ii < spec.groups.length; ii++) {
|
|
|
|
var group = spec.groups[ii];
|
|
|
|
var options = [];
|
|
|
|
for (var jj = 0; jj < group.options.length; jj++) {
|
|
|
|
var option = group.options[jj];
|
|
|
|
options.push(JX.$N('option', {value: option.key}, option.label));
|
|
|
|
|
|
|
|
if (option.selected && (value === null)) {
|
|
|
|
value = option.key;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
optgroups.push(JX.$N('optgroup', {label: group.label}, options));
|
|
|
|
}
|
|
|
|
|
|
|
|
var node = JX.$N('select', {}, optgroups);
|
|
|
|
node.value = value;
|
|
|
|
|
2015-12-04 16:56:03 +01:00
|
|
|
return {
|
|
|
|
node: node,
|
|
|
|
get: function() {
|
|
|
|
return node.value;
|
|
|
|
},
|
|
|
|
set: function(value) {
|
|
|
|
node.value = value;
|
|
|
|
}
|
|
|
|
};
|
2015-12-02 23:38:11 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|