Skip to content

Commit

Permalink
fix(components): support moving components in watch mode (#273)
Browse files Browse the repository at this point in the history
This change introduced a mix-in class with `manage(handle)` method,
for automatic release of `handle` when the component is released.

Fixes #272.
  • Loading branch information
asudoh authored and marijohannessen committed Jan 4, 2018
1 parent 5e0031d commit 0336425
Show file tree
Hide file tree
Showing 28 changed files with 683 additions and 512 deletions.
33 changes: 20 additions & 13 deletions src/components/accordion/accordion.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import initComponentBySearch from '../../globals/js/mixins/init-component-by-search';
import handles from '../../globals/js/mixins/handles';
import eventMatches from '../../globals/js/misc/event-matches';
import on from '../../globals/js/misc/on';

class Accordion extends mixin(createComponent, initComponentBySearch) {
class Accordion extends mixin(createComponent, initComponentBySearch, handles) {
/**
* Accordion.
* @extends CreateComponent
* @extends InitComponentBySearch
* @extends Handles
* @param {HTMLElement} element The element working as an accordion.
*/
constructor(element, options) {
super(element, options);
this.element.addEventListener('click', event => {
const item = eventMatches(event, this.options.selectorAccordionItem);
if (item && !eventMatches(event, this.options.selectorAccordionContent)) {
this._toggle(item);
}
});
this.manage(
on(this.element, 'click', event => {
const item = eventMatches(event, this.options.selectorAccordionItem);
if (item && !eventMatches(event, this.options.selectorAccordionContent)) {
this._toggle(item);
}
})
);

/**
*
Expand All @@ -30,13 +35,15 @@ class Accordion extends mixin(createComponent, initComponentBySearch) {
*/

if (!this._checkIfButton()) {
this.element.addEventListener('keypress', event => {
const item = eventMatches(event, this.options.selectorAccordionItem);
this.manage(
on(this.element, 'keypress', event => {
const item = eventMatches(event, this.options.selectorAccordionItem);

if (item && !eventMatches(event, this.options.selectorAccordionContent)) {
this._handleKeypress(event);
}
});
if (item && !eventMatches(event, this.options.selectorAccordionContent)) {
this._handleKeypress(event);
}
})
);
}
}

Expand Down
13 changes: 9 additions & 4 deletions src/components/card/card.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,29 @@ import warning from 'warning';
import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import initComponentBySearch from '../../globals/js/mixins/init-component-by-search';
import handles from '../../globals/js/mixins/handles';
import eventMatches from '../../globals/js/misc/event-matches';
import on from '../../globals/js/misc/on';

let didWarnAboutDeprecation = false;

class Card extends mixin(createComponent, initComponentBySearch) {
class Card extends mixin(createComponent, initComponentBySearch, handles) {
/**
* The container for cards.
* @extends CreateComponent
* @extends InitComponentBySearch
* @extends Handles
* @param {HTMLElement} element The element working as a container.
* @param {Object} [options] The component options.
* @param {string} [options.selectorCard] The CSS selector to find cards.
*/
constructor(element, options) {
super(element, options);
this.element.addEventListener('keydown', event => {
this._cardKeyPress(event);
});
this.manage(
on(this.element, 'keydown', event => {
this._cardKeyPress(event);
})
);
if (__DEV__) {
warning(
didWarnAboutDeprecation,
Expand Down
13 changes: 9 additions & 4 deletions src/components/content-switcher/content-switcher.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import initComponentBySearch from '../../globals/js/mixins/init-component-by-search';
import eventedState from '../../globals/js/mixins/evented-state';
import handles from '../../globals/js/mixins/handles';
import eventMatches from '../../globals/js/misc/event-matches';
import on from '../../globals/js/misc/on';

class ContentSwitcher extends mixin(createComponent, initComponentBySearch, eventedState) {
class ContentSwitcher extends mixin(createComponent, initComponentBySearch, eventedState, handles) {
/**
* Set of content switcher buttons.
* @extends CreateComponent
* @extends InitComponentBySearch
* @extends EventedState
* @extends Handles
* @param {HTMLElement} element The element working as a set of content switcher buttons.
* @param {Object} [options] The component options.
* @param {string} [options.selectorButton] The CSS selector to find switcher buttons.
Expand All @@ -22,9 +25,11 @@ class ContentSwitcher extends mixin(createComponent, initComponentBySearch, even
*/
constructor(element, options) {
super(element, options);
this.element.addEventListener('click', event => {
this._handleClick(event);
});
this.manage(
on(this.element, 'click', event => {
this._handleClick(event);
})
);
}

/**
Expand Down
7 changes: 5 additions & 2 deletions src/components/copy-button/copy-button.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import InitComponentBySearch from '../../globals/js/mixins/init-component-by-search';
import handles from '../../globals/js/mixins/handles';
import on from '../../globals/js/misc/on';

class CopyButton extends mixin(createComponent, InitComponentBySearch) {
class CopyButton extends mixin(createComponent, InitComponentBySearch, handles) {
/**
* CopyBtn UI.
* @extends CreateComponent
* @extends InitComponentBySearch
* @extends Handles
* @param {HTMLElement} element The element working as a copy button UI.
*/
constructor(element, options) {
super(element, options);
this.element.addEventListener('click', () => this.handleClick());
this.manage(on(this.element, 'click', () => this.handleClick()));
}

/**
Expand Down
31 changes: 19 additions & 12 deletions src/components/data-table/data-table.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import initComponentBySearch from '../../globals/js/mixins/init-component-by-search';
import eventedState from '../../globals/js/mixins/evented-state';
import handles from '../../globals/js/mixins/handles';
import eventMatches from '../../globals/js/misc/event-matches';
import on from '../../globals/js/misc/on';

class DataTable extends mixin(createComponent, initComponentBySearch, eventedState) {
class DataTable extends mixin(createComponent, initComponentBySearch, eventedState, handles) {
/**
* Data Table
* @extends CreateComponent
* @extends InitComponentBySearch
* @extends EventedState
* @extends Handles
* @param {HTMLElement} element The root element of tables
* @param {Object} [options] the... options
* @param {string} [options.selectorInit] selector initialization
Expand All @@ -32,21 +35,25 @@ class DataTable extends mixin(createComponent, initComponentBySearch, eventedSta

this.refreshRows();

this.element.addEventListener('click', evt => {
const eventElement = eventMatches(evt, this.options.eventTrigger);
if (eventElement) {
this._toggleState(eventElement, evt);
}
});

this.element.addEventListener('keydown', evt => {
if (evt.which === 13) {
this.manage(
on(this.element, 'click', evt => {
const eventElement = eventMatches(evt, this.options.eventTrigger);
if (eventElement) {
this._toggleState(eventElement, evt);
}
}
});
})
);

this.manage(
on(this.element, 'keydown', evt => {
if (evt.which === 13) {
const eventElement = eventMatches(evt, this.options.eventTrigger);
if (eventElement) {
this._toggleState(eventElement, evt);
}
}
})
);
}

/**
Expand Down
67 changes: 40 additions & 27 deletions src/components/date-picker/date-picker.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import Flatpickr from 'flatpickr';
import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import initComponentBySearch from '../../globals/js/mixins/init-component-by-search';
import handles from '../../globals/js/mixins/handles';
import on from '../../globals/js/misc/on';

// `this.options` create-component mix-in creates prototype chain
// so that `options` given in constructor argument wins over the one defined in static `options` property
Expand All @@ -26,28 +28,33 @@ Flatpickr.l10ns.en.weekdays.shorthand.forEach((day, index) => {
}
});

class DatePicker extends mixin(createComponent, initComponentBySearch) {
class DatePicker extends mixin(createComponent, initComponentBySearch, handles) {
/**
* DatePicker.
* @extends CreateComponent
* @extends InitComponentBySearch
* @extends Handles
* @param {HTMLElement} element The element working as an date picker.
*/
constructor(element, options) {
super(element, options);
const type = this.element.getAttribute(this.options.attribType);
this.calendar = this._initDatePicker(type);
this.element.addEventListener('keydown', e => {
if (e.which === 40) {
this.calendar.calendarContainer.focus();
}
});
this.calendar.calendarContainer.addEventListener('keydown', e => {
if (e.which === 9 && type === 'range') {
this._updateClassNames(this.calendar);
this.element.querySelector(this.options.selectorDatePickerInputFrom).focus();
}
});
this.manage(
on(this.element, 'keydown', e => {
if (e.which === 40) {
this.calendar.calendarContainer.focus();
}
})
);
this.manage(
on(this.calendar.calendarContainer, 'keydown', e => {
if (e.which === 9 && type === 'range') {
this._updateClassNames(this.calendar);
this.element.querySelector(this.options.selectorDatePickerInputFrom).focus();
}
})
);
}

_initDatePicker = type => {
Expand Down Expand Up @@ -96,16 +103,20 @@ class DatePicker extends mixin(createComponent, initComponentBySearch) {
})
);
if (type === 'range') {
this.element.querySelector(this.options.selectorDatePickerInputTo).addEventListener('click', () => {
this.element.querySelector(this.options.selectorDatePickerInputTo).focus();
calendar.open();
this._updateClassNames(calendar);
});
this.manage(
on(this.element.querySelector(this.options.selectorDatePickerInputTo), 'click', () => {
this.element.querySelector(this.options.selectorDatePickerInputTo).focus();
calendar.open();
this._updateClassNames(calendar);
})
);
this._addInputLogic(this.element.querySelector(this.options.selectorDatePickerInputTo));
}
this.element.querySelector(this.options.selectorDatePickerIcon).addEventListener('click', () => {
calendar.open();
});
this.manage(
on(this.element.querySelector(this.options.selectorDatePickerIcon), 'click', () => {
calendar.open();
})
);
this._updateClassNames(calendar);
this._addInputLogic(date);
return calendar;
Expand All @@ -127,13 +138,15 @@ class DatePicker extends mixin(createComponent, initComponentBySearch) {

_addInputLogic = input => {
const inputField = input;
inputField.addEventListener('change', () => {
const inputDate = this.calendar.parseDate(inputField.value);
if (!isNaN(inputDate.valueOf())) {
this.calendar.setDate(inputDate);
}
this._updateClassNames(this.calendar);
});
this.manage(
on(inputField, 'change', () => {
const inputDate = this.calendar.parseDate(inputField.value);
if (!isNaN(inputDate.valueOf())) {
this.calendar.setDate(inputDate);
}
this._updateClassNames(this.calendar);
})
);
};

_updateClassNames = calendar => {
Expand Down
14 changes: 4 additions & 10 deletions src/components/detail-page-header/detail-page-header.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,17 @@ import debounce from 'lodash.debounce';
import mixin from '../../globals/js/misc/mixin';
import createComponent from '../../globals/js/mixins/create-component';
import initComponentBySearch from '../../globals/js/mixins/init-component-by-search';
import handles from '../../globals/js/mixins/handles';
import on from '../../globals/js/misc/on';

let didWarnAboutDeprecation = false;

class DetailPageHeader extends mixin(createComponent, initComponentBySearch) {
class DetailPageHeader extends mixin(createComponent, initComponentBySearch, handles) {
/**
* The Detail Page Header.
* @extends CreateComponent
* @extends InitComponentBySearch
* @extends Handles
* @param {HTMLElement} element The element working as a page header.
* @param {Object} [options] The component options.
*/
Expand All @@ -21,7 +23,7 @@ class DetailPageHeader extends mixin(createComponent, initComponentBySearch) {
this.previousScrollY = 0;
// Debounce scroll event calls to handleScroll (default: 50)
const debouncedScroll = debounce(this._handleScroll.bind(this), 25);
this.hScroll = on(this.element.ownerDocument.defaultView, 'scroll', debouncedScroll);
this.manage(on(this.element.ownerDocument.defaultView, 'scroll', debouncedScroll));
if (__DEV__) {
warning(
didWarnAboutDeprecation,
Expand Down Expand Up @@ -59,14 +61,6 @@ class DetailPageHeader extends mixin(createComponent, initComponentBySearch) {
this.previousScrollY = scrollPosition;
}

/**
* Cleans up stuffs specific to this widget.
*/
release() {
this.hScroll.release();
super.release();
}

/**
* The map associating DOM element and detail page header instance.
* @member DetailPageHeader.components
Expand Down
Loading

0 comments on commit 0336425

Please sign in to comment.