Migrate cdb.core.View form cartodb.js

pull/7703/head
Nicklas Gummesson 8 years ago
parent 209afc71b6
commit bfad7277ea

2
.gitignore vendored

@ -53,7 +53,7 @@ vendor/bundle/*
vendor/cache/*
.vagrant
Vagrantfile
node_modules
/node_modules
.grunt/*
vendor/assets/javascripts/cartodb.*
vendor/assets/stylesheets/cartodb.*

@ -0,0 +1,4 @@
utilizes https://github.com/substack/browserify-handbook#how-node_modules-works,
to avoid annoying `require('../../../../../')` for both source and test environment
Was migrated as-is from https://github.com/CartoDB/cartodb.js/blob/470399abb12b40d5476ab6bbfd792d95aa819f50/src/core/ on May 3rd 2016

@ -0,0 +1,160 @@
var _ = require('underscore');
var Backbone = require('backbone');
/**
* NOTE! Migrated as-is from https://github.com/CartoDB/cartodb.js/blob/470399abb12b40d5476ab6bbfd792d95aa819f50/src/core/view.js 2016-06-03
* Base View for all CartoDB views.
* DO NOT USE Backbone.View directly
*/
var View = Backbone.View.extend({
classLabel: 'cdb.core.View',
constructor: function (options) {
this.options = _.defaults(options, this.options);
this._models = [];
this._subviews = {};
Backbone.View.call(this, options);
View.viewCount++;
View.views[this.cid] = this;
this._created_at = new Date();
},
add_related_model: function (m) {
if (!m) throw new Error('added non valid model');
this._models.push(m);
},
addView: function (v) {
this._subviews[v.cid] = v;
v._parent = this;
},
removeView: function (v) {
delete this._subviews[v.cid];
},
clearSubViews: function () {
_(this._subviews).each(function (v) {
v.clean();
});
this._subviews = {};
},
/**
* this methid clean removes the view
* and clean and events associated. call it when
* the view is not going to be used anymore
*/
clean: function () {
var self = this;
this.trigger('clean');
this.clearSubViews();
// remove from parent
if (this._parent) {
this._parent.removeView(this);
this._parent = null;
}
this.remove();
this.unbind();
// remove this model binding
if (this.model && this.model.unbind) this.model.unbind(null, null, this);
// remove model binding
_(this._models).each(function (m) {
m.unbind(null, null, self);
});
this._models = [];
View.viewCount--;
delete View.views[this.cid];
return this;
},
show: function () {
this.$el.show();
},
hide: function () {
this.$el.hide();
},
/**
* Listen for an event on another object and triggers on itself, with the same name or a new one
* @method retrigger
* @param ev {String} event who triggers the action
* @param obj {Object} object where the event happens
* @param obj {Object} [optional] name of the retriggered event
*/
retrigger: function (ev, obj, retrigEvent) {
if (!retrigEvent) {
retrigEvent = ev;
}
var self = this;
obj.bind && obj.bind(ev, function () {
self.trigger(retrigEvent);
}, self);
// add it as related model//object
this.add_related_model(obj);
},
/**
* Captures an event and prevents the default behaviour and stops it from bubbling
* @method killEvent
* @param event {Event}
*/
killEvent: function (ev) {
if (ev && ev.preventDefault) {
ev.preventDefault();
}
if (ev && ev.stopPropagation) {
ev.stopPropagation();
}
},
/**
* Remove all the tipsy tooltips from the document
* @method cleanTooltips
*/
cleanTooltips: function () {
this.$('.tipsy').remove();
}
}, {
viewCount: 0,
views: {},
/**
* when a view with events is inherit and you want to add more events
* this helper can be used:
* var MyView = new core.View({
* events: View.extendEvents({
* 'click': 'fn'
* })
* })
*/
extendEvents: function (newEvents) {
return function () {
return _.extend(newEvents, this.constructor.__super__.events);
};
},
/**
* search for views in a view and check if they are added as subviews
*/
runChecker: function () {
_.each(View.views, function (view) {
_.each(view, function (prop, k) {
if (k !== '_parent' &&
view.hasOwnProperty(k) &&
prop instanceof View &&
view._subviews[prop.cid] === undefined) {
console.log('=========');
console.log('untracked view: ');
console.log(prop.el);
console.log('parent');
console.log(view.el);
console.log(' ');
}
});
});
}
});
module.exports = View;

@ -0,0 +1,163 @@
var $ = require('jquery');
var _ = require('underscore');
var Backbone = require('backbone');
var CoreView = require('backbone/core-view');
describe('backbone/core-view', function () {
var TestView;
var view;
beforeEach(function () {
TestView = CoreView.extend({
initialize: function () {
this.init_called = true;
},
test_method: function () {}
});
CoreView.viewCount = 0;
view = new TestView({el: $('<div>')});
});
it('should call initialize', function () {
expect(view.init_called).toEqual(true);
});
it('should increment refCount', function () {
expect(CoreView.viewCount).toEqual(1);
expect(CoreView.views[view.cid]).toBeTruthy();
});
it('should decrement refCount', function () {
view.clean();
expect(CoreView.viewCount).toEqual(0);
expect(CoreView.views[view.cid]).toBeFalsy();
});
it('clean should remove view from dom', function () {
var dom = $('<div>');
dom.append(view.el);
expect(dom.children().length).toEqual(1);
view.clean();
expect(dom.children().length).toEqual(0);
});
it('clean should unbind all events', function () {
view.bind('meh', function () {});
expect(_.size(view._events)).toEqual(1);
view.clean();
expect(view._events).toEqual(undefined);
});
it('should unlink the view model', function () {
var called = false;
var new_view = new TestView({ el: $('<div>'), model: new Backbone.Model() });
spyOn(new_view, 'test_method');
new_view.model.bind('change', new_view.test_method, new_view);
new_view.model.bind('change', function () { called = true; });
new_view.model.trigger('change');
expect(called).toEqual(true);
expect(new_view.test_method).toHaveBeenCalled();
expect(new_view.test_method.calls.count()).toEqual(1);
called = false;
new_view.clean();
// trigger again
new_view.model.trigger('change');
expect(called).toEqual(true);
expect(new_view.test_method.calls.count()).toEqual(1);
});
it('should unlink linked models', function () {
var called = false;
var model = new Backbone.Model();
spyOn(view, 'test_method');
model.bind('change', view.test_method, view);
model.bind('change', function () { called = true; });
view.add_related_model(model);
model.trigger('change');
expect(called).toEqual(true);
expect(view.test_method).toHaveBeenCalled();
expect(view.test_method.calls.count()).toEqual(1);
called = false;
view.clean();
expect(_.size(view._models)).toEqual(0);
// trigger again
model.trigger('change');
expect(called).toEqual(true);
expect(view.test_method.calls.count()).toEqual(1);
});
it('should add and remove subview', function () {
var v1 = new CoreView();
view.addView(v1);
expect(view._subviews[v1.cid]).toEqual(v1);
expect(v1._parent).toEqual(view);
view.removeView(v1);
expect(view._subviews[v1.cid]).toEqual(undefined);
});
it('should remove and clean subviews', function () {
var v1 = new CoreView();
spyOn(v1, 'clean');
view.addView(v1);
expect(view._subviews[v1.cid]).toEqual(v1);
view.clean();
expect(view._subviews[v1.cid]).toEqual(undefined);
expect(v1.clean).toHaveBeenCalled();
});
it('subview shuould be removed from its parent', function () {
var v1 = new CoreView();
view.addView(v1);
expect(view._subviews[v1.cid]).toEqual(v1);
v1.clean();
expect(view._subviews[v1.cid]).toEqual(undefined);
});
it('extendEvents should extend events', function () {
var V1 = CoreView.extend({
events: CoreView.extendEvents({
'click': 'hide'
})
});
var v1 = new V1();
expect(v1.el.style.display).not.toEqual('none');
v1.$el.trigger('click');
expect(v1.el.style.display).toEqual('none');
});
it('should retrigger an event when launched on a descendant object', function (done) {
var launched = false;
view.child = new TestView({});
view.retrigger('cachopo', view.child);
view.bind('cachopo', function () {
launched = true;
});
view.child.trigger('cachopo');
setTimeout(function () {
expect(launched).toBeTruthy();
done();
}, 25);
});
it('should kill an event', function () {
var ev = {
stopPropagation: function () {},
preventDefault: function () {}
};
var ev2 = 'thisisnotanevent';
spyOn(ev, 'stopPropagation');
spyOn(ev, 'preventDefault');
view.killEvent(ev);
view.killEvent(ev2);
view.killEvent();
expect(ev.stopPropagation).toHaveBeenCalled();
expect(ev.preventDefault).toHaveBeenCalled();
});
});

@ -167,7 +167,8 @@ module.exports = {
'lib/build/source-map-support.js',
// Add specs for browserify module code here:
'lib/assets/test/spec/cartodb3/**/*.spec.js'
'lib/assets/test/spec/cartodb3/**/*.spec.js',
'lib/assets/test/spec/node_modules/**/*.spec.js'
],
dest: '.grunt/cartodb3-specs.js'
}

Loading…
Cancel
Save