Socket
Socket
Sign inDemoInstall

compago-controller

Package Overview
Dependencies
2
Maintainers
1
Versions
2
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.0.0 to 2.0.0

56

package.json
{
"name": "compago-controller",
"version": "1.0.0",
"version": "2.0.0",
"description": "A component of the Compago framework handling interactions between the application state and the DOM.",
"main": "dist/node/index.js",
"browser": "src/index.js",
"module": "src/index.js",
"keywords": [

@@ -20,8 +21,5 @@ "controller",

"scripts": {
"build-node": "babel src/index.js --out-file dist/node/index.js",
"lint": "eslint src/index.js tests/unit.test.js",
"clean": "rimraf dist && mkdirp dist dist/node",
"build": "npm run clean && npm run build-node",
"report-coverage": "cat ./coverage/lcov.info | codecov",
"test": "babel-node ./node_modules/istanbul/lib/cli cover node_modules/mocha/bin/_mocha -- -R spec tests/unit.test.js"
"test": "jest > nul"
},

@@ -54,4 +52,30 @@ "author": "Maga D. Zandaqo <denelxan@gmail.com> (http://maga.name)",

"babel": {
"presets": [
"node6"
"env": {
"test": {
"presets": [
"node7"
]
}
}
},
"jest": {
"collectCoverage": true,
"collectCoverageFrom": [
"**/src/**",
"!**/node_modules/**",
"!**/tests/**"
],
"coverageDirectory": "<rootDir>/coverage",
"coverageReporters": [
"lcov"
],
"transformIgnorePatterns": [
"<rootDir>/node_modules/(?!compago-)\\.*"
],
"moduleNameMapper": {
"compago-listener": "<rootDir>/node_modules/compago-listener/src/index.js",
"compago-region": "<rootDir>/node_modules/compago-region/src/index.js"
},
"roots": [
"<rootDir>/tests"
]

@@ -64,15 +88,11 @@ },

"devDependencies": {
"babel-cli": "^6.16.0",
"babel-preset-node6": "^11.0.0",
"codecov.io": "^0.1.6",
"eslint": "^3.7.1",
"eslint-config-airbnb-base": "^8.0.0",
"eslint-plugin-import": "^2.0.1",
"expect": "^1.20.2",
"eslint": "^3.18.0",
"eslint-config-airbnb-base": "^11.1.1",
"eslint-plugin-import": "^2.2.0",
"istanbul": "^1.1.0-alpha.1",
"mkdirp": "^0.5.1",
"mocha": "^3.1.2",
"mock-browser": "^0.92.12",
"rimraf": "^2.5.4"
"babel-jest": "^19.0.0",
"babel-preset-node7": "1.5.0",
"jest": "^19.0.2"
}
}

@@ -20,12 +20,12 @@ /* eslint-env browser */

* @param {Object} [options.handlers] the DOM event handlers for the controller
* @param {Object} [options.ui] a hash of names and respective selectors to use as shortcuts
* for selecting UI elements inside the controller
* @param {Object} [options.model] the data model used by the controller
* @param {Object} [options.view] the view or template function used in rendering the controller
* @param {Object} [options.renderEvents] the model events that cause the controller to re-render
* @param {string} [options.renderEvents] the model events that cause the controller to re-render
* @param {Array} [options.renderAttributes] the attributes of the controller's element
* that cause it to re-render
* @param {Object} [options.regions] a hash of regions of the controller
*/
constructor(options = _opt) {
const { el, tagName, attributes, handlers, ui,
model, view, renderEvents, regions } = options;
const { el, tagName, attributes, handlers, model,
view, renderEvents, renderAttributes, regions } = options;
Object.assign(this, Listener);

@@ -38,6 +38,5 @@ this.tagName = tagName || 'div';

this._setEventHandlers();
this.uiSelectors = ui;
this.ui = undefined;
this.regionSelectors = regions;
this.regions = undefined;
this._observer = undefined;
this.model = model;

@@ -48,2 +47,5 @@ this.view = view;

}
if (renderAttributes) {
this._observeAttributes(renderAttributes);
}
}

@@ -55,4 +57,3 @@

* By default, invokes `this.view` supplying the controller's element and model if present,
* establishes links (if `this.ui` is specified), prepares the controller's regions,
* and returns the controller's DOM element.
* prepares the controller's regions, and returns the controller's DOM element.
*

@@ -62,4 +63,3 @@ * @returns {HTMLElement} the DOM element of the controller

render() {
if (this.view) this.view(this.el, this.model);
this._linkUI();
if (this.view) this.view(this.el, this);
this._ensureRegions();

@@ -172,3 +172,6 @@ return this.el;

this._disposeRegions();
this.ui = undefined;
if (this._observer) {
this._observer.disconnect();
this._observer = undefined;
}
const parent = this.el.parentNode;

@@ -211,3 +214,3 @@ if (parent) parent.removeChild(this.el);

if (prevent) event.preventDefault();
const field = bond !== true ? bond : target.dataset.bond;
const field = bond !== true ? bond : target.getAttribute('data-bond');
this.model.set({ [field]: typeof parse === 'function' ? parse(target[value]) : target[value] }, { nested });

@@ -268,7 +271,5 @@ }

} else {
for (let el = event.target; el && el !== this.el; el = el.parentElement) {
if (Controller._matches.call(el, selector)) {
cb.call(this, event, el, data);
break;
}
const el = event.target.closest(selector);
if (el && this.el.contains(el)) {
cb.call(this, event, el, data);
}

@@ -314,17 +315,2 @@ }

/**
* Establishes links to controller's UI elements.
*
* @returns {void}
*/
_linkUI() {
if (!this.uiSelectors) return;
this.ui = {};
const names = Object.keys(this.uiSelectors);
for (let i = 0; i < names.length; i++) {
const name = names[i];
this.ui[name] = this.el.querySelector(this.uiSelectors[name]);
}
}
/**
* Disposes all regions of the controller.

@@ -346,3 +332,17 @@ *

/**
* Sets up a Mutation Observer to watch for changes in attributes of the controller.
*
* @param {Array} attributeFilter the list attributes to watch
* @returns {void}
*/
_observeAttributes(attributeFilter) {
const observer = new MutationObserver(() => {
this.render();
});
observer.observe(this.el, { attributes: true, attributeFilter });
this._observer = observer;
}
/**
*
* @param {Function} callback

@@ -366,5 +366,2 @@ * @param {number} wait

/** The reference to the native implementation of `matchesSelector` method. */
Controller._matches = (typeof Element !== 'undefined') ? Element.prototype.matches || Element.prototype.msMatchesSelector : undefined;
export default Controller;

@@ -1,4 +0,4 @@

/* eslint-env node, mocha, browser */
import expect from 'expect';
import { mocks } from 'mock-browser';
/* eslint-env jest, browser */
/* globals jest, expect */
import Region from 'compago-region';

@@ -9,5 +9,12 @@ import Listener from 'compago-listener';

const mb = new mocks.MockBrowser();
GLOBAL.document = mb.getDocument();
Controller._matches = mb.getWindow().Element.prototype.matches;
window.Element.prototype.closest = function (selector) {
let el = this;
while (el) {
if (el.matches(selector)) {
return el;
}
el = el.parentElement;
}
return null;
};

@@ -17,2 +24,3 @@ describe('Controller', () => {

let el;
beforeEach(() => {

@@ -23,3 +31,3 @@ v = new Controller();

v.el.appendChild(el);
v.someMethod = expect.createSpy();
v.someMethod = jest.fn();
v.handlers = v._prepareHandlers({

@@ -92,3 +100,3 @@ click: 'someMethod',

model = {
set: expect.createSpy(),
set: jest.fn(),
};

@@ -99,3 +107,3 @@ v.model = model;

v.el.appendChild(input);
event = { type: 'input', target: input, preventDefault: expect.createSpy() };
event = { type: 'input', target: input, preventDefault: jest.fn() };
});

@@ -109,3 +117,3 @@

expect(model.set).toHaveBeenCalled();
expect(model.set.calls[0].arguments).toEqual([{ name: '' }, { nested: false }]);
expect(model.set.mock.calls[0]).toEqual([{ name: '' }, { nested: false }]);
});

@@ -119,3 +127,3 @@

expect(model.set).toHaveBeenCalled();
expect(model.set.calls[0].arguments).toEqual([{ 'name.first': '' }, { nested: true }]);
expect(model.set.mock.calls[0]).toEqual([{ 'name.first': '' }, { nested: true }]);
});

@@ -129,3 +137,3 @@

expect(model.set).toHaveBeenCalled();
expect(model.set.calls[0].arguments).toEqual([{ name: '' }, { nested: false }]);
expect(model.set.mock.calls[0]).toEqual([{ name: '' }, { nested: false }]);
expect(event.preventDefault).toHaveBeenCalled();

@@ -142,12 +150,12 @@ });

expect(model.set).toHaveBeenCalled();
expect(model.set.calls[0].arguments).toEqual([{ id: 1 }, { nested: false }]);
expect(model.set.mock.calls[0]).toEqual([{ id: 1 }, { nested: false }]);
});
it('debounces handlers if `debounce` is set', () => {
expect.spyOn(Controller, '_handleDebounce').andCallThrough();
const spy = jest.spyOn(Controller, '_handleDebounce');
v.handlers = v._prepareHandlers({
'input #name': { bond: 'name', debounce: 1000 },
});
expect(Controller._handleDebounce).toHaveBeenCalled();
expect.restoreSpies();
expect(spy).toHaveBeenCalled();
spy.mockRestore();
});

@@ -172,4 +180,4 @@ });

beforeEach(() => {
v.otherMethod = expect.createSpy();
v.yetAnother = expect.createSpy();
v.otherMethod = jest.fn();
v.yetAnother = jest.fn();
});

@@ -192,7 +200,7 @@

v._handle(event);
expect(v.someMethod.calls.length).toBe(1);
expect(v.otherMethod.calls.length).toBe(1);
expect(v.yetAnother.calls.length).toBe(0);
expect(v.someMethod.calls[0].arguments).toEqual([event, submit, undefined]);
expect(v.otherMethod.calls[0].arguments).toEqual([event, undefined, undefined]);
expect(v.someMethod.mock.calls.length).toBe(1);
expect(v.otherMethod.mock.calls.length).toBe(1);
expect(v.yetAnother.mock.calls.length).toBe(0);
expect(v.someMethod.mock.calls[0]).toEqual([event, submit, undefined]);
expect(v.otherMethod.mock.calls[0]).toEqual([event, undefined, undefined]);
});

@@ -202,5 +210,5 @@

expect(v._handle({ type: 'nonExistantEvent' })).toBe(undefined);
expect(v.someMethod.calls.length).toBe(0);
expect(v.otherMethod.calls.length).toBe(0);
expect(v.yetAnother.calls.length).toBe(0);
expect(v.someMethod.mock.calls.length).toBe(0);
expect(v.otherMethod.mock.calls.length).toBe(0);
expect(v.yetAnother.mock.calls.length).toBe(0);
});

@@ -211,4 +219,4 @@ });

beforeEach(() => {
v.el.addEventListener = expect.createSpy();
v.el.removeEventListener = expect.createSpy();
v.el.addEventListener = jest.fn();
v.el.removeEventListener = jest.fn();
});

@@ -218,4 +226,4 @@

v._setEventHandlers();
expect(v.el.addEventListener.calls.length).toBe(1);
expect(v.el.addEventListener.calls[0].arguments).toEqual(['click', v._handle]);
expect(v.el.addEventListener.mock.calls.length).toBe(1);
expect(v.el.addEventListener.mock.calls[0]).toEqual(['click', v._handle]);
});

@@ -226,4 +234,4 @@

v._setEventHandlers(true);
expect(v.el.removeEventListener.calls.length).toBe(1);
expect(v.el.removeEventListener.calls[0].arguments).toEqual(['click', v._handle]);
expect(v.el.removeEventListener.mock.calls.length).toBe(1);
expect(v.el.removeEventListener.mock.calls[0]).toEqual(['click', v._handle]);
});

@@ -245,4 +253,4 @@ });

v.undelegate();
v.el.addEventListener = expect.createSpy();
v.el.removeEventListener = expect.createSpy();
v.el.addEventListener = jest.fn();
v.el.removeEventListener = jest.fn();
});

@@ -253,5 +261,5 @@

expect(v.handlers.get('mouseover')[0]).toEqual([v.someMethod, '#submit']);
expect(v.el.addEventListener.calls.length).toBe(1);
expect(v.el.removeEventListener.calls.length).toBe(0);
expect(v.el.addEventListener.calls[0].arguments).toEqual(['mouseover', v._handle]);
expect(v.el.addEventListener.mock.calls.length).toBe(1);
expect(v.el.removeEventListener.mock.calls.length).toBe(0);
expect(v.el.addEventListener.mock.calls[0]).toEqual(['mouseover', v._handle]);
});

@@ -264,5 +272,5 @@

expect(v.handlers.get('mouseover')[1]).toEqual(v.someMethod);
expect(v.el.addEventListener.calls.length).toBe(1);
expect(v.el.removeEventListener.calls.length).toBe(0);
expect(v.el.addEventListener.calls[0].arguments).toEqual(['mouseover', v._handle]);
expect(v.el.addEventListener.mock.calls.length).toBe(1);
expect(v.el.removeEventListener.mock.calls.length).toBe(0);
expect(v.el.addEventListener.mock.calls[0]).toEqual(['mouseover', v._handle]);
});

@@ -273,3 +281,3 @@

expect(v.handlers.get('mouseover')).toBe(undefined);
expect(v.el.addEventListener.calls.length).toBe(0);
expect(v.el.addEventListener.mock.calls.length).toBe(0);
});

@@ -279,4 +287,4 @@

v.delegate();
expect(v.el.addEventListener.calls.length).toBe(1);
expect(v.el.removeEventListener.calls.length).toBe(1);
expect(v.el.addEventListener.mock.calls.length).toBe(1);
expect(v.el.removeEventListener.mock.calls.length).toBe(1);
});

@@ -288,4 +296,4 @@ });

v.undelegate();
v.el.addEventListener = expect.createSpy();
v.el.removeEventListener = expect.createSpy();
v.el.addEventListener = jest.fn();
v.el.removeEventListener = jest.fn();
});

@@ -296,4 +304,4 @@

v.undelegate();
expect(v.el.addEventListener.calls.length).toBe(1);
expect(v.el.removeEventListener.calls.length).toBe(2);
expect(v.el.addEventListener.mock.calls.length).toBe(1);
expect(v.el.removeEventListener.mock.calls.length).toBe(2);
});

@@ -313,4 +321,4 @@

expect(v.handlers.get('mouseover')).toBe(undefined);
expect(v.el.removeEventListener.calls.length).toBe(1);
expect(v.el.removeEventListener.calls[0].arguments).toEqual(['mouseover', v._handle]);
expect(v.el.removeEventListener.mock.calls.length).toBe(1);
expect(v.el.removeEventListener.mock.calls[0]).toEqual(['mouseover', v._handle]);
});

@@ -321,35 +329,15 @@ });

it('renders and returns the controller element', () => {
v.view = expect.createSpy();
v.view = jest.fn();
v.model = {};
const result = v.render();
expect(result).toBe(v.el);
expect(v.view.calls.length).toBe(1);
expect(v.view.calls[0].arguments).toEqual([v.el, v.model]);
expect(v.view.mock.calls.length).toBe(1);
expect(v.view.mock.calls[0]).toEqual([v.el, v]);
});
});
describe('_linkUI', () => {
it('establishes links to the UI elements of the controller', () => {
v.uiSelectors = {
header: '#header',
footer: '#footer',
};
const header = document.createElement('div');
header.setAttribute('id', 'header');
v.el.appendChild(header);
v._linkUI();
expect(v.ui.header).toBe(header);
expect(v.ui.footer).toEqual(null);
expect(v.uiSelectors.header).toBe('#header');
v._linkUI();
expect(v.ui.header).toBe(header);
expect(v.uiSelectors.header).toBe('#header');
});
});
describe('_disposeRegions', () => {
it('disposes all regions of the layout', () => {
const region = new Region(el);
region.dispose = expect.createSpy();
region.dispose = jest.fn();
v.regions = { region };

@@ -378,3 +366,3 @@ v._disposeRegions();

it('disposes of the regions of the controller', () => {
v._disposeRegions = expect.createSpy();
v._disposeRegions = jest.fn();
v.dispose();

@@ -386,3 +374,3 @@ expect(v._disposeRegions).toHaveBeenCalled();

const model = {
dispose: expect.createSpy(),
dispose: jest.fn(),
};

@@ -392,3 +380,3 @@

v.dispose({ save: true });
expect(model.dispose).toNotHaveBeenCalled();
expect(model.dispose).not.toHaveBeenCalled();
expect(v.model).toBe(undefined);

@@ -407,12 +395,16 @@

v.otherMethod = expect.createSpy();
v.otherMethod = jest.fn();
v.on(v, 'dispose', v.otherMethod);
v.dispose({ silent: true });
expect(v.otherMethod).toNotHaveBeenCalled();
expect(v.otherMethod).not.toHaveBeenCalled();
});
});
describe('_handleDebounce', (done) => {
it('creates a closure to debounce event handlers for a given time', () => {
const callback = expect.createSpy();
xdescribe('_observeAttributes', () => {
// todo wait for MutationObserver support in jsdom
});
describe('_handleDebounce', () => {
it('creates a closure to debounce event handlers for a given time', (done) => {
const callback = jest.fn();
const debounce = Controller._handleDebounce(callback, 500);

@@ -423,3 +415,3 @@ expect(typeof debounce).toBe('function');

setTimeout(() => {
expect(callback.calls.length).toBe(1);
expect(callback.mock.calls.length).toBe(1);
done();

@@ -426,0 +418,0 @@ }, 2000);

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc