Socket
Socket
Sign inDemoInstall

ampersand-view

Package Overview
Dependencies
Maintainers
7
Versions
71
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ampersand-view - npm Package Compare versions

Comparing version 7.4.2 to 8.0.0

.validate.json

89

ampersand-view.js

@@ -20,3 +20,2 @@ /*$AMPERSAND_VERSION*/

function View(attrs) {

@@ -37,3 +36,3 @@ this.cid = uniqueId('view');

this.initialize.apply(this, arguments);
this.set(pick(attrs, viewOptions));
this._rendered = this.rendered; // prep `rendered` derived cache immediately
if (this.autoRender && this.template) {

@@ -72,11 +71,8 @@ this.render();

el: 'element',
collection: 'collection'
collection: 'collection',
},
session: {
_rendered: ['boolean', true, false]
},
derived: {
rendered: {
deps: ['el'],
fn: function () {
return !!this.el;
}
},
hasData: {

@@ -87,2 +83,13 @@ deps: ['model'],

}
},
rendered: {
deps: ['_rendered'],
fn: function() {
if (this._rendered) {
this.trigger('render', this);
return true;
}
this.trigger('remove', this);
return false;
}
}

@@ -95,7 +102,6 @@ }

// List of view options to be merged as properties.
var viewOptions = ['model', 'collection', 'el'];
View.prototype = Object.create(BaseState.prototype);
var queryNoElMsg = 'Query cannot be performed as this.el is not defined. Ensure that the view has been rendered.';
// Set up all inheritable properties and methods.

@@ -110,2 +116,5 @@ assign(View.prototype, {

query: function (selector) {
if (!this.el) {
throw new Error(queryNoElMsg);
}
if (!selector) return this.el;

@@ -124,5 +133,7 @@ if (typeof selector === 'string') {

queryAll: function (selector) {
if (!this.el) {
throw new Error(queryNoElMsg);
}
if (!selector) return [this.el];
var res = [];
if (!this.el) return res;
if (selector === '') return [this.el];
if (matches(this.el, selector)) res.push(this.el);

@@ -150,16 +161,17 @@ return res.concat(Array.prototype.slice.call(this.el.querySelectorAll(selector)));

// **render** is the core function that your view can override, its job is
// **render** is the core function that your view can override. Its job is
// to populate its element (`this.el`), with the appropriate HTML.
render: function () {
_render: function () {
this.renderWithTemplate(this);
this._rendered = true;
return this;
},
// Remove this view by taking the element out of the DOM, and removing any
// Removes this view by taking the element out of the DOM, and removing any
// applicable events listeners.
remove: function () {
_remove: function () {
var parsedBindings = this._parsedBindings;
if (this.el && this.el.parentNode) this.el.parentNode.removeChild(this.el);
this._rendered = false;
if (this._subviews) invoke(flatten(this._subviews), 'remove');
this.trigger('remove', this);
this.stopListening();

@@ -279,4 +291,8 @@ // TODO: Not sure if this is actually necessary.

var self = this;
//backwards compatibility with older versions, when `container` was a valid property (#114)
if (subview.container) {
subview.selector = subview.container;
}
var opts = {
selector: subview.container || '[data-hook="' + subview.hook + '"]',
selector: subview.selector || '[data-hook="' + subview.hook + '"]',
waitFor: subview.waitFor || '',

@@ -305,3 +321,2 @@ prepareView: subview.prepareView || function (el) {

// Shortcut for doing everything we need to do to

@@ -388,6 +403,38 @@ // render and fully replace current root element.

return this.registerSubview(collectionView);
},
_setRender: function(obj) {
Object.defineProperty(obj, 'render', {
get: function() {
return this._render;
},
set: function(fn) {
this._render = function() {
fn.apply(this, arguments);
this._rendered = true;
return this;
};
}
});
},
_setRemove: function(obj) {
Object.defineProperty(obj, 'remove', {
get: function() {
return this._remove;
},
set: function(fn) {
this._remove = function() {
fn.apply(this, arguments);
this._rendered = false;
return this;
};
}
});
}
});
View.prototype._setRender(View.prototype);
View.prototype._setRemove(View.prototype);
View.extend = BaseState.extend;
module.exports = View;
{
"name": "ampersand-view",
"description": "A smart base view for Backbone apps, to make it easy to bind collections and properties to the DOM.",
"version": "7.4.2",
"version": "8.0.0",
"author": "Henrik Joreteg <henrik@andyet.net>",

@@ -62,3 +62,7 @@ "browser": "./ampersand-view.js",

"start": "run-browser test/index.js",
"test": "browserify test/index.js | tape-run | tap-spec"
"test": "browserify test/index.js | tape-run | tap-spec",
"preversion": "git checkout master && git pull && npm ls",
"publish-patch": "npm run preversion && npm version patch && git push origin master --tags && npm publish",
"publish-minor": "npm run preversion && npm version minor && git push origin master --tags && npm publish",
"publish-major": "npm run preversion && npm version major && git push origin master --tags && npm publish"
},

@@ -65,0 +69,0 @@ "testling": {

@@ -296,2 +296,4 @@ # ampersand-view

ampersand-view triggers a `'render'` event for your convenience, too, if you want to set listeners for it. The `'render'` and `'remove'` events emitted by this module are merely convenience events, as you may listen solely to `change:rendered` in order to capture the render/remove events in just one listener.
### renderCollection `view.renderCollection(collection, ItemView, containerEl, [viewOptions])`

@@ -481,3 +483,3 @@

Removes a view from the DOM, and calls `stopListening` to remove any bound events that the view has `listenTo`'d. This method also triggers a `remove` event on the view, allowing for listeners (or the view itself) to listen to it and do some action, like cleanup some other resources being used.
Removes a view from the DOM, and calls `stopListening` to remove any bound events that the view has `listenTo`'d. This method also triggers a `remove` event on the view, allowing for listeners (or the view itself) to listen to it and do some action, like cleanup some other resources being used. The view will trigger the `remove` event if `remove()` is overridden.

@@ -553,3 +555,3 @@ ```javascript

myStuff: {
container: '[data-hook=collection-container]',
selector: '[data-hook=collection-container]',
waitFor: 'model.stuffCollection',

@@ -564,3 +566,3 @@ prepareView: function (el) {

tab: {
container: '[data-hook=switcher]',
hook: 'switcher',
constructor: ViewSwitcher

@@ -574,3 +576,3 @@ }

* container {String} Selector that describes the element within the view that should hold the subview.
* selector {String} Selector that describes the element within the view that should hold the subview.
* hook {String} Alternate method for specifying a container element using its `data-hook` attribute. Equivalent to `selector: '[data-hook=some-hook]'`.

@@ -606,2 +608,3 @@ * constructor {ViewConstructor} Any [view conventions compliant](http://ampersandjs.com/learn/view-conventions) view constructor. It will be initialized with `{el: [Element grabbed from selector], parent: [reference to parent view instance]}`. So if you don't need to do any custom setup, you can just provide the constructor.

- 8.0.0 Improve `rendered` property behavior. `rendered` now set after calling render()/remove() fns, vs. old strategy which simply checked for `view.el`
- 7.0.0 Replacing use of `role` in lieu of `data-hook` for [accessibility reasons discussed here](https://github.com/AmpersandJS/ampersand/issues/21)

@@ -608,0 +611,0 @@ - [insert period of poor changelog management here], this will not happen again now that ampersand is public.

var test = require('tape');
var AmpersandModel = require('ampersand-model');
var AmpersandCollection = require('ampersand-rest-collection');
var AmpersandView = require('../ampersand-view');

@@ -42,2 +43,90 @@

test('event behavior with over-ridden `render` & `remove` fns', function (t) {
var renderCount = 0;
t.plan(4);
var ChildView = AmpersandView.extend({
render: function() {
AmpersandView.prototype.render.call(this);
t.ok(true, 'child view render called');
}
});
var GrandChildView = AmpersandView.extend({
render: function() {
ChildView.prototype.render.call(this);
t.ok(true, 'grand child view render called');
}
});
var detachedEl = document.createElement('div');
var view = new GrandChildView({
template: '<span></span>',
el: detachedEl
});
view.on('render', function(view, value) {
++renderCount;
t.ok(true, 'view `render` event happened on `render()`');
});
view.render();
view.remove();
t.equal(1, renderCount, 'over-ridden `render` triggered render just once');
t.end();
});
test('standard `rendered` attr behavior', function (t) {
var caughtRenderEvt = false;
var detachedEl = document.createElement('div');
var view = new AmpersandView({
template: '<span></span>',
el: detachedEl
});
view.on('change:rendered', function() {
caughtRenderEvt = !caughtRenderEvt;
});
t.notOk(view.rendered, 'view not `rendered` prior to `render()` call');
view.render();
t.ok(view.rendered, 'view `rendered` post `render()` call');
t.ok(caughtRenderEvt, 'view `rendered` evt observed on `render()` call');
view.remove();
t.notOk(caughtRenderEvt, 'view `rendered` evt observed on `remove()` call');
t.notOk(view.rendered, 'view not `rendered` post `remove()` call');
t.end();
});
test('user over-ridden `render()` and `remove()` behavior', function (t) {
var view;
var RenderTestView = AmpersandView.extend({
template: '<span></span>',
render: function() {
t.ok(true, 'user defined `render()` executed');
},
remove: function() {
t.ok(true, 'user defined `remove()` executed');
}
});
t.plan(4);
view = new RenderTestView();
view.on('change:rendered', function() {
t.ok(true, '`rendered` triggered on custom render/remove');
});
view.render();
view.remove();
t.end();
});
test('Model, collection, and el become properties', function (t) {
var model = new Model();
var collection = new AmpersandCollection();
var el = document.createElement('div');
var view = new AmpersandView({
model: model,
collection: collection,
el: el
});
t.equal(view.model, model);
t.equal(view.collection, collection);
t.equal(view.el, el);
t.end();
});
test('registerSubview', function (t) {

@@ -123,3 +212,3 @@ var removeCalled = 0;

var instance = new View(),
rendered = instance.render();
rendered = instance.render();
t.equal(instance, rendered);

@@ -383,3 +472,68 @@ t.equal(typeof rendered.span, 'object');

test('query should throw an error if view was not rendered', function (t) {
var View = AmpersandView.extend({
autoRender: false,
template: '<div class="test"><div class="test deep"><div class="test deep"></div></div></div>'
});
var view = new View();
t.throws((function () {
view.query('.test');
}), Error, 'Throws error on query with selector');
t.throws((function () {
view.query('');
}), Error, 'Throws error on query with empty selector');
t.end();
});
test('query should not throw an error if view was rendered', function (t) {
var View = AmpersandView.extend({
autoRender: false,
template: '<div class="test"><div class="test deep"><div class="test deep"></div></div></div>'
});
var view = new View();
view.render();
t.doesNotThrow((function () {
view.query('.test');
}), Error, 'Does not throws error on query');
t.doesNotThrow((function () {
view.query('');
}), Error, 'Does not throws error on empty selector');
t.end();
});
test('queryAll should throw an error if view was not rendered', function (t) {
var View = AmpersandView.extend({
autoRender: false,
template: '<div class="test"><div class="test deep"><div class="test deep"></div></div></div>'
});
var view = new View();
t.throws((function () {
view.queryAll('div');
}), Error, 'Throws error on queryAll');
t.throws((function () {
view.queryAll('');
}), Error, 'Throws error on queryAll with empty selector');
t.end();
});
test('queryAll should not throw an error if view was rendered', function (t) {
var View = AmpersandView.extend({
autoRender: false,
template: '<div class="test"><div class="test deep"><div class="test deep"></div></div></div>'
});
var view = new View();
view.render();
t.doesNotThrow((function () {
view.queryAll('div');
}), Error, 'Does not throw error on queryAll');
t.doesNotThrow((function () {
view.queryAll('');
}), Error, 'Does not throw error on queryAll with empty selector');
t.end();
});
//test('focus/blur events should work in events hash. Issue #8', function (t) {

@@ -584,3 +738,3 @@ // t.plan(2);

test('trigger `remove` when view is removed using on', function (t) {
test('trigger `remove` event when view is removed', function (t) {
var View = AmpersandView.extend({

@@ -598,4 +752,3 @@ template: '<div></div>',

test('trigger `remove` when view is removed using listenTo', function(t){
test('trigger `remove` when view is removed using listenTo', function (t) {
var View = AmpersandView.extend({

@@ -606,3 +759,3 @@ template: '<div></div>',

var view = new View();
view.listenTo(view,'remove', function() {
view.listenTo(view, 'remove', function() {
t.pass('remove fired');

@@ -624,2 +777,24 @@ t.end();

sub1: {
selector: '.container',
constructor: Sub
}
}
});
var view = new View();
t.equal(view.el.innerHTML, '<span></span>');
t.end();
});
test('subViews declaraction can accept a CSS selector string via `container` property for backwards compatibility (#114)', function (t) {
var Sub = AmpersandView.extend({
template: '<span></span>'
});
var View = AmpersandView.extend({
template: '<div><div class="container"></div></div>',
autoRender: true,
subviews: {
sub1: {
container: '.container',

@@ -673,3 +848,3 @@ constructor: Sub

waitFor: 'model',
container: '.container',
selector: '.container',
constructor: Sub

@@ -676,0 +851,0 @@ },

SocketSocket SOC 2 Logo

Product

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

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc