consul/ui-v2/app/components/app-view.js
John Cowen 63a0582fa3 ui: Reduce mutation of html.classList (#5974)
Throughout the app we mutate the value of the root node classList on
navigation between separate pages (basically on URL change).

Every template has a unique classList for example `template-service
template-show` and `template-service template-list` etc etc.

When navigating between 2 pages, both pages using the same template yet
with different data, previoulsy we would entirely clear out the
`html.classList` and then refill it again with eaxctly the same classes.

This commit moves this to perform a diff previous to mutating the
classList, and then potentially no classList mutating is needed when
moving between 2 pages of the same template.
2019-09-04 08:35:03 +00:00

49 lines
1.7 KiB
JavaScript

import Component from '@ember/component';
import SlotsMixin from 'block-slots';
import { get } from '@ember/object';
import { inject as service } from '@ember/service';
import templatize from 'consul-ui/utils/templatize';
export default Component.extend(SlotsMixin, {
loading: false,
authorized: true,
enabled: true,
classNames: ['app-view'],
classNameBindings: ['enabled::disabled', 'authorized::unauthorized'],
dom: service('dom'),
didReceiveAttrs: function() {
this._super(...arguments);
// right now only manually added classes are hoisted to <html>
const $root = get(this, 'dom').root();
let cls = get(this, 'class') || '';
if (get(this, 'loading')) {
cls += ' loading';
} else {
$root.classList.remove(...templatize(['loading']));
}
if (cls) {
// its possible for 'layout' templates to change after insert
// check for these specific layouts and clear them out
const receivedClasses = new Set(templatize(cls.split(' ')));
const difference = new Set([...$root.classList].filter(item => !receivedClasses.has(item)));
[...difference].forEach(function(item, i) {
if (templatize(['edit', 'show', 'list']).indexOf(item) !== -1) {
$root.classList.remove(item);
}
});
$root.classList.add(...receivedClasses);
}
},
didInsertElement: function() {
this._super(...arguments);
this.didReceiveAttrs();
},
didDestroyElement: function() {
this._super(...arguments);
const cls = get(this, 'class') + ' loading';
if (cls) {
const $root = get(this, 'dom').root();
$root.classList.remove(...templatize(cls.split(' ')));
}
},
});