feat(view): reimplemented property setters using change detection

This commit is contained in:
vsavkin
2015-04-21 11:47:53 -07:00
parent 8a92a1f13e
commit 8ccafb0524
36 changed files with 510 additions and 469 deletions

View File

@ -1,7 +1,6 @@
import {Component, View} from 'angular2/angular2';
import {PropertySetter, EventEmitter} from 'angular2/src/core/annotations/di';
import {onChange} from 'angular2/src/core/annotations/annotations';
import {isPresent, StringWrapper} from 'angular2/src/facade/lang';
import {isPresent} from 'angular2/src/facade/lang';
@Component({selector: '[md-button]:not([href])'})
@ -17,21 +16,18 @@ export class MdButton {
'disabled': 'disabled'
},
hostListeners: {'click': 'onClick($event)'},
hostProperties: {'tabIndex': 'tabIndex'},
lifecycle: [onChange]
})
@View({
templateUrl: 'angular2_material/src/components/button/button.html'
})
export class MdAnchor {
tabIndexSetter: Function;
tabIndex: number;
/** Whether the component is disabled. */
disabled: boolean;
constructor(@PropertySetter('tabIndex') tabIndexSetter: Function) {
this.tabIndexSetter = tabIndexSetter;
}
onClick(event) {
// A disabled anchor shouldn't navigate anywhere.
if (isPresent(this.disabled) && this.disabled !== false) {
@ -42,6 +38,6 @@ export class MdAnchor {
/** Invoked when a change is detected. */
onChange(_) {
// A disabled anchor should not be in the tab flow.
this.tabIndexSetter(this.disabled ? -1 : 0);
this.tabIndex = this.disabled ? -1 : 0;
}
}

View File

@ -1,4 +1,4 @@
import {Component, View, Attribute, PropertySetter} from 'angular2/angular2';
import {Component, View, Attribute} from 'angular2/angular2';
import {isPresent} from 'angular2/src/facade/lang';
import {KEY_SPACE} from 'angular2_material/src/core/constants'
import {KeyboardEvent} from 'angular2/src/facade/browser';
@ -11,6 +11,12 @@ import {KeyboardEvent} from 'angular2/src/facade/browser';
},
hostListeners: {
'keydown': 'onKeydown($event)'
},
hostProperties: {
'tabindex': 'tabindex',
'role': 'attr.role',
'checked': 'attr.aria-checked',
'disabled_': 'attr.aria-disabled'
}
})
@View({
@ -19,38 +25,21 @@ import {KeyboardEvent} from 'angular2/src/facade/browser';
})
export class MdCheckbox {
/** Whether this checkbox is checked. */
checked_: boolean;
checked: boolean;
/** Whether this checkbox is disabled. */
disabled_: boolean;
/** Setter for `aria-checked` attribute. */
ariaCheckedSetter: Function;
/** Setter for `role` attribute. */
role: string;
/** Setter for `aria-disabled` attribute. */
ariaDisabledSetter: Function;
/** Setter for tabindex */
tabindex: any;
constructor(
@Attribute('tabindex') tabindex: string,
@PropertySetter('tabindex') tabindexSetter: Function,
@PropertySetter('attr.role') roleSetter: Function,
@PropertySetter('attr.aria-checked') ariaCheckedSetter: Function,
@PropertySetter('attr.aria-disabled') ariaDisabledSetter: Function) {
this.ariaCheckedSetter = ariaCheckedSetter;
this.ariaDisabledSetter = ariaDisabledSetter;
roleSetter('checkbox');
constructor(@Attribute('tabindex') tabindex: string) {
this.role = 'checkbox';
this.checked = false;
tabindexSetter(isPresent(tabindex) ? tabindex : '0');
}
get checked() {
return this.checked_;
}
set checked(value) {
this.checked_ = value;
this.ariaCheckedSetter(value);
this.tabindex = isPresent(tabindex) ? tabindex : '0';
}
get disabled() {
@ -59,7 +48,6 @@ export class MdCheckbox {
set disabled(value) {
this.disabled_ = isPresent(value) && value !== false;
this.ariaDisabledSetter(this.disabled_);
}
onKeydown(event: KeyboardEvent) {
@ -76,6 +64,5 @@ export class MdCheckbox {
}
this.checked = !this.checked;
this.ariaCheckedSetter(this.checked);
}
}

View File

@ -2,7 +2,6 @@ import {Component, View, onAllChangesDone, Parent} from 'angular2/angular2';
import {onDestroy, onChange} from 'angular2/src/core/annotations/annotations';
import {ListWrapper} from 'angular2/src/facade/collection';
import {isPresent, isString, NumberWrapper, stringify} from 'angular2/src/facade/lang';
import {PropertySetter} from 'angular2/src/core/annotations/di';
// TODO(jelbourn): Set appropriate aria attributes for grid list elements.
@ -172,6 +171,15 @@ export class MdGridList {
'rowspan': 'rowspan',
'colspan': 'colspan'
},
hostProperties: {
'styleHeight': 'style.height',
'styleWidth': 'style.width',
'styleTop': 'style.top',
'styleLeft': 'style.left',
'styleMarginTop': 'style.marginTop',
'stylePaddingTop': 'style.paddingTop',
'role': 'role'
},
lifecycle: [onDestroy, onChange]
})
@View({
@ -181,40 +189,28 @@ export class MdGridTile {
gridList: MdGridList;
rowspan: number;
colspan: number;
heightSetter;
widthSetter;
topSetter;
leftSetter;
marginTopSetter;
paddingTopSetter;
styleHeight:any;
styleWidth:any;
styleTop:any;
styleLeft:any;
styleMarginTop:any;
stylePaddingTop:any;
role:any;
isRegisteredWithGridList: boolean;
constructor(
@Parent() gridList: MdGridList,
@PropertySetter('style.height') heightSetter: Function,
@PropertySetter('style.width') widthSetter: Function,
@PropertySetter('style.top') topSetter: Function,
@PropertySetter('style.left') leftSetter: Function,
@PropertySetter('style.marginTop') marginTopSetter: Function,
@PropertySetter('style.paddingTop') paddingTopSetter: Function,
@PropertySetter('role') roleSetter: Function
) {
constructor(@Parent() gridList: MdGridList) {
this.gridList = gridList;
this.heightSetter = heightSetter;
this.widthSetter = widthSetter;
this.topSetter = topSetter;
this.leftSetter = leftSetter;
this.marginTopSetter = marginTopSetter;
this.paddingTopSetter = paddingTopSetter;
roleSetter('listitem');
this.role = 'listitem';
// Tiles default to 1x1, but rowspan and colspan can be changed via binding.
this.rowspan = 1;
this.colspan = 1;
// DEBUG
heightSetter(`${gridList.tiles.length * 100}px`);
this.styleHeight = `${gridList.tiles.length * 100}px`;
}
/**

View File

@ -1,4 +1,4 @@
import {Component, View, Attribute, PropertySetter, onChange} from 'angular2/angular2';
import {Component, View, Attribute, onChange} from 'angular2/angular2';
import {isPresent, isBlank} from 'angular2/src/facade/lang';
import {Math} from 'angular2/src/facade/math';
@ -8,6 +8,12 @@ import {Math} from 'angular2/src/facade/math';
properties: {
'value': 'value',
'bufferValue': 'buffer-value'
},
hostProperties: {
'role': 'attr.role',
'ariaValuemin': 'attr.aria-valuemin',
'ariaValuemax': 'attr.aria-valuemax',
'ariaValuenow': 'attr.aria-valuenow'
}
})
@View({
@ -33,19 +39,20 @@ export class MdProgressLinear {
/** CSS `transform` property applied to the secondary bar. */
secondaryBarTransform: string;
constructor(
@Attribute('md-mode') mode: string,
@PropertySetter('attr.role') roleSetter: Function,
@PropertySetter('attr.aria-valuemin') ariaValueMinSetter: Function,
@PropertySetter('attr.aria-valuemax') ariaValueMaxSetter: Function,
@PropertySetter('attr.aria-valuenow') ariaValueNowSetter: Function) {
role:any;
ariaValuemin:any;
ariaValuemax:any;
ariaValuenow:any;
constructor(@Attribute('md-mode') mode: string) {
this.ariaValueNowSetter = ariaValueNowSetter;
this.primaryBarTransform = '';
this.secondaryBarTransform = '';
roleSetter('progressbar');
ariaValueMinSetter('0');
ariaValueMaxSetter('100');
this.role = 'progressbar';
this.ariaValuemin = '0';
this.ariaValuemax = '100';
this.mode = isPresent(mode) ? mode : Mode.DETERMINATE;
}

View File

@ -1,4 +1,4 @@
import {Component, View, Parent, Ancestor, Attribute, PropertySetter} from 'angular2/angular2';
import {Component, View, Parent, Ancestor, Attribute} from 'angular2/angular2';
import {Optional} from 'angular2/src/di/annotations';
import {MdRadioDispatcher} from 'angular2_material/src/components/radio/radio_dispatcher'
import {onChange} from 'angular2/src/core/annotations/annotations';
@ -34,6 +34,13 @@ var _uniqueIdCounter:number = 0;
},
hostListeners: {
'keydown': 'onKeydown($event)'
},
hostProperties: {
'id': 'id',
'tabindex': 'tabindex',
'role': 'attr.role',
'checked': 'attr.aria-checked',
'disabled': 'attr.aria-disabled'
}
})
@View({
@ -42,7 +49,7 @@ var _uniqueIdCounter:number = 0;
})
export class MdRadioButton {
/** Whether this radio is checked. */
checked_: boolean;
checked: boolean;
/** Whether the radio is disabled. */
disabled_: boolean;
@ -62,36 +69,26 @@ export class MdRadioButton {
/** Dispatcher for coordinating radio unique-selection by name. */
radioDispatcher: MdRadioDispatcher;
/** Setter for `aria-checked` attribute. */
ariaCheckedSetter: Function;
/** Setter for `aria-disabled` attribute. */
ariaDisabledSetter: Function;
tabindex:any;
role:any;
constructor(
@Optional() @Parent() radioGroup: MdRadioGroup,
@Attribute('id') id: string,
@Attribute('tabindex') tabindex: string,
@PropertySetter('id') idSetter: Function,
@PropertySetter('tabindex') tabindexSetter: Function,
@PropertySetter('attr.role') roleSetter: Function,
@PropertySetter('attr.aria-checked') ariaCheckedSetter: Function,
@PropertySetter('attr.aria-disabled') ariaDisabledSetter: Function,
radioDispatcher: MdRadioDispatcher) {
// Assertions. Ideally these should be stripped out by the compiler.
// TODO(jelbourn): Assert that there's no name binding AND a parent radio group.
this.radioGroup = radioGroup;
this.radioDispatcher = radioDispatcher;
this.ariaCheckedSetter = ariaCheckedSetter;
this.ariaDisabledSetter = ariaDisabledSetter;
this.value = null;
roleSetter('radio');
this.role = 'radio';
this.checked = false;
this.id = isPresent(id) ? id : `md-radio-${_uniqueIdCounter++}`;
idSetter(this.id);
this.id = isPresent(id) ? id : `md-radio-${_uniqueIdCounter++}`;;
// Whenever a radio button with the same name is checked, uncheck this radio button.
radioDispatcher.listen((name) => {
@ -108,7 +105,7 @@ export class MdRadioButton {
// If the user has not set a tabindex, default to zero (in the normal document flow).
if (!isPresent(radioGroup)) {
tabindexSetter(isPresent(tabindex) ? tabindex : '0');
this.tabindex = isPresent(tabindex) ? tabindex : '0';
}
}
@ -129,22 +126,12 @@ export class MdRadioButton {
(isPresent(this.radioGroup) && this.radioGroup.disabled);
}
get checked() {
return this.checked_;
}
set checked(value) {
this.checked_ = value;
this.ariaCheckedSetter(value);
}
get disabled() {
return this.disabled_;
}
set disabled(value) {
this.disabled_ = isPresent(value) && value !== false;
this.ariaDisabledSetter(this.disabled_);
}
/** Select this radio button. */
@ -183,6 +170,13 @@ export class MdRadioButton {
},
hostListeners: {
'keydown': 'onKeydown($event)'
},
hostProperties: {
'tabindex': 'tabindex',
'role': 'attr.role',
'checked': 'attr.aria-checked',
'disabled': 'attr.aria-disabled',
'activedescendant': 'attr.aria-activedescendant'
}
})
@View({
@ -201,11 +195,7 @@ export class MdRadioGroup {
/** List of child radio buttons. */
radios_: List<MdRadioButton>;
changeEmitter: Function;
ariaActiveDescendantSetter: Function;
ariaDisabledSetter: Function;
activedescendant: any;
disabled_: boolean;
@ -214,30 +204,28 @@ export class MdRadioGroup {
change:EventEmitter;
tabindex:any;
role:any;
constructor(
@Attribute('tabindex') tabindex: string,
@Attribute('disabled') disabled: string,
@PropertySetter('tabindex') tabindexSetter: Function,
@PropertySetter('attr.role') roleSetter: Function,
@PropertySetter('attr.aria-disabled') ariaDisabledSetter: Function,
@PropertySetter('attr.aria-activedescendant') ariaActiveDescendantSetter: Function,
radioDispatcher: MdRadioDispatcher) {
this.name_ = `md-radio-group-${_uniqueIdCounter++}`;
this.radios_ = [];
this.change = new EventEmitter();
this.ariaActiveDescendantSetter = ariaActiveDescendantSetter;
this.ariaDisabledSetter = ariaDisabledSetter;
this.radioDispatcher = radioDispatcher;
this.selectedRadioId = '';
this.disabled_ = false;
roleSetter('radiogroup');
this.role = 'radiogroup';
// The simple presence of the `disabled` attribute dictates disabled state.
this.disabled = isPresent(disabled);
// If the user has not set a tabindex, default to zero (in the normal document flow).
tabindexSetter(isPresent(tabindex) ? tabindex : '0');
this.tabindex = isPresent(tabindex) ? tabindex : '0';
}
/** Gets the name of this group, as to be applied in the HTML 'name' attribute. */
@ -251,7 +239,6 @@ export class MdRadioGroup {
set disabled(value) {
this.disabled_ = isPresent(value) && value !== false;
this.ariaDisabledSetter(this.disabled_);
}
/** Change handler invoked when bindings are resolved or when bindings have changed. */
@ -267,7 +254,7 @@ export class MdRadioGroup {
if (radio.value == this.value) {
radio.checked = true;
this.selectedRadioId = radio.id;
this.ariaActiveDescendantSetter(radio.id);
this.activedescendant = radio.id;
}
});
}
@ -277,7 +264,7 @@ export class MdRadioGroup {
updateValue(value: any, id: string) {
this.value = value;
this.selectedRadioId = id;
this.ariaActiveDescendantSetter(id);
this.activedescendant = id;
ObservableWrapper.callNext(this.change, null);
}
@ -335,6 +322,6 @@ export class MdRadioGroup {
this.value = radio.value;
this.selectedRadioId = radio.id;
this.ariaActiveDescendantSetter(radio.id);
this.activedescendant = radio.id;
}
}

View File

@ -1,4 +1,4 @@
import {Component, View, Attribute, PropertySetter} from 'angular2/angular2';
import {Component, View, Attribute} from 'angular2/angular2';
import {isPresent} from 'angular2/src/facade/lang';
import {KEY_SPACE} from 'angular2_material/src/core/constants'
import {KeyboardEvent} from 'angular2/src/facade/browser';
@ -13,6 +13,11 @@ import {KeyboardEvent} from 'angular2/src/facade/browser';
},
hostListeners: {
'keydown': 'onKeydown($event)'
},
hostProperties: {
'checked': 'attr.aria-checked',
'disabled_': 'attr.aria-disabled',
'role': 'attr.role'
}
})
@View({
@ -21,38 +26,18 @@ import {KeyboardEvent} from 'angular2/src/facade/browser';
})
export class MdSwitch {
/** Whether this switch is checked. */
checked_: boolean;
checked: boolean;
/** Whether this switch is disabled. */
disabled_: boolean;
/** Setter for `aria-checked` attribute. */
ariaCheckedSetter: Function;
tabindex:any;
role:any;
/** Setter for `aria-disabled` attribute. */
ariaDisabledSetter: Function;
constructor(
@Attribute('tabindex') tabindex: string,
@PropertySetter('tabindex') tabindexSetter: Function,
@PropertySetter('attr.role') roleSetter: Function,
@PropertySetter('attr.aria-checked') ariaCheckedSetter: Function,
@PropertySetter('attr.aria-disabled') ariaDisabledSetter: Function) {
this.ariaCheckedSetter = ariaCheckedSetter;
this.ariaDisabledSetter = ariaDisabledSetter;
roleSetter('checkbox');
constructor(@Attribute('tabindex') tabindex: string) {
this.role = 'checkbox';
this.checked = false;
tabindexSetter(isPresent(tabindex) ? tabindex : '0');
}
get checked() {
return this.checked_;
}
set checked(value) {
this.checked_ = value;
this.ariaCheckedSetter(value);
this.tabindex = isPresent(tabindex) ? tabindex : '0';
}
get disabled() {
@ -61,7 +46,6 @@ export class MdSwitch {
set disabled(value) {
this.disabled_ = isPresent(value) && value !== false;
this.ariaDisabledSetter(this.disabled_);
}
onKeydown(event: KeyboardEvent) {
@ -78,7 +62,6 @@ export class MdSwitch {
}
this.checked = !this.checked;
this.ariaCheckedSetter(this.checked);
}
}