Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Paper input #319

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
88d8fa8
paper-input: destructure Ember a la ES6.
DanChadwick Mar 22, 2016
bc1cd3b
paper-input: Move isTouched test out of validate(), allowing it to be…
DanChadwick Mar 22, 2016
e88252a
paper-input: Clean up textarea setup/teardown and remove jQuery event…
DanChadwick Mar 22, 2016
5756178
paper-input: Adjust actions to accept closures. Pass keyDown thur, li…
DanChadwick Mar 23, 2016
6a20f32
paper-input: validation theming. WIP.
DanChadwick Mar 23, 2016
5f86d59
paper-input: fix floating icon display.
DanChadwick Mar 23, 2016
aeef43a
paper-input: Backport required asterisk form angular-material-source …
DanChadwick Mar 23, 2016
79b3e0f
paper-input: Fix camelCase capitalization typo in onKeyDown.
DanChadwick Mar 23, 2016
17ece3d
paper-input: Update validation theming.
DanChadwick Mar 23, 2016
5a94f0a
paper-input: Use a computed property for validations. Allow multiple …
DanChadwick Mar 23, 2016
a702126
paper-input: merge built-in validations with custom code validations.
DanChadwick Mar 23, 2016
6774a7d
paper-input: Support external validation messages.
DanChadwick Mar 24, 2016
e53fee4
paper-input: Fix indenting and style in documentation page.
DanChadwick Mar 24, 2016
c2cb207
paper-input: Implement event actions.
DanChadwick Mar 24, 2016
cc8b6f0
paper-input: Change attr- to passThru.
DanChadwick Mar 24, 2016
00f548d
paper-input: Update dummy app for change from 'attr-' to 'passThru.'.
DanChadwick Mar 24, 2016
f7c8246
paper-input: Support required="style" for style-only required (no val…
DanChadwick Mar 24, 2016
168a8e8
paper-input: Document required html5 attribute.
DanChadwick Mar 24, 2016
edf5436
paper-input: Document API changes in CHANGELOG.md.
DanChadwick Mar 24, 2016
ac87097
paper-input: Fix broken tests.
DanChadwick Mar 25, 2016
bbe4c1a
paper-input: Change style of event in demo app to avoid redraw bug.
DanChadwick Mar 25, 2016
d86f89c
Remove obsolete focus class binding.
DanChadwick Mar 28, 2016
b7126ee
paper-input: namespace event .on() and .off() to avoid removing unint…
DanChadwick Mar 28, 2016
93e1811
paper-input: Change 'validationErrors' to just 'errors' in API.
DanChadwick Mar 28, 2016
99fda2f
paper-input: Change 'icon-class' to 'iconClass' in API.
DanChadwick Mar 28, 2016
8f23254
ember-input: Change message to error in template for clarity.
DanChadwick Mar 28, 2016
3a53b24
ember-input: Make external validation message more flexible, allowing…
DanChadwick Mar 28, 2016
cef9797
ember-input: Remove vestigial icon-class/iconClass.
DanChadwick Mar 28, 2016
aadd4d1
paper-input: icon, iconRight, noFloat, with tests.
DanChadwick Mar 29, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
- [#286](https://github.com/miguelcobain/ember-paper/pull/286) paper-radio now sends the action `onchange` instead of `changed` and it is mandatory (see ddau)
- [#303](https://github.com/miguelcobain/ember-paper/pull/303) paper-menu template may now specify `dense=true` to display menu items compactly
- [#313](https://github.com/miguelcobain/ember-paper/pull/313) paper-backdrop `tap` action renamed `onTap` and required action closure.
- [#319](https://github.com/miguelcobain/ember-paper/pull/319) paper-input now uses a passThru hash rather than individual attr-xxx attributes to pass attribute binds through to the underlying input.
The required attribute can now be used to mean native validation, required label styling with an
asterisk, and/or native html5 required validation.

### 0.2.11

Expand Down
200 changes: 108 additions & 92 deletions addon/components/paper-input.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,61 +3,75 @@ import BaseFocusable from './base-focusable';
import ColorMixin from 'ember-paper/mixins/color-mixin';
import FlexMixin from 'ember-paper/mixins/flex-mixin';

const { $, computed, isPresent, isArray, Logger, A, getWithDefault } = Ember;

export default BaseFocusable.extend(ColorMixin, FlexMixin, {
tagName: 'md-input-container',
classNames: ['md-default-theme'],
classNameBindings: ['hasValue:md-input-has-value', 'focus:md-input-focused', 'isInvalid:md-input-invalid', 'iconFloat:md-icon-float'],
classNameBindings: [
'hasValue:md-input-has-value',
'isInvalid:md-input-invalid',
'eitherIcon:md-has-icon',
'iconFloat:md-icon-float',
'iconRight:md-icon-right'
],
type: 'text',
autofocus: false,
tabindex: -1,
hideAllMessages: false,
hasValue: Ember.computed.notEmpty('value'),
isTouched: false,

hasValue: computed.notEmpty('value'),

inputElementId: Ember.computed('elementId', function() {
inputElementId: computed('elementId', function() {
return `input-${this.get('elementId')}`;
}),

isInvalid: Ember.computed('isTouched', 'value', function() {
return this.validate();
isInvalid: computed('isTouched', 'value', function() {
return this.get('isTouched') && isPresent(this.get('errorMessages'));
}),

renderCharCount: Ember.computed('value', function() {
renderCharCount: computed('value', function() {
let currentLength = this.get('value') ? this.get('value').length : 0;
return `${currentLength}/${this.get('maxlength')}`;
}),

iconFloat: Ember.computed.and('icon', 'label'),
eitherIcon: computed.or('icon', 'iconRight'),
iconFloat: computed.and('eitherIcon', 'label'),

didInsertElement() {
if (this.get('textarea')) {
this.setupTextarea();
}
},

setupTextarea() {
let textarea = this.$().children('textarea').first();
let textareaNode = textarea.get(0);
let container = this.get('element');
let minRows = NaN;
let lineHeight = null;
let textarea = this.$().children('textarea').first();
let textareaNode = textarea.get(0);
let container = this.get('element');
let minRows = NaN;
let lineHeight = null;

if (textareaNode.hasAttribute('rows')) {
minRows = parseInt(textareaNode.getAttribute('rows'));
}

if (textareaNode.hasAttribute('rows')) {
minRows = parseInt(textareaNode.getAttribute('rows'));
}
textarea.on(`keydown.${this.elementId} input.${this.elementId}`, () => {
this.growTextarea(textarea, textareaNode, container, minRows, lineHeight);
});

textarea.on('keydown input', () => {
this.growTextarea(textarea, textareaNode, container, minRows, lineHeight);
});
if (isNaN(minRows)) {
textarea.attr('rows', '1');

if (isNaN(minRows)) {
textarea.attr('rows', '1');
textarea.on(`scroll.${this.elementId}`, () => {
this.onScroll(textareaNode);
});
}

textarea.on('scroll', () => {
this.onScroll(textareaNode);
});
$(window).on(`resize.${this.elementId}`, this.growTextarea(textarea, textareaNode, container, minRows, lineHeight));
}
},

Ember.$(window).on('resize', this.growTextarea(textarea, textareaNode, container, minRows, lineHeight));
willDestroyElement() {
if (this.get('textarea')) {
$(window).off(`resize.${this.elementId}`, this.growTextarea);
this.$().children('textarea').first().off(`keydown.${this.elementId} input.${this.elementId} scroll.${this.elementId}`);
}
},

growTextarea(textarea, textareaNode, container, minRows, lineHeight) {
Expand Down Expand Up @@ -107,103 +121,105 @@ export default BaseFocusable.extend(ColorMixin, FlexMixin, {
node.style.height = `${height}px`;
},

willDestroyElement() {
Ember.$(window).off('resize', this.growTextarea);
},

validate() {

if (!this.get('isTouched')) {
return false;
}

let valueIsInvalid = false;
/**
* Return the built-in constraints.
*
* May be overridden to provide additional built-in constraints. Be sure to
* call this._super() to retrieve the standard constraints.
*
* @public
*/
constraints() {
let currentValue = this.get('value');
let constraints = [
return [
{
attr: 'required',
defaultError: 'This is required.',
isError: () => this.get('required') && !this.get('hasValue')
// required can be a boolean or 'style' for just required asterisk styling.
isError: () => this.get('required') === true && !this.get('hasValue')
},
{
attr: 'min',
defaultError: `Must be at least ${this.get('min')}.`,
isError: () => +currentValue < +this.get('min')
isError: () => currentValue && +currentValue < +this.get('min')
},
{
attr: 'max',
defaultError: `Must be less than ${this.get('max')}.`,
isError: () => +currentValue > +this.get('max')
isError: () => currentValue && +currentValue > +this.get('max')
},
{
attr: 'maxlength',
defaultError: `Must not exceed ${this.get('maxlength')} characters.`,
isError: () => currentValue && currentValue.length > +this.get('maxlength')
}
];
},

constraints.some((thisConstraint) => {
if (thisConstraint.isError()) {
this.setError(thisConstraint);
valueIsInvalid = true;
return true;
/**
* Computed property that validate the input and return an array of error
* objects, each with an ng-message code and an error message.
*
* @public
*/
errorMessages: computed('value', function() {
let constraints = A();
let customConstraints = this.get('customValidation');
constraints.pushObjects(this.constraints());
if (isPresent(customConstraints)) {
if (isArray(customConstraints)) {
constraints.pushObjects(customConstraints);
} else {
constraints.pushObject(customConstraints);
}
});

if (valueIsInvalid === true) {
return true;
}

if (!Ember.isEmpty(this.get('customValidation'))) {
let validationObjects = Ember.A();
let self = this;
let validationObjectsLength;

try {
if (!Ember.isArray(this.get('customValidation'))) {
validationObjects.addObject(this.get('customValidation'));
} else {
validationObjects = this.get('customValidation');
}

validationObjectsLength = validationObjects.length;
for (let i = 0; i < validationObjectsLength; i++) {
if (typeof validationObjects[i].isError === 'function') {
if (validationObjects[i].isError([currentValue]) === true) {
self.setError(validationObjects[i]);
valueIsInvalid = true;
break;
}
}
let currentValueParameter = [ this.get('value') ];
let messages = A();
try {
constraints.forEach((constraint) => {
if (constraint.isError(currentValueParameter)) {
messages.pushObject({
key: constraint.attr || 'custom',
message: this.get(`${constraint.attr}-errortext`) || constraint.defaultError || constraint.errorMessage
});
}
} catch (error) {
Ember.Logger.error('Exception with custom validation: ', error);
}

});
} catch (error) {
Logger.error('Exception with custom validation: ', error);
}

return valueIsInvalid;
},
let errors = this.get('errors');
if (errors && isArray(errors)) {
messages.pushObjects(errors.map((i) => ({
key: getWithDefault(i, 'attr', 'custom'),
message: getWithDefault(i, 'message', i)
})));
}

setError(constraint) {
this.set('ng-message', constraint.attr || 'custom');
this.set('errortext', this.get(`${constraint.attr}-errortext`) || constraint.defaultError || constraint.errorMessage);
},
return messages;
}),

actions: {
focusIn(value) {
// We resend action so other components can take use of the actions also ( if they want ).
focusIn(ev) {
// Actions must be sent before focusing.
this.sendAction('focus-in', value);
if (this.get('onFocusIn')) {
this.get('onFocusIn')(ev);
}
this.set('focus', true);
},
focusOut(value) {
this.sendAction('focus-out', value);
focusOut(ev) {
if (this.get('onFocusOut')) {
this.get('onFocusOut')(ev);
}
this.set('focus', false);
this.set('isTouched', true);
},
keyDown(value, event) {
this.sendAction('key-down', value, event);
}
// ,
// keyDown(value, ev) {
// if (this.get('onKeyDown')) {
// this.get('onKeyDown')(value, ev);
// }
// }
}
});
11 changes: 11 additions & 0 deletions app/styles/backports/paper-input.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/**
* Backports from versions of angular-material-source that are later than the
* version used by ember-paper.
*/

// For paper-input, backports the required asterisk in the element's label.
md-input-container label.md-required:not(._md-container-ignore)::after {
content: ' *';
font-size: 13px;
vertical-align: top;
}
3 changes: 3 additions & 0 deletions app/styles/ember-paper.scss
Original file line number Diff line number Diff line change
Expand Up @@ -145,3 +145,6 @@

@import './angular-material/components/dialog/dialog';
@import './angular-material/components/dialog/dialog-theme';

// Backports of features from future versions of angular-material-source to this version
@import './backports/paper-input';
Loading