drop ClayEvents.one since it is a pain to work with and add tests for ClayEvents

This commit is contained in:
Keegan
2016-02-09 17:19:41 -08:00
parent 80982c8e6d
commit c0f6fb770c
6 changed files with 265 additions and 39 deletions
+11
View File
@@ -193,7 +193,18 @@ ClayConfig.registerComponent = function(component) {
var _component = _.copyObj(component);
if (typeof _component.manipulator === 'string') {
_component.manipulator = manipulators[component.manipulator];
if (!_component.manipulator) {
throw new Error('The manipulator: ' + component.manipulator +
' does not exist in the built-in manipulators.');
}
}
if (typeof _component.manipulator.set !== 'function' ||
typeof _component.manipulator.get !== 'function') {
throw new Error('The manipulator must have both a `get` and `set` method');
}
componentStore[_component.name] = _component;
};
+39 -33
View File
@@ -1,7 +1,7 @@
'use strict';
var $ = require('../vendor/minified/minified').$;
var _ = require('../vendor/minified/minified')._;
/**
* Attaches event methods to the context.
* Call with ClayEvents.call(yourObject, $eventTarget)
@@ -11,48 +11,51 @@ var $ = require('../vendor/minified/minified').$;
*/
function ClayEvents($eventTarget) {
var self = this;
var _eventProxies = {};
var _eventProxies = [];
/**
* Attach an event listener to the item. This proxies minified.js' on.
* If you are using a native event like "change", consider using "|change" instead
* as this will allow the native events to still work
* @see {@link http://minifiedjs.com/api/on.html|.on()}
* prefixes events with "|"
* @param {string} events
* @param {function} handler
* @returns {object}
* @returns {string}
* @private
*/
self.on = function(events, handler) {
var _events = events.split(' ').map(function(event) {
var _transformEventNames = function(events) {
return events.split(' ').map(function(event) {
return '|' + event.replace(/^\|/, '');
}).join(' ');
var self = this;
_eventProxies[handler] = function() {
handler.apply(self, arguments);
};
$eventTarget.on(_events, _eventProxies[handler]);
return self;
};
var _registerEventProxy = function(handler, proxy) {
var eventProxy = _.find(_eventProxies, function(item) {
return item.handler === handler ? item : null;
});
if (!eventProxy) {
eventProxy = { handler: handler, proxy: proxy };
_eventProxies.push(eventProxy);
}
return eventProxy.proxy;
};
var _getEventProxy = function(handler) {
return _.find(_eventProxies, function(item) {
return item.handler === handler ? item.proxy : null;
});
};
/**
* Attach an event listener to the item. This proxies minified.js' one.
* If you are using a native event like "change", consider using "|change" instead
* as this will allow the native events to still work
* @see {@link http://minifiedjs.com/api/one.html|.one()}
* @param {string} events
* Attach an event listener to the item.
* @param {string} events - a space separated list of events
* @param {function} handler
* @returns {object}
* @returns {ClayEvents}
*/
self.one = function(events, handler) {
var _events = events.split(' ').map(function(event) {
return '|' + event.replace(/^\|/, '');
}).join(' ');
self.on = function(events, handler) {
var _events = _transformEventNames(events);
var self = this;
_eventProxies[handler] = function(event) {
var _proxy = _registerEventProxy(handler, function() {
handler.apply(self, arguments);
$.off(_eventProxies[handler]);
};
$eventTarget.on(_events, _eventProxies[handler]);
});
$eventTarget.on(_events, _proxy);
return self;
};
@@ -60,10 +63,13 @@ function ClayEvents($eventTarget) {
* Remove the given event handler.
* @see {@link http://minifiedjs.com/api/off.html|$.off()}
* @param {function} handler
* @returns {object}
* @returns {ClayEvents}
*/
self.off = function(handler) {
$.off(_eventProxies[handler]);
var _proxy = _getEventProxy(handler);
if (_proxy) {
$.off(_proxy);
}
return self;
};
@@ -73,7 +79,7 @@ function ClayEvents($eventTarget) {
* @param {object} [eventObj] - an object to pass to the event handler,
* provided the handler does not have custom arguments.
* @see {@link http://minifiedjs.com/api/trigger.html|.trigger()}
* @returns {object}
* @returns {ClayEvents}
*/
self.trigger = function(name, eventObj) {
$eventTarget.trigger(name, eventObj);
+69 -2
View File
@@ -1,7 +1,8 @@
// minified.js config start -- use this comment to re-create a configuration in the Builder
// - Only sections add, always, amdsupport, copyobj, dollardollar,
// - each, eachobj, error, extend, format, formathtml, get, ht, html, isobject,
// - off, on, ready, request, select, set, template, trigger, underscore, wait.
// - each, eachobj, error, extend, find, format, formathtml, get, ht, html,
// - isobject, off, on, ready, request, select, set, template, trigger, underscore,
// - wait.
// WARNING! This file is autogenerated from minified-master.js and others.
@@ -1549,6 +1550,69 @@ define('minified', function() {
*/
'each': listBind(each),
/*$
* @id find
* @group LIST
* @requires
* @configurable default
* @name .find()
* @altname _.find()
* @syntax list.find(findFunc)
* @syntax list.find(element)
* @syntax list.find(findFunc, startIndex)
* @syntax list.find(element, startIndex)
* @syntax _.find(list, findFunc)
* @syntax _.find(list, element)
* @syntax _.find(list, findFunc, startIndex)
* @syntax _.find(list, element, startIndex)
* @module WEB, UTIL
* Finds a specific value in the list. There are two ways of calling <var>find()</var>:
* <ol>
* <li>With a value as argument. Then <var>find()</var> will search for the first occurrence of an identical value in the list,
* using the '===' operator for comparisons, and return the index. If it is not found,
* <var>find()</var> returns <var>undefined</var>.</li>
* <li>With a callback function. <var>find()</var> will then call the given function for each list element until the function
* returns a value that is not <var>null</var> or <var>undefined</var>. This value will be returned.</li>
* </ol>
*
* <var>find()</var> can also be used as an alternative to ##each() if you need to abort the loop.
*
* @example Finds the first negative number in the list:
* <pre>
* var i = _(1, 2, -4, 5, 2, -1).find(function(value, index) { if (value &lt; 0) return index; }); // returns 2
* </pre>
* @example Finds the index of the first 5 in the array:
* <pre>
* var i = _.find([3, 6, 7, 6, 5, 4, 5], 5); // returns 4 (index of first 5)
* </pre>
*
* @example Determines the position of the element with the id '#wanted' among all li elements:
* <pre>
* var elementIndex = $('li').find($$('#wanted'));
* </pre>
*
* @example Goes through the elements to find the first div that has the class 'myClass', and returns this element:
* <pre>
* var myClassElement = $('div').find(function(e) { if ($(e).is('.myClass')) return e; });
* </pre>
*
* @param list A list to use as input. Can be an array, a ##list#Minified list## or any other array-like structure with
* <var>length</var> property.
* @param findFunc The callback <code>function(item, index)</code> that will be invoked for every list item until it returns a non-null value:
* <dl><dt>item</dt><dd>The current list element.</dd><dt>index</dt><dd>The second the zero-based index of the current element.</dd>
* <dt class="this">this</dt><dd>This list.</dd>
* <dt class="returnValue">(callback return value)</dt><dd>If the callback returns something other than <var>null</var> or
* <var>undefined</var>, <var>find()</var> will return it directly. Otherwise it will continue. </dd></dl>
* @param element the element to search for
* @param startIndex optional the 0-based index of the first element to search.
* @return if called with an element, either the element's index in the list or <var>undefined</var> if not found. If called with a callback function,
* it returns either the value returned by the callback or <var>undefined</var>.
*
* @see ##findLast() is the equivalent to <var>find()</var> for the list's end.
*/
'find': listBind(find),
/*$
* @stop
*/
@@ -2559,6 +2623,9 @@ define('minified', function() {
// @condblock each
'toObject': toObject,
// @condend
// @condblock find
'find': find,
// @condend
/*$
* @id copyobj
+32 -3
View File
@@ -1,7 +1,7 @@
'use strict';
var assert = require('chai').assert;
var sinon = require('sinon');
var _ = require('../../../src/scripts/vendor/minified/minified')._;
var textComponent = require('pebble-clay-components/dist/components/text');
var componentRegistry = require('../../../src/scripts/lib/component-registry');
var checkReadOnly = require('../../test-utils').checkReadOnly;
@@ -18,7 +18,6 @@ describe('ClayConfig', function() {
'registerComponent',
'build',
'on',
'one',
'off',
'trigger'
];
@@ -129,7 +128,37 @@ describe('ClayConfig', function() {
clayConfig.build();
});
// @todo test for validation
it('throws if manipulator is a string and does not match built-in manipulator',
function(done) {
var clayConfig = fixtures.clayConfig(['text'], true);
var _textComponent = _.copyObj(textComponent);
_textComponent.manipulator = 'not_real';
clayConfig.on(clayConfig.EVENTS.BEFORE_BUILD, function() {
assert.throws(function() {
clayConfig.registerComponent(_textComponent);
}, new RegExp('not_real'));
done();
});
clayConfig.build();
});
it('throws if manipulator does not have a `get` and `set` method',
function(done) {
var clayConfig = fixtures.clayConfig(['text'], true);
var _textComponent = _.copyObj(textComponent);
_textComponent.manipulator = {};
clayConfig.on(clayConfig.EVENTS.BEFORE_BUILD, function() {
assert.throws(function() {
clayConfig.registerComponent(_textComponent);
}, /(get.*set)|(set.*get)/);
done();
});
clayConfig.build();
});
});
describe('.build()', function() {
+114
View File
@@ -0,0 +1,114 @@
'use strict';
var sinon = require('sinon');
var assert = require('chai').assert;
var ClayEvents = require('../../../src/scripts/lib/clay-events');
var $ = require('../../../src/scripts/vendor/minified/minified').$;
var HTML = require('../../../src/scripts/vendor/minified/minified').HTML;
/**
* @extends ClayEvents
*/
var ctx;
var eventCounter = 0;
var createEventName = function() {
eventCounter++;
return 'test-event-' + eventCounter;
};
describe('ClayEvents', function() {
beforeEach(function() {
ctx = {};
ClayEvents.call(ctx, $(HTML('<div>')));
});
it('registers the methods on the context', function() {
['on', 'off', 'trigger'].forEach(function(method) {
assert.typeOf(ctx[method], 'function');
});
});
describe('.on()', function() {
it('registers one event', function() {
var eventName = createEventName();
var eventHandlerSpy = sinon.spy();
ctx.on(eventName, eventHandlerSpy);
ctx.trigger(eventName);
ctx.trigger(eventName);
assert(eventHandlerSpy.calledTwice, 'handler not called 2 times');
assert(eventHandlerSpy.alwaysCalledOn(ctx), 'handler not called on ctx');
});
it('registers multiple events', function() {
var eventName1 = createEventName();
var eventName2 = createEventName();
var eventHandlerSpy = sinon.spy();
ctx.on(eventName1 + ' ' + eventName2, eventHandlerSpy);
ctx.trigger(eventName1);
ctx.trigger(eventName1);
ctx.trigger(eventName2);
ctx.trigger(eventName2);
assert.strictEqual(eventHandlerSpy.callCount, 4, 'handler not called 4 times');
assert(eventHandlerSpy.alwaysCalledOn(ctx), 'handler not called on ctx');
});
});
describe('.off()', function() {
it('deregisters the handler for all events on the context', function() {
var eventName1 = createEventName();
var eventName2 = createEventName();
var eventHandlerSpy = sinon.spy();
var ctx1 = ctx;
var ctx2 = {};
ClayEvents.call(ctx2, $(HTML('<div>')));
ctx.id = 1;
ctx1.on(eventName1, eventHandlerSpy);
ctx1.on(eventName2, eventHandlerSpy);
ctx2.on(eventName2, eventHandlerSpy);
ctx1.trigger(eventName1);
ctx1.trigger(eventName2);
ctx2.trigger(eventName2);
ctx1.off(eventHandlerSpy);
ctx1.trigger(eventName1);
ctx1.trigger(eventName2);
ctx2.trigger(eventName2);
assert.strictEqual(eventHandlerSpy.callCount, 4, 'handler not called 4 times');
});
it('does nothing if the handler does not exist', function() {
// register a fake event so _getEventProxy() has something to look for
ctx.on(createEventName(), sinon.spy());
assert.doesNotThrow(function() {
ctx.off(sinon.spy());
});
});
});
describe('.trigger()', function() {
it('triggers the handler for the event with custom data', function() {
var eventName = createEventName();
var eventHandlerSpy = sinon.spy();
var customData = {foo: 'bar'};
ctx.on(eventName, eventHandlerSpy);
ctx.trigger(eventName, customData);
assert(eventHandlerSpy.calledOnce, 'handler not called 2 times');
assert(eventHandlerSpy.alwaysCalledOn(ctx), 'handler not called on ctx');
assert(eventHandlerSpy.calledWith(customData), 'handler not called on ctx');
});
});
});
-1
View File
@@ -17,7 +17,6 @@ describe('ClayItem', function() {
'$element',
'$manipulatorTarget',
'on',
'one',
'off',
'trigger',
'initialize'