180 lines
4.5 KiB
JavaScript
180 lines
4.5 KiB
JavaScript
|
// requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel
|
||
|
(function () {
|
||
|
var lastTime = 0;
|
||
|
var vendors = ['ms', 'moz', 'webkit', 'o'];
|
||
|
for (var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
|
||
|
window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame'];
|
||
|
window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame'];
|
||
|
}
|
||
|
|
||
|
if (!window.requestAnimationFrame) {
|
||
|
window.requestAnimationFrame = function (callback, element) {
|
||
|
var currTime = new Date().getTime();
|
||
|
var timeToCall = Math.max(0, 16 - (currTime - lastTime));
|
||
|
var id = window.setTimeout(function () {
|
||
|
callback(currTime + timeToCall);
|
||
|
},
|
||
|
timeToCall);
|
||
|
lastTime = currTime + timeToCall;
|
||
|
return id;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
if (!window.cancelAnimationFrame) {
|
||
|
window.cancelAnimationFrame = function (id) {
|
||
|
clearTimeout(id);
|
||
|
};
|
||
|
}
|
||
|
}());
|
||
|
|
||
|
var spec;
|
||
|
var reporterCurrentSpec = {
|
||
|
specStarted: function (result) {
|
||
|
spec = result.fullName;
|
||
|
}
|
||
|
};
|
||
|
|
||
|
jasmine.getEnv().addReporter(reporterCurrentSpec);
|
||
|
|
||
|
/**
|
||
|
* Utilities to help the tests
|
||
|
* @type {Object}
|
||
|
*/
|
||
|
var TestUtil = {};
|
||
|
window.ACTIVE_LOCALE = 'en';
|
||
|
|
||
|
_t = function (attrs) {
|
||
|
return attrs;
|
||
|
};
|
||
|
|
||
|
TestUtil.config = {
|
||
|
};
|
||
|
|
||
|
TestUtil.linkedObjects = function (view) {
|
||
|
function flatten_views (view) {
|
||
|
var flatten = [];
|
||
|
var sub = view._subviews;
|
||
|
flatten.push(view);
|
||
|
for (var k in sub) {
|
||
|
var v = sub[k];
|
||
|
flatten.push(v);
|
||
|
flatten = flatten.concat(flatten_views(v));
|
||
|
}
|
||
|
return flatten;
|
||
|
}
|
||
|
var views = flatten_views(view);
|
||
|
view.clean = _.once(view.clean); // eslint-disable-line
|
||
|
view.clean();
|
||
|
|
||
|
function evented_objects (obj) {
|
||
|
var ev = [];
|
||
|
for (var k in obj) {
|
||
|
var o = obj[k];
|
||
|
if (k !== '_parent' && o && obj.hasOwnProperty(k) && o._callbacks) {
|
||
|
ev.push(o);
|
||
|
}
|
||
|
}
|
||
|
return ev;
|
||
|
}
|
||
|
|
||
|
function callback_context (o) {
|
||
|
var c = [];
|
||
|
var callbacks = o._callbacks;
|
||
|
for (var i in callbacks) {
|
||
|
var node = callbacks[i];
|
||
|
var end = node.tail;
|
||
|
while ((node = node.next) !== end) {
|
||
|
if (node.context) {
|
||
|
c.push(node.context.cid);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return c;
|
||
|
}
|
||
|
|
||
|
function already_linked () {
|
||
|
var linked = [];
|
||
|
// check no pending callbacks
|
||
|
for (var k in views) {
|
||
|
var v = views[k];
|
||
|
var objs = evented_objects(v);
|
||
|
for (var o in objs) {
|
||
|
if (_.include(callback_context(objs[o]), v.cid)) {
|
||
|
linked.push(v);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return linked;
|
||
|
}
|
||
|
|
||
|
return already_linked();
|
||
|
};
|
||
|
|
||
|
TestUtil.assertNotLeaks = function (view) {
|
||
|
expect(TestUtil.linkedObjects(view).length).toEqual(0);
|
||
|
};
|
||
|
|
||
|
TestUtil._view = function (v) {
|
||
|
// 1) name of view property in "this" context, e.g. "foobarView"
|
||
|
// 2) view object as param, e.g. foobarView
|
||
|
// 3) this.view defined in a beforeEach
|
||
|
return this[v] || v || this.view;
|
||
|
};
|
||
|
|
||
|
beforeEach(function () {
|
||
|
jasmine.addMatchers({
|
||
|
toHaveNoLeaks: function () {
|
||
|
if (arguments.length > 0) {
|
||
|
// throw new Error('toHaveNoLeaks not take arguments, use toHaveBeenCalledWith');
|
||
|
}
|
||
|
|
||
|
return {
|
||
|
compare: function (actual, expected) {
|
||
|
var linked = TestUtil.linkedObjects(actual);
|
||
|
if (linked.length) {
|
||
|
console.log('** linked objects');
|
||
|
for (var i in linked) {
|
||
|
console.log(linked[i]);
|
||
|
}
|
||
|
}
|
||
|
var result = {};
|
||
|
result.pass = linked.length === 0;
|
||
|
result.message = 'Expected objects not linked (' + linked.length + '), check the console';
|
||
|
return result;
|
||
|
}
|
||
|
};
|
||
|
}
|
||
|
});
|
||
|
|
||
|
this.innerHTML = function (v) {
|
||
|
return TestUtil._view.call(this, v).el.innerHTML;
|
||
|
};
|
||
|
|
||
|
this.$html = function (v) {
|
||
|
return TestUtil._view.call(this, v).$el.html();
|
||
|
};
|
||
|
});
|
||
|
|
||
|
afterEach(function () {
|
||
|
if (this.view && this.view.clean) {
|
||
|
this.view.clean();
|
||
|
}
|
||
|
|
||
|
var afterTestResults = false;
|
||
|
var childNodes = [];
|
||
|
|
||
|
Array.prototype.slice.call(document.body.children).forEach(function (childNode) {
|
||
|
if (!afterTestResults && childNode.className === 'jasmine_html-reporter') {
|
||
|
afterTestResults = true;
|
||
|
} else if (afterTestResults) {
|
||
|
childNodes.push(childNode);
|
||
|
}
|
||
|
});
|
||
|
|
||
|
if (childNodes.length > 0) {
|
||
|
var msg = spec + ': DOM nodes found that should have been removed! By default this.view.clean() is called afterEach test, do you have others?';
|
||
|
console.warn(msg, childNodes);
|
||
|
throw new Error(msg + ' See dev console for details');
|
||
|
}
|
||
|
});
|