mirror of
https://github.com/pebble-dev/clay.git
synced 2026-08-27 20:36:33 -04:00
drop ClayEvents.one since it is a pain to work with and add tests for ClayEvents
This commit is contained in:
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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
@@ -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 < 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
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -17,7 +17,6 @@ describe('ClayItem', function() {
|
||||
'$element',
|
||||
'$manipulatorTarget',
|
||||
'on',
|
||||
'one',
|
||||
'off',
|
||||
'trigger',
|
||||
'initialize'
|
||||
|
||||
Reference in New Issue
Block a user