Merge "Allows topic editing in the change view"
This commit is contained in:
@@ -18,6 +18,8 @@ limitations under the License.
|
||||
<link rel="import" href="../../../behaviors/rest-client-behavior.html">
|
||||
<link rel="import" href="../../shared/gr-account-link/gr-account-link.html">
|
||||
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
|
||||
<link rel="import" href="../../shared/gr-editable-label/gr-editable-label.html">
|
||||
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
|
||||
<link rel="import" href="../gr-reviewer-list/gr-reviewer-list.html">
|
||||
|
||||
<dom-module id="gr-change-metadata">
|
||||
@@ -117,7 +119,13 @@ limitations under the License.
|
||||
</section>
|
||||
<section>
|
||||
<span class="title">Topic</span>
|
||||
<span class="value">[[change.topic]]</span>
|
||||
<span class="value">
|
||||
<gr-editable-label
|
||||
value="{{change.topic}}"
|
||||
placeholder="[[_computeTopicPlaceholder(_topicReadOnly)]]"
|
||||
read-only="[[_topicReadOnly]]"
|
||||
on-changed="_handleTopicChanged"></gr-editable-label>
|
||||
</span>
|
||||
</section>
|
||||
<section class="strategy" hidden$="[[_computeHideStrategy(change)]]" hidden>
|
||||
<span class="title">Strategy</span>
|
||||
@@ -141,6 +149,7 @@ limitations under the License.
|
||||
</span>
|
||||
</section>
|
||||
</template>
|
||||
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||
</template>
|
||||
<script src="gr-change-metadata.js"></script>
|
||||
</dom-module>
|
||||
|
||||
@@ -38,6 +38,10 @@
|
||||
type: String,
|
||||
computed: '_computeWebLink(change, commitInfo, serverConfig)',
|
||||
},
|
||||
_topicReadOnly: {
|
||||
type: Boolean,
|
||||
computed: '_computeTopicReadOnly(mutable, change)',
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
@@ -102,5 +106,18 @@
|
||||
});
|
||||
return result;
|
||||
},
|
||||
|
||||
_handleTopicChanged: function(e, topic) {
|
||||
if (!topic.length) { topic = null; }
|
||||
this.$.restAPI.setChangeTopic(this.change.id, topic);
|
||||
},
|
||||
|
||||
_computeTopicReadOnly: function(mutable, change) {
|
||||
return !mutable || !change.actions.topic || !change.actions.topic.enabled;
|
||||
},
|
||||
|
||||
_computeTopicPlaceholder: function(_topicReadOnly) {
|
||||
return _topicReadOnly ? 'No Topic' : 'Click to add topic';
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
<!--
|
||||
Copyright (C) 2016 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
|
||||
<dom-module id="gr-editable-label">
|
||||
<template>
|
||||
<style>
|
||||
input {
|
||||
font: inherit;
|
||||
max-width: 8em;
|
||||
}
|
||||
label {
|
||||
color: #777;
|
||||
}
|
||||
label.editable {
|
||||
cursor: pointer;
|
||||
}
|
||||
label.editable.placeholder {
|
||||
color: #00f;
|
||||
text-decoration: underline;
|
||||
}
|
||||
</style>
|
||||
<input
|
||||
is="iron-input"
|
||||
id="input"
|
||||
hidden$="[[!editing]]"
|
||||
on-keydown="_handleInputKeydown"
|
||||
bind-value="{{_inputText}}">
|
||||
<label
|
||||
hidden$="[[editing]]"
|
||||
class$="[[_computeLabelClass(readOnly, value, placeholder)]]"
|
||||
on-tap="_open">[[_computeLabel(value, placeholder)]]</label>
|
||||
</template>
|
||||
<script src="gr-editable-label.js"></script>
|
||||
</dom-module>
|
||||
@@ -0,0 +1,104 @@
|
||||
// Copyright (C) 2016 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
Polymer({
|
||||
is: 'gr-editable-label',
|
||||
|
||||
/**
|
||||
* Fired when the value is changed.
|
||||
*
|
||||
* @event changed
|
||||
*/
|
||||
|
||||
properties: {
|
||||
editing: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
value: {
|
||||
type: String,
|
||||
notify: true,
|
||||
value: null,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
value: null,
|
||||
},
|
||||
readOnly: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
_inputText: String,
|
||||
},
|
||||
|
||||
_usePlaceholder: function(value, placeholder) {
|
||||
return (!value || !value.length) && placeholder;
|
||||
},
|
||||
|
||||
_computeLabel: function(value, placeholder) {
|
||||
if (this._usePlaceholder(value, placeholder)) {
|
||||
return placeholder;
|
||||
}
|
||||
return value;
|
||||
},
|
||||
|
||||
_open: function() {
|
||||
if (this.readOnly || this.editing) { return; }
|
||||
|
||||
this._inputText = this.value;
|
||||
this.editing = true;
|
||||
|
||||
this.async(function() {
|
||||
this.$.input.focus();
|
||||
this.$.input.setSelectionRange(0, this.$.input.value.length)
|
||||
});
|
||||
},
|
||||
|
||||
_save: function() {
|
||||
if (!this.editing) { return; };
|
||||
|
||||
this.value = this._inputText;
|
||||
this.editing = false;
|
||||
this.fire('changed', this.value);
|
||||
},
|
||||
|
||||
_cancel: function() {
|
||||
if (!this.editing) { return; }
|
||||
|
||||
this.editing = false;
|
||||
this._inputText = this.value;
|
||||
},
|
||||
|
||||
_handleInputKeydown: function(e) {
|
||||
if (e.keyCode === 13) { // Enter key
|
||||
e.preventDefault();
|
||||
this._save();
|
||||
} else if (e.keyCode === 27) { // Escape key
|
||||
e.preventDefault();
|
||||
this._cancel();
|
||||
}
|
||||
},
|
||||
|
||||
_computeLabelClass: function(readOnly, value, placeholder) {
|
||||
var classes = [];
|
||||
if (!readOnly) { classes.push('editable'); }
|
||||
if (this._usePlaceholder(value, placeholder)) {
|
||||
classes.push('placeholder');
|
||||
}
|
||||
return classes.join(' ');
|
||||
},
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,130 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (C) 2016 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>gr-editable-label</title>
|
||||
|
||||
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
|
||||
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
||||
<script src="../../../bower_components/iron-test-helpers/mock-interactions.js"></script>
|
||||
|
||||
<link rel="import" href="gr-editable-label.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-editable-label
|
||||
value="value text"
|
||||
placeholder="label text"></gr-editable-label>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<test-fixture id="read-only">
|
||||
<template>
|
||||
<gr-editable-label
|
||||
read-only
|
||||
value="value text"
|
||||
placeholder="label text"></gr-editable-label>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-linked-text tests', function() {
|
||||
var element;
|
||||
var input;
|
||||
var label;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('basic');
|
||||
|
||||
input = element.$$('input');
|
||||
label = element.$$('label');
|
||||
});
|
||||
|
||||
test('element render', function() {
|
||||
// The input is hidden and the label is visible:
|
||||
assert.isNotNull(input.getAttribute('hidden'));
|
||||
assert.isNull(label.getAttribute('hidden'));
|
||||
|
||||
assert.isTrue(label.classList.contains('editable'));
|
||||
|
||||
assert.equal(label.textContent, 'value text');
|
||||
|
||||
MockInteractions.tap(label);
|
||||
|
||||
Polymer.dom.flush();
|
||||
|
||||
// The input is visible and the label is hidden:
|
||||
assert.isNull(input.getAttribute('hidden'));
|
||||
assert.isNotNull(label.getAttribute('hidden'));
|
||||
|
||||
assert.equal(input.value, 'value text');
|
||||
});
|
||||
|
||||
test('edit value', function(done) {
|
||||
var editedStub = sinon.stub();
|
||||
element.addEventListener('changed', editedStub);
|
||||
|
||||
MockInteractions.tap(label);
|
||||
|
||||
Polymer.dom.flush();
|
||||
|
||||
element._inputText = 'new text';
|
||||
|
||||
assert.isFalse(editedStub.called);
|
||||
|
||||
element.async(function() {
|
||||
assert.isTrue(editedStub.called);
|
||||
assert.equal(input.value, 'new text');
|
||||
done();
|
||||
});
|
||||
|
||||
// Press enter:
|
||||
MockInteractions.keyDownOn(input, 13);
|
||||
});
|
||||
});
|
||||
|
||||
suite('gr-linked-text tests', function() {
|
||||
var element;
|
||||
var input;
|
||||
var label;
|
||||
|
||||
setup(function() {
|
||||
element = fixture('read-only');
|
||||
|
||||
input = element.$$('input');
|
||||
label = element.$$('label');
|
||||
});
|
||||
|
||||
test('disallows edit when read-only', function() {
|
||||
// The input is hidden and the label is visible:
|
||||
assert.isNotNull(input.getAttribute('hidden'));
|
||||
assert.isNull(label.getAttribute('hidden'));
|
||||
|
||||
MockInteractions.tap(label);
|
||||
|
||||
Polymer.dom.flush();
|
||||
|
||||
// The input is still hidden and the label is still visible:
|
||||
assert.isNotNull(input.getAttribute('hidden'));
|
||||
assert.isNull(label.getAttribute('hidden'));
|
||||
});
|
||||
|
||||
test('label is not marked as editable', function() {
|
||||
assert.isFalse(label.classList.contains('editable'));
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -761,5 +761,10 @@
|
||||
return {baseImage: baseImage, revisionImage: revisionImage};
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
setChangeTopic: function(changeNum, topic) {
|
||||
return this.send('PUT', '/changes/' + encodeURIComponent(changeNum) +
|
||||
'/topic', {topic: topic});
|
||||
},
|
||||
});
|
||||
})();
|
||||
|
||||
@@ -61,6 +61,7 @@ limitations under the License.
|
||||
'shared/gr-cursor-manager/gr-cursor-manager_test.html',
|
||||
'shared/gr-date-formatter/gr-date-formatter_test.html',
|
||||
'shared/gr-js-api-interface/gr-js-api-interface_test.html',
|
||||
'shared/gr-editable-label/gr-editable-label_test.html',
|
||||
'shared/gr-linked-text/gr-linked-text_test.html',
|
||||
'shared/gr-rest-api-interface/gr-rest-api-interface_test.html',
|
||||
'shared/gr-storage/gr-storage_test.html',
|
||||
|
||||
Reference in New Issue
Block a user