Update iron-input to 2.0

This version is compatible with Polymer 1 and Polymer 2, but required
for Polymer 2.

Elements that were formerly
<input is="iron-input>

are now
<iron-input>
  <input>
</iron-input>

There are a few scenarios in which inputs were not using two way data
binding, which is the reason for using iron-input, and those have been
modified back to a native input.

With the updated iron-input to access the native input, there is an
'inputElement' getter function, which is used heavily in this update.

Also of note, in many tests, it is required to wrap Polymer.Base.async,
which is necessary because the mutation observer is async:

https://github.com/PolymerElements/iron-input/blob/master/test/iron-input.html

Also modifies polylint_test to explicitly ignore bower_components.

Change-Id: I75f7fa1bb0c00837f631f6e1043e15a3270b9bce
This commit is contained in:
Becky Siegel
2017-07-13 11:43:59 -07:00
parent d639e851cf
commit 37636a6256
38 changed files with 499 additions and 399 deletions

View File

@@ -1062,8 +1062,8 @@ bower_archive(
bower_archive( bower_archive(
name = "iron-input", name = "iron-input",
package = "polymerelements/iron-input", package = "polymerelements/iron-input",
sha1 = "9bc0c8e81de2527125383cbcf74dd9f27e7fa9ac", sha1 = "42f233d8adf3883bcce2fa364c7785a5d2571db4",
version = "1.0.10", version = "2.0.0",
) )
bower_archive( bower_archive(

View File

@@ -25,8 +25,8 @@ def load_bower_archives():
bower_archive( bower_archive(
name = "iron-a11y-announcer", name = "iron-a11y-announcer",
package = "iron-a11y-announcer", package = "iron-a11y-announcer",
version = "1.0.5", version = "2.0.0",
sha1 = "007902c041dd8863a1fe893f62450852f4d8c69b") sha1 = "8a7cc8d63eab3c068e0f8fcf4bf129a85922edc6")
bower_archive( bower_archive(
name = "iron-a11y-keys-behavior", name = "iron-a11y-keys-behavior",
package = "iron-a11y-keys-behavior", package = "iron-a11y-keys-behavior",
@@ -35,38 +35,38 @@ def load_bower_archives():
bower_archive( bower_archive(
name = "iron-behaviors", name = "iron-behaviors",
package = "iron-behaviors", package = "iron-behaviors",
version = "1.0.17", version = "1.0.18",
sha1 = "47df7e1c2b97978dcafa13edb50fbdb702570acd") sha1 = "e231a1a02b090f5183db917639fdb96cdd0dca18")
bower_archive( bower_archive(
name = "iron-fit-behavior", name = "iron-fit-behavior",
package = "iron-fit-behavior", package = "iron-fit-behavior",
version = "1.2.6", version = "1.2.7",
sha1 = "59daa8526aac59aa72b8edcbbd24d9eed555a0f5") sha1 = "01c485fbf898307029bbb72ac7e132db1570a842")
bower_archive( bower_archive(
name = "iron-flex-layout", name = "iron-flex-layout",
package = "iron-flex-layout", package = "iron-flex-layout",
version = "1.3.2", version = "1.3.7",
sha1 = "b896041aad049a5e889a0165828d7b1262e32612") sha1 = "4d4cf3232cf750a17a7df0a37476117f831ac633")
bower_archive( bower_archive(
name = "iron-form-element-behavior", name = "iron-form-element-behavior",
package = "iron-form-element-behavior", package = "iron-form-element-behavior",
version = "1.0.6", version = "1.0.7",
sha1 = "8d9e6530edc1b99bec1a5c34853911fba3701220") sha1 = "7b5a79e02cc32f0918725dd26925d0df1e03ed12")
bower_archive( bower_archive(
name = "iron-meta", name = "iron-meta",
package = "iron-meta", package = "iron-meta",
version = "1.1.2", version = "1.1.3",
sha1 = "dc22fe05e1cb5f94f30a7193d3433ca1808773b8") sha1 = "f77eba3f6f6817f10bda33918bde8f963d450041")
bower_archive( bower_archive(
name = "iron-resizable-behavior", name = "iron-resizable-behavior",
package = "iron-resizable-behavior", package = "iron-resizable-behavior",
version = "1.0.5", version = "1.0.6",
sha1 = "2ebe983377dceb3794dd335131050656e23e2beb") sha1 = "719c2a8a1a784f8aefcdeef41fcc2e5a03518d9e")
bower_archive( bower_archive(
name = "iron-validatable-behavior", name = "iron-validatable-behavior",
package = "iron-validatable-behavior", package = "iron-validatable-behavior",
version = "1.1.1", version = "1.1.2",
sha1 = "480423380be0536f948735d91bc472f6e7ced5b4") sha1 = "7111f34ff32e1510131dfbdb1eaa51bfa291e8be")
bower_archive( bower_archive(
name = "lodash", name = "lodash",
package = "lodash", package = "lodash",
@@ -75,18 +75,18 @@ def load_bower_archives():
bower_archive( bower_archive(
name = "mocha", name = "mocha",
package = "mocha", package = "mocha",
version = "3.2.0", version = "3.4.2",
sha1 = "b77f23f7ad1f1363501bcae96f0f4f47745dad0f") sha1 = "dfa9fd7705c541e8df3bfa22ca83789920024258")
bower_archive( bower_archive(
name = "neon-animation", name = "neon-animation",
package = "neon-animation", package = "neon-animation",
version = "1.2.4", version = "1.2.5",
sha1 = "e8ccbb930c4b7ff470b1450baa901618888a7fd3") sha1 = "588d289f779d02b21ce5b676e257bbd6155649e8")
bower_archive( bower_archive(
name = "sinon-chai", name = "sinon-chai",
package = "sinon-chai", package = "sinon-chai",
version = "2.8.0", version = "2.11.0",
sha1 = "0464b5d944fdf8116bb23e0b02ecfbac945b3517") sha1 = "3facb0ee3d4e06b8cd444c76e2fcb6d8b2ae3091")
bower_archive( bower_archive(
name = "sinonjs", name = "sinonjs",
package = "sinonjs", package = "sinonjs",
@@ -100,8 +100,8 @@ def load_bower_archives():
bower_archive( bower_archive(
name = "web-animations-js", name = "web-animations-js",
package = "web-animations-js", package = "web-animations-js",
version = "2.2.2", version = "2.2.5",
sha1 = "6276a9f227da7d4ccaf77c202b50e174dd11a2c2") sha1 = "078116d92a15ec4def5ca2be2cd09b331efc1eb7")
bower_archive( bower_archive(
name = "webcomponentsjs", name = "webcomponentsjs",
package = "webcomponentsjs", package = "webcomponentsjs",

View File

@@ -167,12 +167,6 @@ def define_bower_components():
license = "//lib:LICENSE-page.js", license = "//lib:LICENSE-page.js",
seed = True, seed = True,
) )
bower_component(
name = "polymer",
license = "//lib:LICENSE-polymer",
deps = [ ":webcomponentsjs" ],
seed = True,
)
bower_component( bower_component(
name = "polymer-resin", name = "polymer-resin",
license = "//lib:LICENSE-polymer", license = "//lib:LICENSE-polymer",
@@ -182,6 +176,12 @@ def define_bower_components():
], ],
seed = True, seed = True,
) )
bower_component(
name = "polymer",
license = "//lib:LICENSE-polymer",
deps = [ ":webcomponentsjs" ],
seed = True,
)
bower_component( bower_component(
name = "promise-polyfill", name = "promise-polyfill",
license = "//lib:LICENSE-promise-polyfill", license = "//lib:LICENSE-promise-polyfill",

View File

@@ -38,10 +38,11 @@ limitations under the License.
<div id="form"> <div id="form">
<section> <section>
<span class="title">Group name</span> <span class="title">Group name</span>
<input <iron-input
is="iron-input"
id="groupNameInput" id="groupNameInput"
bind-value="{{_name}}"> bind-value="{{_name}}">
<input type="text">
</iron-input>
</section> </section>
</div> </div>
</div> </div>

View File

@@ -24,7 +24,7 @@
notify: true, notify: true,
value: false, value: false,
}, },
_name: Object, _name: String,
_groupCreated: { _groupCreated: {
type: Boolean, type: Boolean,
value: false, value: false,

View File

@@ -50,13 +50,14 @@ limitations under the License.
sandbox.restore(); sandbox.restore();
}); });
test('name is updated correctly', () => { test('name is updated correctly', done => {
assert.isFalse(element.hasNewGroupName); Polymer.Base.async(() => {
assert.isFalse(element.hasNewGroupName);
element.$.groupNameInput.bindValue = GROUP_NAME; element.$.groupNameInput.bindValue = GROUP_NAME;
assert.isTrue(element.hasNewGroupName);
assert.isTrue(element.hasNewGroupName); assert.deepEqual(element._name, GROUP_NAME);
assert.deepEqual(element._name, GROUP_NAME); done();
}, 1);
}); });
test('test for redirecting to group on successful creation', done => { test('test for redirecting to group on successful creation', done => {

View File

@@ -53,10 +53,11 @@ limitations under the License.
<div id="form"> <div id="form">
<section> <section>
<span class="title">Project name</span> <span class="title">Project name</span>
<input is="iron-input" <iron-input
id="projectNameInput" id="projectNameInput"
autocomplete="on"
bind-value="{{_projectConfig.name}}"> bind-value="{{_projectConfig.name}}">
<input autocomplete="on">
</iron-input>
</section> </section>
<section> <section>
<span class="title">Rights inherit from</span> <span class="title">Rights inherit from</span>

View File

@@ -170,12 +170,13 @@ limitations under the License.
<section> <section>
<span class="title">Maximum Git object size limit</span> <span class="title">Maximum Git object size limit</span>
<span class="value"> <span class="value">
<input <iron-input
id="maxGitObjSizeInput" id="maxGitObjSizeInput"
bind-value="{{_projectConfig.max_object_size_limit.configured_value}}" bind-value="{{_projectConfig.max_object_size_limit.configured_value}}">
is="iron-input" <input
type="text" type="text"
disabled$="[[_readOnly]]"> disabled$="[[_readOnly]]">
</iron-input>
</span> </span>
</section> </section>
<section> <section>

View File

@@ -194,7 +194,7 @@
}, },
_handleInputKeydown(e) { _handleInputKeydown(e) {
const input = e.detail.input; const input = e.detail.input.inputElement;
if (input.selectionStart !== input.selectionEnd || if (input.selectionStart !== input.selectionEnd ||
input.selectionStart !== 0) { input.selectionStart !== 0) {
return; return;

View File

@@ -329,42 +329,51 @@ limitations under the License.
}); });
suite('keyboard interactions', () => { suite('keyboard interactions', () => {
test('backspace at text input start removes last account', () => { test('backspace at text input start removes last account', done => {
const input = element.$.entry.$.input; Polymer.Base.async(() => {
sandbox.stub(element.$.entry, '_getReviewerSuggestions'); const autocomplete = element.$.entry.$.input;
sandbox.stub(input, '_updateSuggestions'); sandbox.stub(element.$.entry, '_getReviewerSuggestions');
sandbox.stub(element, '_computeRemovable').returns(true); sandbox.stub(autocomplete, '_updateSuggestions');
// Next line is a workaround for Firefix not moving cursor sandbox.stub(element, '_computeRemovable').returns(true);
// on input field update // Next line is a workaround for Firefix not moving cursor
assert.equal(input.$.input.selectionStart, 0); // on input field update
input.text = 'test'; assert.equal(autocomplete.$.input.inputElement.selectionStart, 0);
MockInteractions.focus(input.$.input); autocomplete.text = 'test';
flushAsynchronousOperations(); MockInteractions.focus(autocomplete.$.input.inputElement);
assert.equal(element.accounts.length, 2); flushAsynchronousOperations();
MockInteractions.pressAndReleaseKeyOn(input.$.input, 8); // Backspace assert.equal(element.accounts.length, 2);
assert.equal(element.accounts.length, 2); MockInteractions.pressAndReleaseKeyOn(
input.text = ''; autocomplete.$.input.inputElement, 8); // Backspace
MockInteractions.pressAndReleaseKeyOn(input.$.input, 8); // Backspace assert.equal(element.accounts.length, 2);
assert.equal(element.accounts.length, 1); autocomplete.text = '';
MockInteractions.pressAndReleaseKeyOn(
autocomplete.$.input.inputElement, 8); // Backspace
assert.equal(element.accounts.length, 1);
done();
}, 1);
}); });
test('arrow key navigation', () => { test('arrow key navigation', done => {
const input = element.$.entry.$.input; Polymer.Base.async(() => {
input.text = ''; const autocomplete = element.$.entry.$.input;
element.accounts = [makeAccount(), makeAccount()]; autocomplete.text = '';
MockInteractions.focus(input.$.input); element.accounts = [makeAccount(), makeAccount()];
flushAsynchronousOperations(); MockInteractions.focus(autocomplete.$.input);
const chips = element.accountChips; flushAsynchronousOperations();
const chipsOneSpy = sandbox.spy(chips[1], 'focus'); const chips = element.accountChips;
MockInteractions.pressAndReleaseKeyOn(input.$.input, 37); // Left const chipsOneSpy = sandbox.spy(chips[1], 'focus');
assert.isTrue(chipsOneSpy.called); MockInteractions.pressAndReleaseKeyOn(
const chipsZeroSpy = sandbox.spy(chips[0], 'focus'); autocomplete.$.input.inputElement, 37); // Left
MockInteractions.pressAndReleaseKeyOn(chips[1], 37); // Left assert.isTrue(chipsOneSpy.called);
assert.isTrue(chipsZeroSpy.called); const chipsZeroSpy = sandbox.spy(chips[0], 'focus');
MockInteractions.pressAndReleaseKeyOn(chips[0], 37); // Left MockInteractions.pressAndReleaseKeyOn(chips[1], 37); // Left
assert.isTrue(chipsZeroSpy.calledOnce); assert.isTrue(chipsZeroSpy.called);
MockInteractions.pressAndReleaseKeyOn(chips[0], 39); // Right MockInteractions.pressAndReleaseKeyOn(chips[0], 37); // Left
assert.isTrue(chipsOneSpy.calledTwice); assert.isTrue(chipsZeroSpy.calledOnce);
MockInteractions.pressAndReleaseKeyOn(chips[0], 39); // Right
assert.isTrue(chipsOneSpy.calledTwice);
done();
}, 1);
}); });
test('delete', done => { test('delete', done => {

View File

@@ -61,11 +61,11 @@ limitations under the License.
<label for="branchInput"> <label for="branchInput">
Cherry Pick to branch Cherry Pick to branch
</label> </label>
<input is="iron-input" <iron-input
type="text"
id="branchInput" id="branchInput"
bind-value="{{branch}}" bind-value="{{branch}}">
placeholder="Destination branch"> <input type="text" placeholder="Destination branch">
</iron-input>
<label for="messageInput"> <label for="messageInput">
Cherry Pick Commit Message Cherry Pick Commit Message
</label> </label>

View File

@@ -98,12 +98,12 @@ limitations under the License.
</label> </label>
</div> </div>
<div class="parentRevisionContainer"> <div class="parentRevisionContainer">
<input is="iron-input" <iron-input
type="text"
id="parentInput" id="parentInput"
bind-value="{{base}}" bind-value="{{base}}"
on-tap="_handleEnterChangeNumberTap" on-tap="_handleEnterChangeNumberTap">
placeholder="Change number"> <input type="text" placeholder="Change number">
</iron-input>
</div> </div>
</div> </div>
</gr-confirm-dialog> </gr-confirm-dialog>

View File

@@ -391,10 +391,14 @@
.focus.bind(textarea.getNativeTextarea())); .focus.bind(textarea.getNativeTextarea()));
} else if (section === FocusTarget.REVIEWERS) { } else if (section === FocusTarget.REVIEWERS) {
const reviewerEntry = this.$.reviewers.focusStart; const reviewerEntry = this.$.reviewers.focusStart;
reviewerEntry.async(reviewerEntry.focus); Polymer.Base.async(() => {
reviewerEntry.inputElement.focus();
}, 1);
} else if (section === FocusTarget.CCS) { } else if (section === FocusTarget.CCS) {
const ccEntry = this.$$('#ccs').focusStart; const ccEntry = this.$$('#ccs').focusStart;
ccEntry.async(ccEntry.focus); Polymer.Base.async(() => {
ccEntry.inputElement.focus();
}, 1);
} }
}, },

View File

@@ -267,6 +267,14 @@ limitations under the License.
}); });
} }
function testAsync(testFunc) {
return new Promise(resolve => {
Polymer.Base.async(() => {
resolve(testFunc());
}, 1);
});
}
function testConfirmationDialog(done, cc) { function testConfirmationDialog(done, cc) {
const yesButton = const yesButton =
element.$$('.reviewerConfirmationButtons gr-button:first-child'); element.$$('.reviewerConfirmationButtons gr-button:first-child');
@@ -318,55 +326,59 @@ limitations under the License.
MockInteractions.tap(noButton); // close the overlay MockInteractions.tap(noButton); // close the overlay
return observer; return observer;
}).then(() => { }).then(() => {
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay)); return testAsync(() => {
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
// We should be focused on account entry input. // We should be focused on account entry input.
assert.equal(getActiveElement().id, 'input'); assert.equal(getActiveElement().tagName, 'INPUT');
// No reviewer/CC should have been added. // No reviewer/CC should have been added.
assert.equal(element.$$('#ccs').additions().length, 0); assert.equal(element.$$('#ccs').additions().length, 0);
assert.equal(element.$.reviewers.additions().length, 0); assert.equal(element.$.reviewers.additions().length, 0);
// Reopen confirmation dialog. // Reopen confirmation dialog.
observer = overlayObserver('opened'); observer = overlayObserver('opened');
if (cc) { if (cc) {
element._ccPendingConfirmation = { element._ccPendingConfirmation = {
group, group,
count: 10, count: 10,
}; };
} else { } else {
element._reviewerPendingConfirmation = { element._reviewerPendingConfirmation = {
group, group,
count: 10, count: 10,
}; };
} }
return observer; return observer;
}).then(() => { });
}).then(x => {
assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay)); assert.isTrue(isVisible(element.$.reviewerConfirmationOverlay));
observer = overlayObserver('closed'); observer = overlayObserver('closed');
MockInteractions.tap(yesButton); // Confirm the group. MockInteractions.tap(yesButton); // Confirm the group.
return observer; return observer;
}).then(() => { }).then(() => {
assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay)); return testAsync(() => {
const additions = cc ? assert.isFalse(isVisible(element.$.reviewerConfirmationOverlay));
element.$$('#ccs').additions() : const additions = cc ?
element.$.reviewers.additions(); element.$$('#ccs').additions() :
assert.deepEqual( element.$.reviewers.additions();
additions, assert.deepEqual(
[ additions,
{ [
group: { {
id: 'id', group: {
name: 'name', id: 'id',
confirmed: true, name: 'name',
_group: true, confirmed: true,
_pendingAdd: true, _group: true,
_pendingAdd: true,
},
}, },
}, ]);
]);
// We should be focused on account entry input. // We should be focused on account entry input.
assert.equal(getActiveElement().id, 'input'); assert.equal(getActiveElement().tagName, 'INPUT');
});
}).then(done); }).then(done);
} }

View File

@@ -65,35 +65,47 @@ limitations under the License.
}); });
test('enter in search input triggers nav', done => { test('enter in search input triggers nav', done => {
sinon.stub(page, 'show', () => { Polymer.Base.async(() => {
page.show.restore(); sinon.stub(page, 'show', () => {
assert.notEqual(getActiveElement(), element.$.searchInput); page.show.restore();
assert.notEqual(getActiveElement(), element.$.searchButton); assert.notEqual(getActiveElement(), element.$.searchInput);
assert.notEqual(getActiveElement(), element.$.searchButton);
done();
});
element.value = 'test';
MockInteractions.pressAndReleaseKeyOn(
element.$.searchInput.$.input.inputElement, 13,
null, 'enter');
}, 1);
});
test('search query should be double-escaped', done => {
Polymer.Base.async(() => {
const showStub = sinon.stub(page, 'show');
element.$.searchInput.text = 'fate/stay';
MockInteractions.pressAndReleaseKeyOn(
element.$.searchInput.$.input.inputElement, 13,
null, 'enter');
assert.equal(showStub.lastCall.args[0], '/q/fate%252Fstay');
showStub.restore();
done(); done();
}); }, 1);
element.value = 'test';
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13,
null, 'enter');
}); });
test('search query should be double-escaped', () => { test('input blurred after commit', done => {
const showStub = sinon.stub(page, 'show'); Polymer.Base.async(() => {
element.$.searchInput.text = 'fate/stay'; const showStub = sinon.stub(page, 'show');
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13, const blurSpy = sinon.spy(
null, 'enter'); element.$.searchInput.$.input, 'blur');
assert.equal(showStub.lastCall.args[0], '/q/fate%252Fstay'); element.$.searchInput.text = 'fate/stay';
showStub.restore(); MockInteractions.pressAndReleaseKeyOn(
}); element.$.searchInput.$.input.inputElement, 13,
null, 'enter');
test('input blurred after commit', () => { assert.isTrue(blurSpy.called);
const showStub = sinon.stub(page, 'show'); showStub.restore();
const blurSpy = sinon.spy(element.$.searchInput.$.input, 'blur'); blurSpy.restore();
element.$.searchInput.text = 'fate/stay'; done();
MockInteractions.pressAndReleaseKeyOn(element.$.searchInput.$.input, 13, }, 1);
null, 'enter');
assert.isTrue(blurSpy.called);
showStub.restore();
blurSpy.restore();
}); });
test('empty search query does not trigger nav', () => { test('empty search query does not trigger nav', () => {
@@ -104,12 +116,14 @@ limitations under the License.
assert.isFalse(showSpy.called); assert.isFalse(showSpy.called);
}); });
test('keyboard shortcuts', () => { test('keyboard shortcuts', done => {
const focusSpy = sinon.spy(element.$.searchInput, 'focus'); Polymer.Base.async(() => {
const selectAllSpy = sinon.spy(element.$.searchInput, 'selectAll'); const focusSpy = sinon.spy(element.$.searchInput, 'focus');
MockInteractions.pressAndReleaseKeyOn(document.body, 191, null, '/'); const selectAllSpy = sinon.spy(element.$.searchInput, 'selectAll');
assert.isTrue(focusSpy.called); MockInteractions.pressAndReleaseKeyOn(document.body, 191, null, '/');
assert.isTrue(selectAllSpy.called); assert.isTrue(focusSpy.called);
assert.isTrue(selectAllSpy.called); done();
}, 1);
}); });
suite('_getSearchSuggestions', () => { suite('_getSearchSuggestions', () => {

View File

@@ -93,49 +93,58 @@ limitations under the License.
</div> </div>
<div class="pref"> <div class="pref">
<label for="lineWrappingInput">Fit to screen</label> <label for="lineWrappingInput">Fit to screen</label>
<input <input type="checkbox"
is="iron-input"
type="checkbox"
id="lineWrappingInput" id="lineWrappingInput"
on-tap="_handlelineWrappingTap"> on-tap="_handlelineWrappingTap">
</div> </div>
<div class="pref" id="columnsPref" <div class="pref" id="columnsPref"
hidden$="[[_newPrefs.line_wrapping]]"> hidden$="[[_newPrefs.line_wrapping]]">
<label for="columnsInput">Diff width</label> <label for="columnsInput">Diff width</label>
<input is="iron-input" type="number" id="columnsInput" <iron-input
prevent-invalid-input id="columnsInput"
allowed-pattern="[0-9]" bind-value="{{_newPrefs.line_length}}"
bind-value="{{_newPrefs.line_length}}"> allowed-pattern="[0-9]">
<input type="number">
</iron-input>
</div> </div>
<div class="pref"> <div class="pref">
<label for="tabSizeInput">Tab width</label> <label for="tabSizeInput">Tab width</label>
<input is="iron-input" type="number" id="tabSizeInput" <iron-input
prevent-invalid-input id="tabSizeInput"
allowed-pattern="[0-9]" allowed-pattern="[0-9]"
bind-value="{{_newPrefs.tab_size}}"> bind-value="{{_newPrefs.tab_size}}">
<input type="number">
</iron-input>
</div> </div>
<div class="pref" hidden$="[[!_newPrefs.font_size]]"> <div class="pref" hidden$="[[!_newPrefs.font_size]]">
<label for="fontSizeInput">Font size</label> <label for="fontSizeInput">Font size</label>
<input is="iron-input" type="number" id="fontSizeInput" <iron-input
prevent-invalid-input id="fontSizeInput"
allowed-pattern="[0-9]" allowed-pattern="[0-9]"
bind-value="{{_newPrefs.font_size}}"> bind-value="{{_newPrefs.font_size}}">
<input type="number">
</iron-input>
</div> </div>
<div class="pref"> <div class="pref">
<label for="showTabsInput">Show tabs</label> <label for="showTabsInput">Show tabs</label>
<input is="iron-input" type="checkbox" id="showTabsInput" <input
type="checkbox"
id="showTabsInput"
on-tap="_handleShowTabsTap"> on-tap="_handleShowTabsTap">
</div> </div>
<div class="pref"> <div class="pref">
<label for="showTrailingWhitespaceInput"> <label for="showTrailingWhitespaceInput">
Show trailing whitespace</label> Show trailing whitespace</label>
<input is="iron-input" type="checkbox" <input
id="showTrailingWhitespaceInput" id="showTrailingWhitespaceInput"
type="checkbox"
on-tap="_handleShowTrailingWhitespaceTap"> on-tap="_handleShowTrailingWhitespaceTap">
</div> </div>
<div class="pref"> <div class="pref">
<label for="syntaxHighlightInput">Syntax highlighting</label> <label for="syntaxHighlightInput">Syntax highlighting</label>
<input is="iron-input" type="checkbox" id="syntaxHighlightInput" <input
id="syntaxHighlightInput"
type="checkbox"
on-tap="_handleSyntaxHighlightTap"> on-tap="_handleSyntaxHighlightTap">
</div> </div>
</div> </div>

View File

@@ -45,36 +45,39 @@ limitations under the License.
sandbox.restore(); sandbox.restore();
}); });
test('model changes', () => { test('model changes', done => {
element.prefs = { Polymer.Base.async(() => {
context: 10, element.prefs = {
font_size: 12, context: 10,
line_length: 100, font_size: 12,
show_tabs: true, line_length: 100,
tab_size: 8, show_tabs: true,
show_whitespace_errors: true, tab_size: 8,
syntax_highlighting: true, show_whitespace_errors: true,
}; syntax_highlighting: true,
assert.deepEqual(element.prefs, element._newPrefs); };
assert.deepEqual(element.prefs, element._newPrefs);
element.$.contextSelect.value = '50'; element.$.contextSelect.value = '50';
element.fire('change', {}, {node: element.$.contextSelect}); element.fire('change', {}, {node: element.$.contextSelect});
element.$.columnsInput.bindValue = 80; element.$.columnsInput.bindValue = 80;
element.$.fontSizeInput.bindValue = 10; element.$.fontSizeInput.bindValue = 10;
element.$.tabSizeInput.bindValue = 4; element.$.tabSizeInput.bindValue = 4;
MockInteractions.tap(element.$.showTabsInput); MockInteractions.tap(element.$.showTabsInput);
MockInteractions.tap(element.$.showTrailingWhitespaceInput); MockInteractions.tap(element.$.showTrailingWhitespaceInput);
MockInteractions.tap(element.$.syntaxHighlightInput); MockInteractions.tap(element.$.syntaxHighlightInput);
MockInteractions.tap(element.$.lineWrappingInput); MockInteractions.tap(element.$.lineWrappingInput);
assert.equal(element._newPrefs.context, 50); assert.equal(element._newPrefs.context, 50);
assert.equal(element._newPrefs.font_size, 10); assert.equal(element._newPrefs.font_size, 10);
assert.equal(element._newPrefs.line_length, 80); assert.equal(element._newPrefs.line_length, 80);
assert.equal(element._newPrefs.tab_size, 4); assert.equal(element._newPrefs.tab_size, 4);
assert.isFalse(element._newPrefs.show_tabs); assert.isFalse(element._newPrefs.show_tabs);
assert.isFalse(element._newPrefs.show_whitespace_errors); assert.isFalse(element._newPrefs.show_whitespace_errors);
assert.isTrue(element._newPrefs.line_wrapping); assert.isTrue(element._newPrefs.line_wrapping);
assert.isFalse(element._newPrefs.syntax_highlighting); assert.isFalse(element._newPrefs.syntax_highlighting);
done();
}, 1);
}); });
test('clicking fit to screen hides line length input', () => { test('clicking fit to screen hides line length input', () => {

View File

@@ -16,6 +16,7 @@ limitations under the License.
<link rel="import" href="../../../bower_components/polymer/polymer.html"> <link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
<link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html"> <link rel="import" href="../../shared/gr-date-formatter/gr-date-formatter.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html"> <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
@@ -56,24 +57,25 @@ limitations under the License.
<span <span
hidden$="[[!mutable]]" hidden$="[[!mutable]]"
class="value"> class="value">
<input <iron-input
is="iron-input"
id="nameInput" id="nameInput"
disabled="[[_saving]]"
on-keydown="_handleKeydown"
bind-value="{{_account.name}}"> bind-value="{{_account.name}}">
<input disabled="[[_saving]]"
on-keydown="_handleKeydown">
</iron-input>
</span> </span>
</section> </section>
<section> <section>
<span class="title">Status</span> <span class="title">Status</span>
<span class="value"> <span class="value">
<input <iron-input
is="iron-input"
id="statusInput" id="statusInput"
disabled="[[_saving]]"
on-keydown="_handleKeydown"
bind-value="{{_account.status}}"> bind-value="{{_account.status}}">
</span> <input
disabled="[[_saving]]"
on-keydown="_handleKeydown">
</iron-input>
</span>
</section> </section>
</div> </div>
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface> <gr-rest-api-interface id="restAPI"></gr-rest-api-interface>

View File

@@ -128,23 +128,26 @@ limitations under the License.
}); });
test('name', done => { test('name', done => {
assert.isTrue(element.mutable); Polymer.Base.async(() => {
assert.isFalse(element.hasUnsavedChanges); assert.isTrue(element.mutable);
assert.isFalse(element.hasUnsavedChanges);
element.set('_account.name', 'new name'); element.set('_account.name', 'new name');
assert.isTrue(nameChangedSpy.called); assert.isTrue(nameChangedSpy.called);
assert.isFalse(statusChangedSpy.called); assert.isFalse(statusChangedSpy.called);
assert.isTrue(element.hasUnsavedChanges); assert.isTrue(element.hasUnsavedChanges);
MockInteractions.pressAndReleaseKeyOn(element.$.nameInput, 13); MockInteractions.pressAndReleaseKeyOn(
element.$.nameInput.inputElement, 13);
assert.isTrue(nameStub.called); assert.isTrue(nameStub.called);
assert.isFalse(statusStub.called); assert.isFalse(statusStub.called);
nameStub.lastCall.returnValue.then(() => { nameStub.lastCall.returnValue.then(() => {
assert.equal(nameStub.lastCall.args[0], 'new name'); assert.equal(nameStub.lastCall.args[0], 'new name');
done(); done();
}); });
}, 1);
}); });
test('status', done => { test('status', done => {

View File

@@ -15,7 +15,6 @@ limitations under the License.
--> -->
<link rel="import" href="../../../bower_components/polymer/polymer.html"> <link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
<link rel="import" href="../../shared/gr-button/gr-button.html"> <link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html"> <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html"> <link rel="import" href="../../../styles/shared-styles.html">
@@ -63,7 +62,6 @@ limitations under the License.
<td class="emailColumn">[[item.email]]</td> <td class="emailColumn">[[item.email]]</td>
<td class="preferredControl" on-tap="_handlePreferredControlTap"> <td class="preferredControl" on-tap="_handlePreferredControlTap">
<input <input
is="iron-input"
class="preferredRadio" class="preferredRadio"
type="radio" type="radio"
on-change="_handlePreferredChange" on-change="_handlePreferredChange"

View File

@@ -81,19 +81,22 @@ limitations under the License.
<tfoot> <tfoot>
<tr> <tr>
<th> <th>
<input <iron-input bind-value="{{_newName}}">
is="iron-input" <input
placeholder="New Title" type="text"
on-keydown="_handleInputKeydown" placeholder="New Title"
bind-value="{{_newName}}"> on-keydown="_handleInputKeydown">
</iron-input>
</th> </th>
<th> <th>
<input <iron-input
class="newUrlInput" class="newUrlInput"
is="iron-input"
placeholder="New URL"
on-keydown="_handleInputKeydown"
bind-value="{{_newUrl}}"> bind-value="{{_newUrl}}">
<input
type="text"
placeholder="New URL"
on-keydown="_handleInputKeydown">
</iron-input>
</th> </th>
<th></th> <th></th>
<th></th> <th></th>

View File

@@ -58,7 +58,7 @@
}, },
_computeAddDisabled(newName, newUrl) { _computeAddDisabled(newName, newUrl) {
return !newName.length || !newUrl.length; return !newName || !newUrl;
}, },
_handleInputKeydown(e) { _handleInputKeydown(e) {

View File

@@ -64,19 +64,22 @@ limitations under the License.
Polymer.dom.flush(); Polymer.dom.flush();
}); });
test('renders', () => { test('renders', done => {
const rows = element.$$('tbody').querySelectorAll('tr'); const rows = element.$$('tbody').querySelectorAll('tr');
let tds; let tds;
assert.equal(rows.length, menu.length); Polymer.Base.async(() => {
for (let i = 0; i < menu.length; i++) { assert.equal(rows.length, menu.length);
tds = rows[i].querySelectorAll('td'); for (let i = 0; i < menu.length; i++) {
assert.equal(tds[0].textContent, menu[i].name); tds = rows[i].querySelectorAll('td');
assert.equal(tds[1].textContent, menu[i].url); assert.equal(tds[0].textContent, menu[i].name);
} assert.equal(tds[1].textContent, menu[i].url);
}
assert.isTrue(element._computeAddDisabled(element._newName, assert.isTrue(element._computeAddDisabled(element._newName,
element._newUrl)); element._newUrl));
done();
}, 1);
}); });
test('_computeAddDisabled', () => { test('_computeAddDisabled', () => {
@@ -86,23 +89,27 @@ limitations under the License.
assert.isFalse(element._computeAddDisabled('name', 'url')); assert.isFalse(element._computeAddDisabled('name', 'url'));
}); });
test('add a new menu item', () => { test('add a new menu item', done => {
const newName = 'new name'; const newName = 'new name';
const newUrl = 'new url'; const newUrl = 'new url';
element._newName = newName; Polymer.Base.async(() => {
element._newUrl = newUrl; element._newName = newName;
assert.isFalse(element._computeAddDisabled(element._newName, element._newUrl = newUrl;
element._newUrl));
const originalMenuLength = element.menuItems.length; assert.isFalse(element._computeAddDisabled(element._newName,
element._newUrl));
element._handleAddButton(); const originalMenuLength = element.menuItems.length;
assert.equal(element.menuItems.length, originalMenuLength + 1); element._handleAddButton();
assert.equal(element.menuItems[element.menuItems.length - 1].name,
newName); assert.equal(element.menuItems.length, originalMenuLength + 1);
assert.equal(element.menuItems[element.menuItems.length - 1].url, newUrl); assert.equal(element.menuItems[element.menuItems.length - 1].name,
newName);
assert.equal(element.menuItems[element.menuItems.length - 1].url, newUrl);
done();
}, 1);
}); });
test('move items down', () => { test('move items down', () => {

View File

@@ -15,10 +15,11 @@ limitations under the License.
--> -->
<link rel="import" href="../../../bower_components/polymer/polymer.html"> <link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../styles/gr-form-styles.html"> <link rel="import" href="../../../styles/gr-form-styles.html">
<link rel="import" href="../../../styles/shared-styles.html">
<link rel="import" href="../../shared/gr-button/gr-button.html"> <link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html"> <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html">
<dom-module id="gr-registration-dialog"> <dom-module id="gr-registration-dialog">
<template> <template>
@@ -60,12 +61,11 @@ limitations under the License.
<hr> <hr>
<section> <section>
<div class="title">Full Name</div> <div class="title">Full Name</div>
<input <input
is="iron-input" id="name"
id="name" disabled="[[_saving]]"
bind-value="{{_account.name}}" on-keydown="_handleNameKeydown"
disabled="[[_saving]]" value="[[_account.name]]">
on-keydown="_handleNameKeydown">
</section> </section>
<section> <section>
<div class="title">Preferred Email</div> <div class="title">Preferred Email</div>

View File

@@ -220,34 +220,31 @@ limitations under the License.
<section id="columnsPref" hidden$="[[_diffPrefs.line_wrapping]]"> <section id="columnsPref" hidden$="[[_diffPrefs.line_wrapping]]">
<span class="title">Diff width</span> <span class="title">Diff width</span>
<span class="value"> <span class="value">
<input <iron-input
is="iron-input"
type="number"
prevent-invalid-input
allowed-pattern="[0-9]" allowed-pattern="[0-9]"
bind-value="{{_diffPrefs.line_length}}"> bind-value="{{_diffPrefs.line_length}}">
<input type="number">
</iron-input>
</span> </span>
</section> </section>
<section> <section>
<span class="title">Tab width</span> <span class="title">Tab width</span>
<span class="value"> <span class="value">
<input <iron-input
is="iron-input"
type="number"
prevent-invalid-input
allowed-pattern="[0-9]" allowed-pattern="[0-9]"
bind-value="{{_diffPrefs.tab_size}}"> bind-value="{{_diffPrefs.tab_size}}">
<input type="number">
</iron-input>
</span> </span>
</section> </section>
<section hidden$="[[!_diffPrefs.font_size]]"> <section hidden$="[[!_diffPrefs.font_size]]">
<span class="title">Font size</span> <span class="title">Font size</span>
<span class="value"> <span class="value">
<input <iron-input
is="iron-input" allowed-pattern="[0-9]"
type="number"
prevent-invalid-input
allowed-pattern="[0-9]"
bind-value="{{_diffPrefs.font_size}}"> bind-value="{{_diffPrefs.font_size}}">
<input type="number">
</iron-input>
</span> </span>
</section> </section>
<section> <section>
@@ -337,14 +334,15 @@ limitations under the License.
<section> <section>
<span class="title">New email address</span> <span class="title">New email address</span>
<span class="value"> <span class="value">
<input <iron-input
id="newEmailInput" id="newEmailInput"
bind-value="{{_newEmail}}" bind-value="{{_newEmail}}">
is="iron-input" <input
type="text" type="text"
disabled="[[_addingEmail]]" disabled="[[_addingEmail]]"
on-keydown="_handleNewEmailKeydown" on-keydown="_handleNewEmailKeydown"
placeholder="email@example.com"> placeholder="email@example.com">
</iron-input>
</span> </span>
</section> </section>
<section <section

View File

@@ -102,7 +102,6 @@ limitations under the License.
<input <input
id="newFilter" id="newFilter"
class="newFilterInput" class="newFilterInput"
is="iron-input"
placeholder="branch:name, or other search expression"> placeholder="branch:name, or other search expression">
</th> </th>
<th> <th>

View File

@@ -161,7 +161,7 @@ limitations under the License.
test('_handleAddProject', () => { test('_handleAddProject', () => {
element.$.newProject.value = {id: 'project d'}; element.$.newProject.value = {id: 'project d'};
element.$.newProject.setText('project d'); element.$.newProject.setText('project d');
element.$.newFilter.bindValue = ''; element.$.newFilter.value = '';
element._handleAddProject(); element._handleAddProject();
@@ -174,7 +174,7 @@ limitations under the License.
test('_handleAddProject with invalid inputs', () => { test('_handleAddProject with invalid inputs', () => {
element.$.newProject.value = {id: 'project b'}; element.$.newProject.value = {id: 'project b'};
element.$.newProject.setText('project b'); element.$.newProject.setText('project b');
element.$.newFilter.bindValue = 'filter 1'; element.$.newFilter.value = 'filter 1';
element._handleAddProject(); element._handleAddProject();

View File

@@ -23,32 +23,34 @@ limitations under the License.
<dom-module id="gr-autocomplete"> <dom-module id="gr-autocomplete">
<template> <template>
<style include="shared-styles"> <style include="shared-styles">
input { iron-input, input {
font-size: 1em; font-size: 1em;
height: 100%; height: 100%;
width: 100%; width: 100%;
}
iron-input {
@apply --gr-autocomplete; @apply --gr-autocomplete;
} }
input.borderless, iron-input.borderless input,
input.borderless:focus { iron-input.borderless:focus input {
border: none; border: none;
outline: none; outline: none;
} }
input.warnUncommitted { iron-input.warnUncommitted input {
color: red; color: red;
} }
</style> </style>
<input <iron-input id="input"
id="input"
class$="[[_computeClass(borderless)]]" class$="[[_computeClass(borderless)]]"
is="iron-input" bind-value="{{text}}">
disabled$="[[disabled]]" <input
bind-value="{{text}}" disabled$="[[disabled]]"
placeholder="[[placeholder]]" placeholder="[[placeholder]]"
on-keydown="_handleKeydown" on-keydown="_handleKeydown"
on-focus="_onInputFocus" on-focus="_onInputFocus"
on-blur="_onInputBlur" on-blur="_onInputBlur"
autocomplete="off" /> autocomplete="off" />
</iron-input>
<!-- This container is needed for Safari and Firefox --> <!-- This container is needed for Safari and Firefox -->
<div id="suggestionContainer"> <div id="suggestionContainer">
<gr-autocomplete-dropdown id="suggestions" <gr-autocomplete-dropdown id="suggestions"

View File

@@ -154,7 +154,8 @@
}, },
selectAll() { selectAll() {
this.$.input.setSelectionRange(0, this.$.input.value.length); this.$.input.inputElement.setSelectionRange(0,
this.$.input.bindValue.length);
}, },
clear() { clear() {

View File

@@ -100,12 +100,14 @@ limitations under the License.
const cancelHandler = sandbox.spy(); const cancelHandler = sandbox.spy();
element.addEventListener('cancel', cancelHandler); element.addEventListener('cancel', cancelHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 27, null, 'esc'); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 27,
null, 'esc');
assert.isFalse(cancelHandler.called); assert.isFalse(cancelHandler.called);
assert.isTrue(element.$.suggestions.hidden); assert.isTrue(element.$.suggestions.hidden);
assert.equal(element._suggestions.length, 0); assert.equal(element._suggestions.length, 0);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 27, null, 'esc'); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 27,
null, 'esc');
assert.isTrue(cancelHandler.called); assert.isTrue(cancelHandler.called);
done(); done();
}); });
@@ -137,22 +139,23 @@ limitations under the License.
assert.equal(element.$.suggestions.$.cursor.index, 0); assert.equal(element.$.suggestions.$.cursor.index, 0);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null, MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 40,
'down'); null, 'down');
assert.equal(element.$.suggestions.$.cursor.index, 1); assert.equal(element.$.suggestions.$.cursor.index, 1);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 40, null, MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 40,
'down'); null, 'down');
assert.equal(element.$.suggestions.$.cursor.index, 2); assert.equal(element.$.suggestions.$.cursor.index, 2);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 38, null, 'up'); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 38,
null, 'up');
assert.equal(element.$.suggestions.$.cursor.index, 1); assert.equal(element.$.suggestions.$.cursor.index, 1);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null, MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 13,
'enter'); null, 'enter');
assert.equal(element.value, 1); assert.equal(element.value, 1);
assert.isTrue(commitHandler.called); assert.isTrue(commitHandler.called);
@@ -175,8 +178,8 @@ limitations under the License.
const commitHandler = sandbox.spy(); const commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler); element.addEventListener('commit', commitHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null, MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 13,
'enter'); null, 'enter');
assert.isTrue(commitHandler.called); assert.isTrue(commitHandler.called);
assert.equal(element.text, 'suggestion'); assert.equal(element.text, 'suggestion');
@@ -197,8 +200,8 @@ limitations under the License.
const commitHandler = sandbox.spy(); const commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler); element.addEventListener('commit', commitHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null, MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 13,
'enter'); null, 'enter');
assert.isTrue(commitHandler.called); assert.isTrue(commitHandler.called);
assert.equal(element.text, ''); assert.equal(element.text, '');
@@ -248,8 +251,8 @@ limitations under the License.
const commitHandler = sandbox.spy(); const commitHandler = sandbox.spy();
element.addEventListener('commit', commitHandler); element.addEventListener('commit', commitHandler);
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null, MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 13,
'enter'); null, 'enter');
assert.isTrue(commitHandler.called); assert.isTrue(commitHandler.called);
assert.equal(element.text, 'blah 0'); assert.equal(element.text, 'blah 0');
@@ -267,14 +270,16 @@ limitations under the License.
element._suggestions = ['tunnel snakes rule!']; element._suggestions = ['tunnel snakes rule!'];
element.tabComplete = false; element.tabComplete = false;
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab'); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 9,
null, 'tab');
assert.isFalse(commitHandler.called); assert.isFalse(commitHandler.called);
assert.isFalse(commitSpy.called); assert.isFalse(commitSpy.called);
assert.isFalse(element._focused); assert.isFalse(element._focused);
element.tabComplete = true; element.tabComplete = true;
element._focused = true; element._focused = true;
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab'); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 9,
null, 'tab');
assert.isFalse(commitHandler.called); assert.isFalse(commitHandler.called);
assert.isTrue(commitSpy.called); assert.isTrue(commitSpy.called);
assert.isTrue(element._focused); assert.isTrue(element._focused);
@@ -307,8 +312,8 @@ limitations under the License.
test('enter does not call focus', () => { test('enter does not call focus', () => {
element._suggestions = ['sugar bombs']; element._suggestions = ['sugar bombs'];
focusSpy = sandbox.spy(element, 'focus'); focusSpy = sandbox.spy(element, 'focus');
MockInteractions.pressAndReleaseKeyOn(element.$.input, 13, null, MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 13,
'enter'); null, 'enter');
flushAsynchronousOperations(); flushAsynchronousOperations();
assert.isTrue(commitSpy.called); assert.isTrue(commitSpy.called);
@@ -320,7 +325,8 @@ limitations under the License.
element._suggestions = ['sugar bombs']; element._suggestions = ['sugar bombs'];
focusSpy = sandbox.spy(element, 'focus'); focusSpy = sandbox.spy(element, 'focus');
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab'); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 9,
null, 'tab');
flushAsynchronousOperations(); flushAsynchronousOperations();
assert.isFalse(commitSpy.called); assert.isFalse(commitSpy.called);
@@ -329,7 +335,8 @@ limitations under the License.
element.tabComplete = true; element.tabComplete = true;
element._suggestions = ['tunnel snakes drool']; element._suggestions = ['tunnel snakes drool'];
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab'); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 9,
null, 'tab');
flushAsynchronousOperations(); flushAsynchronousOperations();
assert.isTrue(commitSpy.called); assert.isTrue(commitSpy.called);
@@ -386,12 +393,16 @@ limitations under the License.
}); });
}); });
test('input-keydown event fired', () => { test('input-keydown event fired', done => {
const listener = sandbox.spy(); Polymer.Base.async(() => {
element.addEventListener('input-keydown', listener); const listener = sandbox.spy();
MockInteractions.pressAndReleaseKeyOn(element.$.input, 9, null, 'tab'); element.addEventListener('input-keydown', listener);
flushAsynchronousOperations(); MockInteractions.pressAndReleaseKeyOn(element.$.input.inputElement, 9,
assert.isTrue(listener.called); null, 'tab');
flushAsynchronousOperations();
assert.isTrue(listener.called);
done();
}, 1);
}); });
suite('warnUncommitted', () => { suite('warnUncommitted', () => {
@@ -400,27 +411,36 @@ limitations under the License.
inputClassList = element.$.input.classList; inputClassList = element.$.input.classList;
}); });
test('enabled', () => { test('enabled', done => {
element.warnUncommitted = true; Polymer.Base.async(() => {
element.text = 'blah blah blah'; element.warnUncommitted = true;
MockInteractions.blur(element.$.input); element.text = 'blah blah blah';
assert.isTrue(inputClassList.contains('warnUncommitted')); MockInteractions.blur(element.$.input.inputElement);
MockInteractions.focus(element.$.input); assert.isTrue(inputClassList.contains('warnUncommitted'));
assert.isFalse(inputClassList.contains('warnUncommitted')); MockInteractions.focus(element.$.input.inputElement);
assert.isFalse(inputClassList.contains('warnUncommitted'));
done();
}, 1);
}); });
test('disabled', () => { test('disabled', done => {
element.warnUncommitted = false; Polymer.Base.async(() => {
element.text = 'blah blah blah'; element.warnUncommitted = false;
MockInteractions.blur(element.$.input); element.text = 'blah blah blah';
assert.isFalse(inputClassList.contains('warnUncommitted')); MockInteractions.blur(element.$.input.inputElement);
assert.isFalse(inputClassList.contains('warnUncommitted'));
done();
}, 1);
}); });
test('no text', () => { test('no text', done => {
element.warnUncommitted = true; Polymer.Base.async(() => {
element.text = ''; element.warnUncommitted = true;
MockInteractions.blur(element.$.input); element.text = '';
assert.isFalse(inputClassList.contains('warnUncommitted')); MockInteractions.blur(element.$.input.inputElement);
assert.isFalse(inputClassList.contains('warnUncommitted'));
done();
}, 1);
}); });
}); });
}); });

View File

@@ -15,7 +15,6 @@ limitations under the License.
--> -->
<link rel="import" href="../../../bower_components/polymer/polymer.html"> <link rel="import" href="../../../bower_components/polymer/polymer.html">
<link rel="import" href="../../../bower_components/iron-input/iron-input.html">
<link rel="import" href="../../shared/gr-button/gr-button.html"> <link rel="import" href="../../shared/gr-button/gr-button.html">
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html"> <link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
<link rel="import" href="../../../styles/shared-styles.html"> <link rel="import" href="../../../styles/shared-styles.html">
@@ -46,12 +45,13 @@ limitations under the License.
</style> </style>
<div class="text"> <div class="text">
<label>[[title]]</label> <label>[[title]]</label>
<input id="input" is="iron-input" <input
class$="copyText [[_computeInputClass(hideInput)]]" id="input"
type="text" type="text"
bind-value="[[text]]"
on-tap="_handleInputTap" on-tap="_handleInputTap"
readonly> readonly
class$="copyText [[_computeInputClass(hideInput)]]"
value="[[text]]">
<gr-button id="button" <gr-button id="button"
class="copyToClipboard" class="copyToClipboard"
on-tap="_copyToClipboard"> on-tap="_copyToClipboard">

View File

@@ -45,11 +45,12 @@ limitations under the License.
text-decoration: underline; text-decoration: underline;
} }
</style> </style>
<input <iron-input
is="iron-input"
id="input" id="input"
hidden$="[[!editing]]" bind-value="{{_inputText}}"
bind-value="{{_inputText}}"> hidden$="[[!editing]]">
<input>
</iron-input>
<label <label
hidden$="[[editing]]" hidden$="[[editing]]"
class$="[[_computeLabelClass(readOnly, value, placeholder)]]" class$="[[_computeLabelClass(readOnly, value, placeholder)]]"

View File

@@ -76,8 +76,9 @@
this.editing = true; this.editing = true;
this.async(() => { this.async(() => {
this.$.input.focus(); this.$.input.inputElement.focus();
this.$.input.setSelectionRange(0, this.$.input.value.length); this.$.input.inputElement
.setSelectionRange(0, this.$.input.inputElement.value.length);
}); });
}, },
@@ -99,7 +100,7 @@
_handleEnter(e) { _handleEnter(e) {
e = this.getKeyboardEvent(e); e = this.getKeyboardEvent(e);
const target = Polymer.dom(e).rootTarget; const target = Polymer.dom(e).rootTarget;
if (target === this.$.input) { if (target === this.$.input.inputElement) {
e.preventDefault(); e.preventDefault();
this._save(); this._save();
} }

View File

@@ -54,7 +54,7 @@ limitations under the License.
setup(() => { setup(() => {
element = fixture('basic'); element = fixture('basic');
input = element.$$('input'); input = element.$$('iron-input');
label = element.$$('label'); label = element.$$('label');
sandbox = sinon.sandbox.create(); sandbox = sinon.sandbox.create();
}); });
@@ -63,46 +63,51 @@ limitations under the License.
sandbox.restore(); sandbox.restore();
}); });
test('element render', () => { test('element render', done => {
Polymer.Base.async(() => {
// The input is hidden and the label is visible: // The input is hidden and the label is visible:
assert.isNotNull(input.getAttribute('hidden')); assert.isNotNull(input.getAttribute('hidden'));
assert.isNull(label.getAttribute('hidden')); assert.isNull(label.getAttribute('hidden'));
assert.isTrue(label.classList.contains('editable')); assert.isTrue(label.classList.contains('editable'));
assert.equal(label.textContent, 'value text'); assert.equal(label.textContent, 'value text');
MockInteractions.tap(label); MockInteractions.tap(label);
Polymer.dom.flush(); Polymer.dom.flush();
// The input is visible and the label is hidden: // The input is visible and the label is hidden:
assert.isNull(input.getAttribute('hidden')); assert.isNull(input.getAttribute('hidden'));
assert.isNotNull(label.getAttribute('hidden')); assert.isNotNull(label.getAttribute('hidden'));
assert.equal(input.value, 'value text'); assert.equal(input.inputElement.value, 'value text');
done();
}, 1);
}); });
test('edit value', done => { test('edit value', done => {
const editedStub = sandbox.stub(); Polymer.Base.async(() => {
element.addEventListener('changed', editedStub); const editedStub = sandbox.stub();
element.addEventListener('changed', editedStub);
MockInteractions.tap(label); MockInteractions.tap(label);
Polymer.dom.flush(); Polymer.dom.flush();
element._inputText = 'new text'; element._inputText = 'new text';
assert.isFalse(editedStub.called); assert.isFalse(editedStub.called);
element.async(() => { element.async(() => {
assert.isTrue(editedStub.called); assert.isTrue(editedStub.called);
assert.equal(input.value, 'new text'); assert.equal(input.inputElement.value, 'new text');
done(); done();
}); });
// Press enter: // Press enter:
MockInteractions.keyDownOn(input, 13); MockInteractions.keyDownOn(input.inputElement, 13);
}, 1);
}); });
}); });
@@ -114,22 +119,25 @@ limitations under the License.
setup(() => { setup(() => {
element = fixture('read-only'); element = fixture('read-only');
input = element.$$('input'); input = element.$$('iron-input');
label = element.$$('label'); label = element.$$('label');
}); });
test('disallows edit when read-only', () => { test('disallows edit when read-only', done => {
Polymer.Base.async(() => {
// The input is hidden and the label is visible: // The input is hidden and the label is visible:
assert.isNotNull(input.getAttribute('hidden')); assert.isNotNull(input.getAttribute('hidden'));
assert.isNull(label.getAttribute('hidden')); assert.isNull(label.getAttribute('hidden'));
MockInteractions.tap(label); MockInteractions.tap(label);
Polymer.dom.flush(); Polymer.dom.flush();
// The input is still hidden and the label is still visible: // The input is still hidden and the label is still visible:
assert.isNotNull(input.getAttribute('hidden')); assert.isNotNull(input.getAttribute('hidden'));
assert.isNull(label.getAttribute('hidden')); assert.isNull(label.getAttribute('hidden'));
done();
}, 1);
}); });
test('label is not marked as editable', () => { test('label is not marked as editable', () => {

View File

@@ -57,10 +57,11 @@ limitations under the License.
<div id="topContainer"> <div id="topContainer">
<div> <div>
<label>Filter:</label> <label>Filter:</label>
<input is="iron-input" <iron-input
type="text"
id="filter" id="filter"
bind-value="{{filter}}"> bind-value="{{filter}}">
<input type="text">
</iron-input>
</div> </div>
<div id="createNewContainer" <div id="createNewContainer"
class$="[[_computeCreateClass(createNew)]]"> class$="[[_computeCreateClass(createNew)]]">

View File

@@ -17,4 +17,4 @@ fi
unzip polygerrit-ui/polygerrit_components.bower_components.zip -d polygerrit-ui/app unzip polygerrit-ui/polygerrit_components.bower_components.zip -d polygerrit-ui/app
${polylint_bin} --root polygerrit-ui/app --input elements/gr-app.html ${polylint_bin} --root polygerrit-ui/app --input elements/gr-app.html --b 'bower_components'

View File

@@ -97,6 +97,7 @@ limitations under the License.
--iron-autogrow-textarea: { --iron-autogrow-textarea: {
border: 1px solid #d1d2d3; border: 1px solid #d1d2d3;
border-radius: 2px; border-radius: 2px;
box-sizing: border-box;
font-size: 1em; font-size: 1em;
padding: .25em .15em 0 .15em; padding: .25em .15em 0 .15em;
} }
@@ -104,7 +105,6 @@ limitations under the License.
.gr-form-styles gr-autocomplete { .gr-form-styles gr-autocomplete {
border: none; border: none;
--gr-autocomplete: { --gr-autocomplete: {
border: 1px solid #d1d2d3;
border-radius: 2px; border-radius: 2px;
font-size: 1em; font-size: 1em;
height: 2em; height: 2em;

View File

@@ -32,6 +32,7 @@ limitations under the License.
padding: 0; padding: 0;
vertical-align: baseline; vertical-align: baseline;
} }
iron-input,
input, input,
iron-autogrow-textarea { iron-autogrow-textarea {
box-sizing: border-box; box-sizing: border-box;