Skip to content

Commit

Permalink
WIP Next Region
Browse files Browse the repository at this point in the history
  • Loading branch information
paulfalgout committed Apr 29, 2019
1 parent 5090557 commit 061dd23
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 853 deletions.
24 changes: 19 additions & 5 deletions src/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

import _ from 'underscore';
import extend from './utils/extend';
import buildRegion from './common/build-region';
import normalizeRegion from './common/normalize-region';
import CommonMixin from './mixins/common';
import DestroyMixin from './mixins/destroy';
import RadioMixin from './mixins/radio';
Expand Down Expand Up @@ -50,11 +50,25 @@ _.extend(Application.prototype, CommonMixin, DestroyMixin, RadioMixin, {

if (!region) { return; }

const defaults = {
regionClass: this.regionClass
};
this._region = this._buildRegion(region);
},

_buildRegion(definition) {
if (definition instanceof Region) {
return definition;
}

if (_.isFunction(definition)) {
return this._buildRegion(definition.call(this));
}

const options = normalizeRegion(definition, this.regionClass);

const RegionClass = options.regionClass;

delete options.regionClass;

this._region = buildRegion(region, defaults);
return new RegionClass(options);
},

getRegion() {
Expand Down
2 changes: 1 addition & 1 deletion src/collection-view.js
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ const CollectionView = Backbone.View.extend({
const $emptyEl = this.$container || this.$el;

if (this._emptyRegion && !this._emptyRegion.isDestroyed()) {
this._emptyRegion._setElement($emptyEl[0]);
this._emptyRegion.setElement($emptyEl[0]);
return this._emptyRegion;
}

Expand Down
37 changes: 0 additions & 37 deletions src/common/build-region.js

This file was deleted.

19 changes: 19 additions & 0 deletions src/common/normalize-region.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import _ from 'underscore';
import MarionetteError from '../utils/error';

// return the region instance from the definition
export default function(definition, regionClass) {
if (_.isString(definition)) {
definition = { el: definition };
}

if (!_.isString(definition.el)) {
console.log(definition);
throw new MarionetteError({
message: 'Improper region configuration type.',
url: 'marionette.region.html#defining-regions'
});
}

return _.extend({ regionClass }, definition);
}
118 changes: 54 additions & 64 deletions src/mixins/regions.js
Original file line number Diff line number Diff line change
@@ -1,105 +1,96 @@
import _ from 'underscore';
import _invoke from '../utils/invoke';
import buildRegion from '../common/build-region';
import normalizeRegion from '../common/normalize-region';
import Region from '../region';

// Performant startsWith
function startsWithUi(el) {
return el[0] === '@' &&
el[1] === 'u' &&
el[2] === 'i' &&
el[3] === '.';
}

// MixinOptions
// - regions
// - regionClass

export default {
regionClass: Region,

// Internal method to initialize the regions that have been defined in a
// `regions` attribute on this View.
// Internal method to initialize the regions attributes
_initRegions() {

// init regions hash
this.regions = this.regions || {};
// init regions instance hash
this._regions = {};

this.addRegions(_.result(this, 'regions'));
// init regions definition hash
this.regions = _.extend({}, _.result(this, 'regions'));
},

// Internal method to re-initialize all of the regions by updating
// the `el` that they point to
_reInitRegions() {
_invoke(this._regions, 'reset');
},
// Adds or rebinds all regions associated with the view
_bindRegions() {
const regions = this.addRegions(_.extend({}, this.regions));

// Add a single region, by name, to the View
addRegion(name, definition) {
const regions = {};
regions[name] = definition;
return this.addRegions(regions)[name];
this.triggerMethod('bind:regions', this, regions);
},

// Add multiple regions as a {name: definition, name2: def2} object literal
addRegions(regions) {
// If there's nothing to add, stop here.
if (_.isEmpty(regions)) {
return;
// Finds an existing ui with `@ui.` or finds the `el` on the DOM
_findEl(el) {
if (_.isString(el) && startsWithUi(el)) {
return this.ui[el.slice(4)];
}

// Normalize region selectors hash to allow
// a user to use the @ui. syntax.
regions = this.normalizeUIValues(regions, 'el');

// Add the regions definitions to the regions property
this.regions = _.extend({}, this.regions, regions);

return this._addRegions(regions);
},

// internal method to build and add regions
_addRegions(regionDefinitions) {
const defaults = {
regionClass: this.regionClass,
parentEl: _.partial(_.result, this, 'el')
};

return _.reduce(regionDefinitions, (regions, definition, name) => {
regions[name] = buildRegion(definition, defaults);
this._addRegion(regions[name], name);
return regions;
}, {});
return this.Dom.findEl(this.el, el);
},

_addRegion(region, name) {
this.triggerMethod('before:add:region', this, name, region);
_buildRegion(name, RegionClass, options) {
const region = new RegionClass(options);

region._parentView = this;
region._name = name;

this._regions[name] = region;

this.triggerMethod('add:region', this, name, region);
return region;
},

// Remove a single region from the View, by name
removeRegion(name) {
const region = this._regions[name];
// Add a single region, by name, to the View
addRegion(name, definition) {
const currentRegion = this.getRegion(name);
definition = normalizeRegion(definition, this.regionClass);

this._removeRegion(region, name);
this.regions[name] = definition;

return region;
},
const options = _.extend({}, definition);
options.el = this._findEl(options.el);

// Remove all regions from the View
removeRegions() {
const regions = this._getRegions();
if (currentRegion) {
return currentRegion.setElement(options.el);
}

_.each(this._regions, this._removeRegion.bind(this));
const RegionClass = options.regionClass;
delete options.regionClass;

return regions;
return this._buildRegion(name, RegionClass, options);
},

_removeRegion(region, name) {
this.triggerMethod('before:remove:region', this, name, region);
// Add multiple region definitions
addRegions(regionDefinitions) {
return _.map(regionDefinitions, (definition, name) => {
return this.addRegion(name, definition);
});
},

region.destroy();
// Remove a single region from the View, by name
removeRegion(name) {
return this.getRegion(name).destroy();
},

this.triggerMethod('remove:region', this, name, region);
// Remove all regions from the View
removeRegions() {
const regions = this._getRegions();
_invoke(regions, 'destroy');
return regions;
},

// Called in a region's destroy
Expand Down Expand Up @@ -134,7 +125,7 @@ export default {
},

_getRegions() {
return _.clone(this._regions);
return _.extend({}, this._regions);
},

// Get all regions
Expand All @@ -158,5 +149,4 @@ export default {
getChildView(name) {
return this.getRegion(name).currentView;
}

};
47 changes: 9 additions & 38 deletions src/mixins/ui.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
import _ from 'underscore';
// allows for the use of the @ui. syntax within
// a given key for triggers and events
// swaps the @ui with the associated selector.
// Returns a new, non-mutated, parsed events hash.
const normalizeUIKeys = function(hash, ui) {
return _.reduce(hash, (memo, val, key) => {
const normalizedKey = normalizeUIString(key, ui);
memo[normalizedKey] = val;
return memo;
}, {});
};

const uiRegEx = /@ui\.[a-zA-Z-_$0-9]*/g;

Expand All @@ -21,30 +10,19 @@ const normalizeUIString = function(uiString, ui) {
});
};

// allows for the use of the @ui. syntax within
// a given value for regions
// swaps the @ui with the associated selector
const normalizeUIValues = function(hash, ui, property) {
_.each(hash, (val, key) => {
if (_.isString(val)) {
hash[key] = normalizeUIString(val, ui);
} else if (val) {
const propertyVal = val[property];
if (_.isString(propertyVal)) {
val[property] = normalizeUIString(propertyVal, ui);
}
}
});
return hash;
};

export default {

// normalize the keys of passed hash with the views `ui` selectors.
// `{"@ui.foo": "bar"}`
// allows for the use of the @ui. syntax within
// a given key for triggers and events
// swaps the @ui with the associated selector.
// Returns a new, non-mutated, parsed events hash.
normalizeUIKeys(hash) {
const uiBindings = this._getUIBindings();
return normalizeUIKeys(hash, uiBindings);
return _.reduce(hash, (memo, val, key) => {
const normalizedKey = normalizeUIString(key, uiBindings);
memo[normalizedKey] = val;
return memo;
}, {});
},

// normalize the passed string with the views `ui` selectors.
Expand All @@ -54,13 +32,6 @@ export default {
return normalizeUIString(uiString, uiBindings);
},

// normalize the values of passed hash with the views `ui` selectors.
// `{foo: "@ui.bar"}`
normalizeUIValues(hash, property) {
const uiBindings = this._getUIBindings();
return normalizeUIValues(hash, uiBindings, property);
},

_getUIBindings() {
const uiBindings = _.result(this, '_uiBindings');
return uiBindings || _.result(this, 'ui');
Expand Down
Loading

0 comments on commit 061dd23

Please sign in to comment.