diff --git a/bower.json b/bower.json index 901bcd2..f575c71 100755 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "backbone.siren", - "version": "0.4.1", + "version": "0.4.2", "dependencies": { "backbone": "~1.1.0", "jquery": "~2.0.0", diff --git a/dist/amd/backbone.siren.js b/dist/amd/backbone.siren.js index 18356fd..947db13 100644 --- a/dist/amd/backbone.siren.js +++ b/dist/amd/backbone.siren.js @@ -1,5 +1,5 @@ /* -* Backbone.Siren v0.4.1 +* Backbone.Siren v0.4.2 * * Copyright (c) 2016 Kiva Microfunds * Licensed under the MIT license. @@ -1232,8 +1232,8 @@ define(['jquery', 'underscore', 'backbone'], function ($, _, Backbone) { , getRootForPath: function (path) { // remove parameters an anchor tags from path var strippedPath = path.split(/[\?#]/)[0]; - // grab the parent path (0 is "", 1 is parent) - var strippedPathParent = '/' + strippedPath.split('/')[1]; + // grab the parent path + var strippedPathParent = strippedPath.split('/')[0]; return this.alternateRoots[strippedPath] ? this.alternateRoots[strippedPath] : this.alternateRoots[strippedPathParent] ? this.alternateRoots[strippedPathParent] : this.apiRoot; } diff --git a/dist/amd/backbone.siren.min.js b/dist/amd/backbone.siren.min.js index 69c2d69..9eb02b0 100644 --- a/dist/amd/backbone.siren.min.js +++ b/dist/amd/backbone.siren.min.js @@ -1,8 +1,8 @@ /* -* Backbone.Siren v0.4.1 +* Backbone.Siren v0.4.2 * * Copyright (c) 2016 Kiva Microfunds * Licensed under the MIT license. * https://github.com/kiva/backbone.siren/blob/master/license.txt */ -define(["jquery","underscore","backbone"],function(a,b,c){"use strict";function d(a,c){var d,e;return d=b.filter(a.links,function(a){return!(!a.rel||!b.filter(a.rel,function(a){return a==c}).length)})[0],d&&(e=d.href),e}function e(a){var b;return b=a.href?a.href:a.links?d(a,"self"):""}function f(a){var c;return b.find(a.rel,function(a){return c=/name:(.*)/.exec(a)}),b.last(c)}function g(a){return a.name||f(a)}function h(a,c){return b.indexOf(a["class"],c)>-1}function i(a){return b.indexOf(this.classes(),a)>-1}function j(){return this._data["class"]||[]}function k(){return this._data.title}function l(){return this._data.rel||[]}function m(a){return b.indexOf(this.rel(),a)>-1}function n(a){return"self"==a?e(this._data):d(this._data,a)}function o(){return this._data.links||[]}function p(){return this.link("self")}function q(a){var c={};return b.each(a,function(a,d){b.each(a,function(a){c[a]=d})}),c}function r(){return this._actions||[]}function s(a){return b.find(this._actions,function(b){return b.name==a})}function t(a){var b=!0;return a["class"]&&(b=this.hasClass(a["class"])),a.rel&&(b=this.hasRel(a.rel)),b}function u(a){var c=b.find(this._data.links,function(c){return b.indexOf(c.rel,a)>-1});if(c)return y.resolveOne(c.href)}function v(c){c=a.extend(this.siren.ajaxOptions||{},c);var d=new a.Deferred;if(this.once("sync",function(a){d.resolve(a)}),c.forceFetch||!this.isLoaded)this.fetch(c);else if(b.isEmpty(this._data)){if(c.url){var e=this,f=y.parseChain(c.url),g=f.pop();delete c.url,g&&b.isEmpty(f)?this.resolve(b.extend(b.clone(c),{url:g,forceFetch:!0})).done(function(a){d.resolve(a)}):g&&y.resolveOne(y.stringifyChain(f),c).done(function(a){e.resolve(b.extend(b.clone(c),{url:a.get(g).url(),forceFetch:!0})).done(function(a){d.resolve(a)})})}}else d.resolve(this);return d.promise()}function w(c,d){d=d||{};var e,f,g;if(d.deferred||(d.deferred=new a.Deferred),!b.isArray(c)||b.isEmpty(c))return d.deferred.resolve(this);if(e=c.shift(),f=y.isCollection(this)?this.at(e):this.get(e),!f)throw new ReferenceError('The entity you are looking for, "'+e+'" is not a sub-entity at '+this.url()+".");return g=y.stringifyChain(c),g=g?f.url()+"#"+g:f.url(),y.resolveOne(g,d)}function x(){var a=this,c=[];if(this._data)return b.each(this._data.actions,function(b){var d=new y.Action(b,a);c.push(d)}),a._actions=c,c}var y,z=function(){y.settings.showWarnings&&console&&console.warn.apply(console,arguments)};y=c.Siren=function(a,b){this.store=new c.Siren.Store,this.init(a,b)},b.extend(y,{settings:{showWarnings:!0},warn:z,isHydratedObject:function(a){return!(!a||!a.cid&&!a.models||!a._data)},isLoaded:function(a){return!(!a.links||a.href)},isCollection:function(a){return a instanceof c.Siren.Collection},isRawCollection:function(a){return h(a,"collection")},isRawError:function(a){return h(a,"error")},isRawSiren:function(a){return!!e(a)},addModelToStore:function(a,b){a.addModel(b)},addCollectionToStore:function(a,b,c){var d;return c?void a.addCollection(b,c):(d=b.link("current"),d&&a.addCollection(b,"current"),void a.addCollection(b,"self"))},serializeData:function(a,c){return c=c||{},y.isHydratedObject(a)?b.indexOf(c.renderedEntities,a.url())<0?a.toJSON(c):void 0:a},parseModel:function(a,b){b=b||{};var d,e=b.store;return e&&(d=e.get(a)),d?d.update(a,b):d=new c.Siren.Model(a,b),d},parseCollection:function(a,b){b=b||{};var e,f,g,h,i=b.store;return i?(e=i.get(a),e?e.update(a,b):(b.representationToStore="self",e=new c.Siren.Collection(a,b)),h=d(a,"current"),h&&(f=i.get(h),f?f.update(a,b):(b.representationToStore="current",f=new c.Siren.Collection(a,b))),g=f||e):g=new c.Siren.Collection(a,b),g},parse:function(a,b){return b=b||{},y.isRawCollection(a)?this.parseCollection(a,b):y.isRawError(a)?new c.Siren.Model(a,b):y.isRawSiren?this.parseModel(a,b):void 0},ajax:function(a,d){return d=b.extend({url:a,dataType:"json"},d),c.ajax(d)},parseChain:function(a){return"string"!=typeof a&&new TypeError("Must be a string"),a.replace(/^#|#$/,"").split("#")},stringifyChain:function(a){return b.isArray(a)||new TypeError("Must be an array"),a.join("#")},resolve:function(a,c){return b.isArray(a)?y.resolveMany(a,c):y.resolveOne(a,c)},resolveMany:function(c,d){d=d||{};var e=this,f=b.map(c,function(a){return e.resolveOne(a,b.clone(d))});return a.when.apply(a,f)},resolveOne:function(c,d){d=d||{};var e,f,g,h,i,j=y.parseChain(c),k=j.shift(),l=d.deferred;return d.store&&(e=d.store),e&&(h=e.getRequest(k),h&&(f=h.state())),b.isEmpty(j)&&("resolved"==f&&!d.forceFetch||"pending"==f)?l?h.done(function(a){l.resolve(a)}):h:(l||(l=new a.Deferred),"pending"==f?h.done(function(a){d.deferred=l,a.resolveNextInChain(j,d)}):(e&&(i=e.get(k)),i&&i.isLoaded&&!d.forceFetch?(d.deferred=l,i.resolveNextInChain(j,d)):(g=new a.Deferred,e&&e.addRequest(d.data?k+"?"+a.param(d.data):k,g.promise()),y.ajax(k,d).done(function(a){var b=y.parse(a,d);g.resolve(b),d.deferred=l,b.resolveNextInChain(j,d)}).fail(function(a){var b,c;try{b=JSON.parse(a.responseText)}catch(e){b={}}c=y.parse(b,d),g.reject(c,a),l.reject(c,a)}))),l.promise())},Model:c.Model.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,resolveEntities:function(c){var d=this,e=[];return b.each(this._data.entities,function(a){e.push(d.resolveEntity(a,c))}),a.when(e).done(function(){d.trigger("resolve",d)})},resolveEntity:function(b,c){c=c||{};var d,f,h=this,i=new a.Deferred;return b.href&&"linked"==c.autoFetch||"all"==c.autoFetch?y.resolveOne(e(b),c).done(function(a){i.resolve(h.setEntity(a,b.rel,g(b)))}):(d=y.parse(b,c),f=i.resolve(this.setEntity(d,b.rel,g(b)))),f},setEntity:function(a,b,c){var d={rel:b,entity:a};return c&&(this.set(c,a),d.name=c),this._entities.push(d),a},parse:function(a,b){return this._data=a,this._entities=[],this.isLoaded=y.isLoaded(a),this.resolveEntities(b),a.properties},toJSON:function(a){a=a||{},a.renderedEntities=a.renderedEntities||[];var c,d={},e=this;return a&&a.actionName&&(c=this.getActionByName(a.actionName)),a.renderedEntities.push(this.url()),c?b.each(c.fields,function(b){a.actionName=b.action,d[b.name]=y.serializeData(e.get(b.name),a)}):b.each(this.attributes,function(b,c){d[c]=y.serializeData(b,a)}),d},entities:function(a){var c=b.map(this._entities,function(a){return a.entity});return a&&(c=b.filter(c,function(b){return b.match(a)})),c},isNew:function(){return!this.url()},update:function(a,b){return y.isLoaded(a)&&(this.set(this.parse(a,b),b),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Model.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addModelToStore(b.store,this)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}}),Collection:c.Collection.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,parse:function(a,c){c=c||{},this._data=a,this._meta=a.properties||{},this.isLoaded=y.isLoaded(a);var d=c.preParsedModels||b.map(a.entities,function(a){return y.parse(a,c)});return d},meta:function(a){return this._meta[a]},toJSON:function(a){return a=a||{},a.renderedEntities=a.renderedEntities||[],a.renderedEntities.push(this.url()),this.map(function(b){var c=b.toJSON(a);return a.actionName&&(c.id=b.id),c})},save:function(a,c){return c=b.extend({validate:!0},c),this._validate&&this._validate(a,c),void 0===c.parse&&(c.parse=!0),this.sync("create",this,c)},update:function(a,b){return y.isLoaded(a)&&(this.add(this.parse(a,b)),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Collection.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addCollectionToStore(b.store,this,b.representationToStore)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}})}),y.prototype={init:function(a,b){b=b||{},this.apiRoot=a,this.options=b,this.isAbsoluteRegExp=new RegExp("^(?:[a-z]+:)?//","i"),this.alternateRoots=q(b.alternateRoots)},entityPathToUrl:function(a){return this.isAbsoluteRegExp.test(a)?a:this.getRootForPath(a)+"/"+a},getRootForPath:function(a){var b=a.split(/[\?#]/)[0],c="/"+b.split("/")[1];return this.alternateRoots[b]?this.alternateRoots[b]:this.alternateRoots[c]?this.alternateRoots[c]:this.apiRoot},resolve:function(c,d){d=a.extend({},this.options,d),d.store=this.store;var e=this,f=[];return f="string"==typeof c?this.entityPathToUrl(c):b.map(c,function(a){return e.entityPathToUrl(a)}),y.resolve(f,d)}};var A=c.Siren.Action=function(a,c){var d;b.extend(this,{"class":[],method:"GET",type:"application/x-www-form-urlencoded"},a),b.indexOf(this["class"],"batch")>-1&&b.isEmpty(this.fields)&&(d=c.first(),d&&(this.fields=d.getActionByName(this.name).fields)),this.parent=c};A.prototype={hasClass:function(a){return b.indexOf(this["class"],a)>-1},match:function(a){var b=!0;return a?(a["class"]&&(b=this.hasClass(a["class"])),a.name&&(b=this.name==a.name),b):b},getFieldByName:function(a){return b.find(this.fields,function(b){return b.name==a})},getSecureKeys:function(){var a=this.secureKeys;return a?a:(this.secureKeys=new c.Model,this.secureKeys)},getSecureKey:function(a){var b=this.secureKeys;return b?b.get(a):void 0},setSecureKey:function(a,b){return this.getSecureKeys().set(a,b)},clearSecureKeys:function(){return this.getSecureKeys().clear()},clearSecureKey:function(a){return this.getSecureKeys().unset(a)},execute:function(a){a=a||{};var d,e,f=a.attributes,g=this.name,h=this.parent,i=h&&h.siren&&h.siren.store,j={url:this.href,actionName:g,success:function(a,b,d){h.trigger("sync:"+g,a,b,d),c.Siren.parse(b,{store:i,silent:d.silent})},error:function(a,b,c){h.trigger("error:"+g,a,b,c)}};return delete a.attributes,h?(this.method&&(j.type=this.method),this.type&&(j.contentType=this.type),"PATCH"==j.type&&(a.patch=!0),h instanceof c.Model?(d=h.clone(),d._data=h._data,d._actions=h._actions,d.on("request",function(a,b,c){h.trigger("request",a,b,c),h.trigger("request:"+g,a,b,c)})):(d=h,h.on("request",function(a,b,c){h.trigger("request:"+g,a,b,c)})),a=b.extend(j,h.siren.ajaxOptions||{},a),f=b.extend(h.toJSON({actionName:this.name}),f),e=d.save(f,a),h.validationError=d.validationError,e):void 0}};var B=c.Siren.Store=function(){this.data={},this.requests={}};return B.prototype={addModel:function(a){return this.data[a.url()]=a,this},addCollection:function(a,b){return this.data[a.link(b||"self")]=a,this},get:function(a){return this.data["object"==typeof a?e(a):a]},getCurrentCollection:function(a){return y.isLoaded(a)?this.data[d(a,"current")]:this.data[e(a)]},filter:function(a){var c=new RegExp(a);return b.filter(this.data,function(a,b){return c.test(b)})},exists:function(a){return!!this.get(c.Siren.isHydratedObject(a)?a.url():a)},addRequest:function(a,b){var c=this;return b.done(function(){c.requests[a]=null}),this.requests[a]=b,this},getRequest:function(a){return this.requests[a]}},c.Siren.FormView=c.View.extend({tagName:"form",_events:{submit:"handleFormSubmit"},handleFormSubmit:function(a){a.preventDefault();var d=this,e={};b.each(this.fieldAttributes,function(a,b){var f=a.model;f&&(f instanceof c.Model?e[b]=f.get(b):a.isSecure?(e[b]=f.action.getSecureKey(b),f.action.clearSecurekeys()):"function"==typeof f&&(e[b]=f.call(d)))}),this.model.getActionByName(this.action.name).execute({attributes:e})},template:function(a){var c='<% _.each(data.fieldAttributes, function (field, fieldName) { %>
<% if (field.label) { %><% } %> <% if ((field.type == "radio" || field.type == "checkbox") && _.isArray(field.value)) { %> <% _.each(field.options, function (checked, val) { %> /><% }); %> <% } else if ((field.type == "radio" || field.type == "checkbox") && _.isObject(field.value)) { %> <% _.each(field.options, function (option, name) { %> /><% }); %> <% } else { %> id="<%= field.id %>" <% } if (field.value) { %> value="<%= field.value %>" <% } %> <%= field.checked %> <%= field.required %> /> <% } %>
<% }); %> ';return b.template(c,a,{variable:"data"})},parseAttributes:function(a,b){return b=b||{},{id:b.id||a.name+"-form",enctype:b.enctype||a.type,method:b.method||a.method,action:b.action||a.href,title:b.title||a.title,novalidate:!b.validation}},parseFieldAttributes:function(a,c){c=c||{};var d={},e=a.fields;return b.each(e,function(e){var f,g,h;if("entity"==e.type?console.log("@todo - how to handle sub-entity views?"):"entity"!=e.type&&(f=e.name,h=a.parent.get(f),g=b.extend({value:h,type:"text"},e,c[f]),"checkbox"==g.type?b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)?(g.options=[],b.each(g.value,function(a,c){g.options.push({value:a,label:c,checked:b.indexOf(h,a)>-1?"checked":""})})):g.value?g.checked="checked":g.checked="":"radio"==g.type&&(b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)&&(g.options=[],b.each(g.value,function(a,b){g.options.push({value:b,label:a,checked:h==b?"checked":""})}))),g.required=g.required?"required":""),g){var i=f.split("."),j=d,k=i.length;b.each(i,function(a,b){j[a]||(b==k-1?j[a]=g:j[a]={}),j=j[a]})}}),d},setFieldAttributes:function(c){var d={};return b.each(this.fieldAttributes,function(b,e){d[e]=a.extend(b,c[e])}),this.fieldAttributes=d,this},getFieldAttributes:function(){return this.fieldAttributes},render:function(){var a={fieldAttributes:this.fieldAttributes};return this.templateHelpers&&b.extend(a,this.templateHelpers),this.$el.html(this.template(a)),this},setAction:function(a){if(!(a.parent instanceof c.Siren.Model))throw'Action object either missing required "parent" or "parent" is not a Backbone.Siren Model';return this.action=a,this.model=a.parent,this},initializeForm:function(a){var b=a.action;if(!b)throw'Missing required property: "action"';this.setAction(b),this.cid?this.$el.attr(this.parseAttributes(b,a.attributes)):a.attributes=this.parseAttributes(a.action,a.attributes),this.fieldAttributes=this.parseFieldAttributes(b,a.fieldAttributes)},initialize:function(){this.render()},constructor:function(a){a=a||{},a.action&&this.initializeForm(a),this.events=b.extend(this._events,this.events),c.View.call(this,a)}}),c}); \ No newline at end of file +define(["jquery","underscore","backbone"],function(a,b,c){"use strict";function d(a,c){var d,e;return d=b.filter(a.links,function(a){return!(!a.rel||!b.filter(a.rel,function(a){return a==c}).length)})[0],d&&(e=d.href),e}function e(a){var b;return b=a.href?a.href:a.links?d(a,"self"):""}function f(a){var c;return b.find(a.rel,function(a){return c=/name:(.*)/.exec(a)}),b.last(c)}function g(a){return a.name||f(a)}function h(a,c){return b.indexOf(a["class"],c)>-1}function i(a){return b.indexOf(this.classes(),a)>-1}function j(){return this._data["class"]||[]}function k(){return this._data.title}function l(){return this._data.rel||[]}function m(a){return b.indexOf(this.rel(),a)>-1}function n(a){return"self"==a?e(this._data):d(this._data,a)}function o(){return this._data.links||[]}function p(){return this.link("self")}function q(a){var c={};return b.each(a,function(a,d){b.each(a,function(a){c[a]=d})}),c}function r(){return this._actions||[]}function s(a){return b.find(this._actions,function(b){return b.name==a})}function t(a){var b=!0;return a["class"]&&(b=this.hasClass(a["class"])),a.rel&&(b=this.hasRel(a.rel)),b}function u(a){var c=b.find(this._data.links,function(c){return b.indexOf(c.rel,a)>-1});if(c)return y.resolveOne(c.href)}function v(c){c=a.extend(this.siren.ajaxOptions||{},c);var d=new a.Deferred;if(this.once("sync",function(a){d.resolve(a)}),c.forceFetch||!this.isLoaded)this.fetch(c);else if(b.isEmpty(this._data)){if(c.url){var e=this,f=y.parseChain(c.url),g=f.pop();delete c.url,g&&b.isEmpty(f)?this.resolve(b.extend(b.clone(c),{url:g,forceFetch:!0})).done(function(a){d.resolve(a)}):g&&y.resolveOne(y.stringifyChain(f),c).done(function(a){e.resolve(b.extend(b.clone(c),{url:a.get(g).url(),forceFetch:!0})).done(function(a){d.resolve(a)})})}}else d.resolve(this);return d.promise()}function w(c,d){d=d||{};var e,f,g;if(d.deferred||(d.deferred=new a.Deferred),!b.isArray(c)||b.isEmpty(c))return d.deferred.resolve(this);if(e=c.shift(),f=y.isCollection(this)?this.at(e):this.get(e),!f)throw new ReferenceError('The entity you are looking for, "'+e+'" is not a sub-entity at '+this.url()+".");return g=y.stringifyChain(c),g=g?f.url()+"#"+g:f.url(),y.resolveOne(g,d)}function x(){var a=this,c=[];if(this._data)return b.each(this._data.actions,function(b){var d=new y.Action(b,a);c.push(d)}),a._actions=c,c}var y,z=function(){y.settings.showWarnings&&console&&console.warn.apply(console,arguments)};y=c.Siren=function(a,b){this.store=new c.Siren.Store,this.init(a,b)},b.extend(y,{settings:{showWarnings:!0},warn:z,isHydratedObject:function(a){return!(!a||!a.cid&&!a.models||!a._data)},isLoaded:function(a){return!(!a.links||a.href)},isCollection:function(a){return a instanceof c.Siren.Collection},isRawCollection:function(a){return h(a,"collection")},isRawError:function(a){return h(a,"error")},isRawSiren:function(a){return!!e(a)},addModelToStore:function(a,b){a.addModel(b)},addCollectionToStore:function(a,b,c){var d;return c?void a.addCollection(b,c):(d=b.link("current"),d&&a.addCollection(b,"current"),void a.addCollection(b,"self"))},serializeData:function(a,c){return c=c||{},y.isHydratedObject(a)?b.indexOf(c.renderedEntities,a.url())<0?a.toJSON(c):void 0:a},parseModel:function(a,b){b=b||{};var d,e=b.store;return e&&(d=e.get(a)),d?d.update(a,b):d=new c.Siren.Model(a,b),d},parseCollection:function(a,b){b=b||{};var e,f,g,h,i=b.store;return i?(e=i.get(a),e?e.update(a,b):(b.representationToStore="self",e=new c.Siren.Collection(a,b)),h=d(a,"current"),h&&(f=i.get(h),f?f.update(a,b):(b.representationToStore="current",f=new c.Siren.Collection(a,b))),g=f||e):g=new c.Siren.Collection(a,b),g},parse:function(a,b){return b=b||{},y.isRawCollection(a)?this.parseCollection(a,b):y.isRawError(a)?new c.Siren.Model(a,b):y.isRawSiren?this.parseModel(a,b):void 0},ajax:function(a,d){return d=b.extend({url:a,dataType:"json"},d),c.ajax(d)},parseChain:function(a){return"string"!=typeof a&&new TypeError("Must be a string"),a.replace(/^#|#$/,"").split("#")},stringifyChain:function(a){return b.isArray(a)||new TypeError("Must be an array"),a.join("#")},resolve:function(a,c){return b.isArray(a)?y.resolveMany(a,c):y.resolveOne(a,c)},resolveMany:function(c,d){d=d||{};var e=this,f=b.map(c,function(a){return e.resolveOne(a,b.clone(d))});return a.when.apply(a,f)},resolveOne:function(c,d){d=d||{};var e,f,g,h,i,j=y.parseChain(c),k=j.shift(),l=d.deferred;return d.store&&(e=d.store),e&&(h=e.getRequest(k),h&&(f=h.state())),b.isEmpty(j)&&("resolved"==f&&!d.forceFetch||"pending"==f)?l?h.done(function(a){l.resolve(a)}):h:(l||(l=new a.Deferred),"pending"==f?h.done(function(a){d.deferred=l,a.resolveNextInChain(j,d)}):(e&&(i=e.get(k)),i&&i.isLoaded&&!d.forceFetch?(d.deferred=l,i.resolveNextInChain(j,d)):(g=new a.Deferred,e&&e.addRequest(d.data?k+"?"+a.param(d.data):k,g.promise()),y.ajax(k,d).done(function(a){var b=y.parse(a,d);g.resolve(b),d.deferred=l,b.resolveNextInChain(j,d)}).fail(function(a){var b,c;try{b=JSON.parse(a.responseText)}catch(e){b={}}c=y.parse(b,d),g.reject(c,a),l.reject(c,a)}))),l.promise())},Model:c.Model.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,resolveEntities:function(c){var d=this,e=[];return b.each(this._data.entities,function(a){e.push(d.resolveEntity(a,c))}),a.when(e).done(function(){d.trigger("resolve",d)})},resolveEntity:function(b,c){c=c||{};var d,f,h=this,i=new a.Deferred;return b.href&&"linked"==c.autoFetch||"all"==c.autoFetch?y.resolveOne(e(b),c).done(function(a){i.resolve(h.setEntity(a,b.rel,g(b)))}):(d=y.parse(b,c),f=i.resolve(this.setEntity(d,b.rel,g(b)))),f},setEntity:function(a,b,c){var d={rel:b,entity:a};return c&&(this.set(c,a),d.name=c),this._entities.push(d),a},parse:function(a,b){return this._data=a,this._entities=[],this.isLoaded=y.isLoaded(a),this.resolveEntities(b),a.properties},toJSON:function(a){a=a||{},a.renderedEntities=a.renderedEntities||[];var c,d={},e=this;return a&&a.actionName&&(c=this.getActionByName(a.actionName)),a.renderedEntities.push(this.url()),c?b.each(c.fields,function(b){a.actionName=b.action,d[b.name]=y.serializeData(e.get(b.name),a)}):b.each(this.attributes,function(b,c){d[c]=y.serializeData(b,a)}),d},entities:function(a){var c=b.map(this._entities,function(a){return a.entity});return a&&(c=b.filter(c,function(b){return b.match(a)})),c},isNew:function(){return!this.url()},update:function(a,b){return y.isLoaded(a)&&(this.set(this.parse(a,b),b),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Model.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addModelToStore(b.store,this)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}}),Collection:c.Collection.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,parse:function(a,c){c=c||{},this._data=a,this._meta=a.properties||{},this.isLoaded=y.isLoaded(a);var d=c.preParsedModels||b.map(a.entities,function(a){return y.parse(a,c)});return d},meta:function(a){return this._meta[a]},toJSON:function(a){return a=a||{},a.renderedEntities=a.renderedEntities||[],a.renderedEntities.push(this.url()),this.map(function(b){var c=b.toJSON(a);return a.actionName&&(c.id=b.id),c})},save:function(a,c){return c=b.extend({validate:!0},c),this._validate&&this._validate(a,c),void 0===c.parse&&(c.parse=!0),this.sync("create",this,c)},update:function(a,b){return y.isLoaded(a)&&(this.add(this.parse(a,b)),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Collection.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addCollectionToStore(b.store,this,b.representationToStore)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}})}),y.prototype={init:function(a,b){b=b||{},this.apiRoot=a,this.options=b,this.isAbsoluteRegExp=new RegExp("^(?:[a-z]+:)?//","i"),this.alternateRoots=q(b.alternateRoots)},entityPathToUrl:function(a){return this.isAbsoluteRegExp.test(a)?a:this.getRootForPath(a)+"/"+a},getRootForPath:function(a){var b=a.split(/[\?#]/)[0],c=b.split("/")[0];return this.alternateRoots[b]?this.alternateRoots[b]:this.alternateRoots[c]?this.alternateRoots[c]:this.apiRoot},resolve:function(c,d){d=a.extend({},this.options,d),d.store=this.store;var e=this,f=[];return f="string"==typeof c?this.entityPathToUrl(c):b.map(c,function(a){return e.entityPathToUrl(a)}),y.resolve(f,d)}};var A=c.Siren.Action=function(a,c){var d;b.extend(this,{"class":[],method:"GET",type:"application/x-www-form-urlencoded"},a),b.indexOf(this["class"],"batch")>-1&&b.isEmpty(this.fields)&&(d=c.first(),d&&(this.fields=d.getActionByName(this.name).fields)),this.parent=c};A.prototype={hasClass:function(a){return b.indexOf(this["class"],a)>-1},match:function(a){var b=!0;return a?(a["class"]&&(b=this.hasClass(a["class"])),a.name&&(b=this.name==a.name),b):b},getFieldByName:function(a){return b.find(this.fields,function(b){return b.name==a})},getSecureKeys:function(){var a=this.secureKeys;return a?a:(this.secureKeys=new c.Model,this.secureKeys)},getSecureKey:function(a){var b=this.secureKeys;return b?b.get(a):void 0},setSecureKey:function(a,b){return this.getSecureKeys().set(a,b)},clearSecureKeys:function(){return this.getSecureKeys().clear()},clearSecureKey:function(a){return this.getSecureKeys().unset(a)},execute:function(a){a=a||{};var d,e,f=a.attributes,g=this.name,h=this.parent,i=h&&h.siren&&h.siren.store,j={url:this.href,actionName:g,success:function(a,b,d){h.trigger("sync:"+g,a,b,d),c.Siren.parse(b,{store:i,silent:d.silent})},error:function(a,b,c){h.trigger("error:"+g,a,b,c)}};return delete a.attributes,h?(this.method&&(j.type=this.method),this.type&&(j.contentType=this.type),"PATCH"==j.type&&(a.patch=!0),h instanceof c.Model?(d=h.clone(),d._data=h._data,d._actions=h._actions,d.on("request",function(a,b,c){h.trigger("request",a,b,c),h.trigger("request:"+g,a,b,c)})):(d=h,h.on("request",function(a,b,c){h.trigger("request:"+g,a,b,c)})),a=b.extend(j,h.siren.ajaxOptions||{},a),f=b.extend(h.toJSON({actionName:this.name}),f),e=d.save(f,a),h.validationError=d.validationError,e):void 0}};var B=c.Siren.Store=function(){this.data={},this.requests={}};return B.prototype={addModel:function(a){return this.data[a.url()]=a,this},addCollection:function(a,b){return this.data[a.link(b||"self")]=a,this},get:function(a){return this.data["object"==typeof a?e(a):a]},getCurrentCollection:function(a){return y.isLoaded(a)?this.data[d(a,"current")]:this.data[e(a)]},filter:function(a){var c=new RegExp(a);return b.filter(this.data,function(a,b){return c.test(b)})},exists:function(a){return!!this.get(c.Siren.isHydratedObject(a)?a.url():a)},addRequest:function(a,b){var c=this;return b.done(function(){c.requests[a]=null}),this.requests[a]=b,this},getRequest:function(a){return this.requests[a]}},c.Siren.FormView=c.View.extend({tagName:"form",_events:{submit:"handleFormSubmit"},handleFormSubmit:function(a){a.preventDefault();var d=this,e={};b.each(this.fieldAttributes,function(a,b){var f=a.model;f&&(f instanceof c.Model?e[b]=f.get(b):a.isSecure?(e[b]=f.action.getSecureKey(b),f.action.clearSecurekeys()):"function"==typeof f&&(e[b]=f.call(d)))}),this.model.getActionByName(this.action.name).execute({attributes:e})},template:function(a){var c='<% _.each(data.fieldAttributes, function (field, fieldName) { %>
<% if (field.label) { %><% } %> <% if ((field.type == "radio" || field.type == "checkbox") && _.isArray(field.value)) { %> <% _.each(field.options, function (checked, val) { %> /><% }); %> <% } else if ((field.type == "radio" || field.type == "checkbox") && _.isObject(field.value)) { %> <% _.each(field.options, function (option, name) { %> /><% }); %> <% } else { %> id="<%= field.id %>" <% } if (field.value) { %> value="<%= field.value %>" <% } %> <%= field.checked %> <%= field.required %> /> <% } %>
<% }); %> ';return b.template(c,a,{variable:"data"})},parseAttributes:function(a,b){return b=b||{},{id:b.id||a.name+"-form",enctype:b.enctype||a.type,method:b.method||a.method,action:b.action||a.href,title:b.title||a.title,novalidate:!b.validation}},parseFieldAttributes:function(a,c){c=c||{};var d={},e=a.fields;return b.each(e,function(e){var f,g,h;if("entity"==e.type?console.log("@todo - how to handle sub-entity views?"):"entity"!=e.type&&(f=e.name,h=a.parent.get(f),g=b.extend({value:h,type:"text"},e,c[f]),"checkbox"==g.type?b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)?(g.options=[],b.each(g.value,function(a,c){g.options.push({value:a,label:c,checked:b.indexOf(h,a)>-1?"checked":""})})):g.value?g.checked="checked":g.checked="":"radio"==g.type&&(b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)&&(g.options=[],b.each(g.value,function(a,b){g.options.push({value:b,label:a,checked:h==b?"checked":""})}))),g.required=g.required?"required":""),g){var i=f.split("."),j=d,k=i.length;b.each(i,function(a,b){j[a]||(b==k-1?j[a]=g:j[a]={}),j=j[a]})}}),d},setFieldAttributes:function(c){var d={};return b.each(this.fieldAttributes,function(b,e){d[e]=a.extend(b,c[e])}),this.fieldAttributes=d,this},getFieldAttributes:function(){return this.fieldAttributes},render:function(){var a={fieldAttributes:this.fieldAttributes};return this.templateHelpers&&b.extend(a,this.templateHelpers),this.$el.html(this.template(a)),this},setAction:function(a){if(!(a.parent instanceof c.Siren.Model))throw'Action object either missing required "parent" or "parent" is not a Backbone.Siren Model';return this.action=a,this.model=a.parent,this},initializeForm:function(a){var b=a.action;if(!b)throw'Missing required property: "action"';this.setAction(b),this.cid?this.$el.attr(this.parseAttributes(b,a.attributes)):a.attributes=this.parseAttributes(a.action,a.attributes),this.fieldAttributes=this.parseFieldAttributes(b,a.fieldAttributes)},initialize:function(){this.render()},constructor:function(a){a=a||{},a.action&&this.initializeForm(a),this.events=b.extend(this._events,this.events),c.View.call(this,a)}}),c}); \ No newline at end of file diff --git a/dist/iife/backbone.siren.js b/dist/iife/backbone.siren.js index efecf4b..b2d30d0 100644 --- a/dist/iife/backbone.siren.js +++ b/dist/iife/backbone.siren.js @@ -1,5 +1,5 @@ /* -* Backbone.Siren v0.4.1 +* Backbone.Siren v0.4.2 * * Copyright (c) 2016 Kiva Microfunds * Licensed under the MIT license. @@ -1232,8 +1232,8 @@ , getRootForPath: function (path) { // remove parameters an anchor tags from path var strippedPath = path.split(/[\?#]/)[0]; - // grab the parent path (0 is "", 1 is parent) - var strippedPathParent = '/' + strippedPath.split('/')[1]; + // grab the parent path + var strippedPathParent = strippedPath.split('/')[0]; return this.alternateRoots[strippedPath] ? this.alternateRoots[strippedPath] : this.alternateRoots[strippedPathParent] ? this.alternateRoots[strippedPathParent] : this.apiRoot; } diff --git a/dist/iife/backbone.siren.min.js b/dist/iife/backbone.siren.min.js index 61d58a4..71ddf6b 100644 --- a/dist/iife/backbone.siren.min.js +++ b/dist/iife/backbone.siren.min.js @@ -1,8 +1,8 @@ /* -* Backbone.Siren v0.4.1 +* Backbone.Siren v0.4.2 * * Copyright (c) 2016 Kiva Microfunds * Licensed under the MIT license. * https://github.com/kiva/backbone.siren/blob/master/license.txt */ -!function(a,b,c){"use strict";function d(a,c){var d,e;return d=b.filter(a.links,function(a){return!(!a.rel||!b.filter(a.rel,function(a){return a==c}).length)})[0],d&&(e=d.href),e}function e(a){var b;return b=a.href?a.href:a.links?d(a,"self"):""}function f(a){var c;return b.find(a.rel,function(a){return c=/name:(.*)/.exec(a)}),b.last(c)}function g(a){return a.name||f(a)}function h(a,c){return b.indexOf(a["class"],c)>-1}function i(a){return b.indexOf(this.classes(),a)>-1}function j(){return this._data["class"]||[]}function k(){return this._data.title}function l(){return this._data.rel||[]}function m(a){return b.indexOf(this.rel(),a)>-1}function n(a){return"self"==a?e(this._data):d(this._data,a)}function o(){return this._data.links||[]}function p(){return this.link("self")}function q(a){var c={};return b.each(a,function(a,d){b.each(a,function(a){c[a]=d})}),c}function r(){return this._actions||[]}function s(a){return b.find(this._actions,function(b){return b.name==a})}function t(a){var b=!0;return a["class"]&&(b=this.hasClass(a["class"])),a.rel&&(b=this.hasRel(a.rel)),b}function u(a){var c=b.find(this._data.links,function(c){return b.indexOf(c.rel,a)>-1});if(c)return y.resolveOne(c.href)}function v(c){c=a.extend(this.siren.ajaxOptions||{},c);var d=new a.Deferred;if(this.once("sync",function(a){d.resolve(a)}),c.forceFetch||!this.isLoaded)this.fetch(c);else if(b.isEmpty(this._data)){if(c.url){var e=this,f=y.parseChain(c.url),g=f.pop();delete c.url,g&&b.isEmpty(f)?this.resolve(b.extend(b.clone(c),{url:g,forceFetch:!0})).done(function(a){d.resolve(a)}):g&&y.resolveOne(y.stringifyChain(f),c).done(function(a){e.resolve(b.extend(b.clone(c),{url:a.get(g).url(),forceFetch:!0})).done(function(a){d.resolve(a)})})}}else d.resolve(this);return d.promise()}function w(c,d){d=d||{};var e,f,g;if(d.deferred||(d.deferred=new a.Deferred),!b.isArray(c)||b.isEmpty(c))return d.deferred.resolve(this);if(e=c.shift(),f=y.isCollection(this)?this.at(e):this.get(e),!f)throw new ReferenceError('The entity you are looking for, "'+e+'" is not a sub-entity at '+this.url()+".");return g=y.stringifyChain(c),g=g?f.url()+"#"+g:f.url(),y.resolveOne(g,d)}function x(){var a=this,c=[];if(this._data)return b.each(this._data.actions,function(b){var d=new y.Action(b,a);c.push(d)}),a._actions=c,c}var y,z=function(){y.settings.showWarnings&&console&&console.warn.apply(console,arguments)};y=c.Siren=function(a,b){this.store=new c.Siren.Store,this.init(a,b)},b.extend(y,{settings:{showWarnings:!0},warn:z,isHydratedObject:function(a){return!(!a||!a.cid&&!a.models||!a._data)},isLoaded:function(a){return!(!a.links||a.href)},isCollection:function(a){return a instanceof c.Siren.Collection},isRawCollection:function(a){return h(a,"collection")},isRawError:function(a){return h(a,"error")},isRawSiren:function(a){return!!e(a)},addModelToStore:function(a,b){a.addModel(b)},addCollectionToStore:function(a,b,c){var d;return c?void a.addCollection(b,c):(d=b.link("current"),d&&a.addCollection(b,"current"),void a.addCollection(b,"self"))},serializeData:function(a,c){return c=c||{},y.isHydratedObject(a)?b.indexOf(c.renderedEntities,a.url())<0?a.toJSON(c):void 0:a},parseModel:function(a,b){b=b||{};var d,e=b.store;return e&&(d=e.get(a)),d?d.update(a,b):d=new c.Siren.Model(a,b),d},parseCollection:function(a,b){b=b||{};var e,f,g,h,i=b.store;return i?(e=i.get(a),e?e.update(a,b):(b.representationToStore="self",e=new c.Siren.Collection(a,b)),h=d(a,"current"),h&&(f=i.get(h),f?f.update(a,b):(b.representationToStore="current",f=new c.Siren.Collection(a,b))),g=f||e):g=new c.Siren.Collection(a,b),g},parse:function(a,b){return b=b||{},y.isRawCollection(a)?this.parseCollection(a,b):y.isRawError(a)?new c.Siren.Model(a,b):y.isRawSiren?this.parseModel(a,b):void 0},ajax:function(a,d){return d=b.extend({url:a,dataType:"json"},d),c.ajax(d)},parseChain:function(a){return"string"!=typeof a&&new TypeError("Must be a string"),a.replace(/^#|#$/,"").split("#")},stringifyChain:function(a){return b.isArray(a)||new TypeError("Must be an array"),a.join("#")},resolve:function(a,c){return b.isArray(a)?y.resolveMany(a,c):y.resolveOne(a,c)},resolveMany:function(c,d){d=d||{};var e=this,f=b.map(c,function(a){return e.resolveOne(a,b.clone(d))});return a.when.apply(a,f)},resolveOne:function(c,d){d=d||{};var e,f,g,h,i,j=y.parseChain(c),k=j.shift(),l=d.deferred;return d.store&&(e=d.store),e&&(h=e.getRequest(k),h&&(f=h.state())),b.isEmpty(j)&&("resolved"==f&&!d.forceFetch||"pending"==f)?l?h.done(function(a){l.resolve(a)}):h:(l||(l=new a.Deferred),"pending"==f?h.done(function(a){d.deferred=l,a.resolveNextInChain(j,d)}):(e&&(i=e.get(k)),i&&i.isLoaded&&!d.forceFetch?(d.deferred=l,i.resolveNextInChain(j,d)):(g=new a.Deferred,e&&e.addRequest(d.data?k+"?"+a.param(d.data):k,g.promise()),y.ajax(k,d).done(function(a){var b=y.parse(a,d);g.resolve(b),d.deferred=l,b.resolveNextInChain(j,d)}).fail(function(a){var b,c;try{b=JSON.parse(a.responseText)}catch(e){b={}}c=y.parse(b,d),g.reject(c,a),l.reject(c,a)}))),l.promise())},Model:c.Model.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,resolveEntities:function(c){var d=this,e=[];return b.each(this._data.entities,function(a){e.push(d.resolveEntity(a,c))}),a.when(e).done(function(){d.trigger("resolve",d)})},resolveEntity:function(b,c){c=c||{};var d,f,h=this,i=new a.Deferred;return b.href&&"linked"==c.autoFetch||"all"==c.autoFetch?y.resolveOne(e(b),c).done(function(a){i.resolve(h.setEntity(a,b.rel,g(b)))}):(d=y.parse(b,c),f=i.resolve(this.setEntity(d,b.rel,g(b)))),f},setEntity:function(a,b,c){var d={rel:b,entity:a};return c&&(this.set(c,a),d.name=c),this._entities.push(d),a},parse:function(a,b){return this._data=a,this._entities=[],this.isLoaded=y.isLoaded(a),this.resolveEntities(b),a.properties},toJSON:function(a){a=a||{},a.renderedEntities=a.renderedEntities||[];var c,d={},e=this;return a&&a.actionName&&(c=this.getActionByName(a.actionName)),a.renderedEntities.push(this.url()),c?b.each(c.fields,function(b){a.actionName=b.action,d[b.name]=y.serializeData(e.get(b.name),a)}):b.each(this.attributes,function(b,c){d[c]=y.serializeData(b,a)}),d},entities:function(a){var c=b.map(this._entities,function(a){return a.entity});return a&&(c=b.filter(c,function(b){return b.match(a)})),c},isNew:function(){return!this.url()},update:function(a,b){return y.isLoaded(a)&&(this.set(this.parse(a,b),b),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Model.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addModelToStore(b.store,this)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}}),Collection:c.Collection.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,parse:function(a,c){c=c||{},this._data=a,this._meta=a.properties||{},this.isLoaded=y.isLoaded(a);var d=c.preParsedModels||b.map(a.entities,function(a){return y.parse(a,c)});return d},meta:function(a){return this._meta[a]},toJSON:function(a){return a=a||{},a.renderedEntities=a.renderedEntities||[],a.renderedEntities.push(this.url()),this.map(function(b){var c=b.toJSON(a);return a.actionName&&(c.id=b.id),c})},save:function(a,c){return c=b.extend({validate:!0},c),this._validate&&this._validate(a,c),void 0===c.parse&&(c.parse=!0),this.sync("create",this,c)},update:function(a,b){return y.isLoaded(a)&&(this.add(this.parse(a,b)),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Collection.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addCollectionToStore(b.store,this,b.representationToStore)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}})}),y.prototype={init:function(a,b){b=b||{},this.apiRoot=a,this.options=b,this.isAbsoluteRegExp=new RegExp("^(?:[a-z]+:)?//","i"),this.alternateRoots=q(b.alternateRoots)},entityPathToUrl:function(a){return this.isAbsoluteRegExp.test(a)?a:this.getRootForPath(a)+"/"+a},getRootForPath:function(a){var b=a.split(/[\?#]/)[0],c="/"+b.split("/")[1];return this.alternateRoots[b]?this.alternateRoots[b]:this.alternateRoots[c]?this.alternateRoots[c]:this.apiRoot},resolve:function(c,d){d=a.extend({},this.options,d),d.store=this.store;var e=this,f=[];return f="string"==typeof c?this.entityPathToUrl(c):b.map(c,function(a){return e.entityPathToUrl(a)}),y.resolve(f,d)}};var A=c.Siren.Action=function(a,c){var d;b.extend(this,{"class":[],method:"GET",type:"application/x-www-form-urlencoded"},a),b.indexOf(this["class"],"batch")>-1&&b.isEmpty(this.fields)&&(d=c.first(),d&&(this.fields=d.getActionByName(this.name).fields)),this.parent=c};A.prototype={hasClass:function(a){return b.indexOf(this["class"],a)>-1},match:function(a){var b=!0;return a?(a["class"]&&(b=this.hasClass(a["class"])),a.name&&(b=this.name==a.name),b):b},getFieldByName:function(a){return b.find(this.fields,function(b){return b.name==a})},getSecureKeys:function(){var a=this.secureKeys;return a?a:(this.secureKeys=new c.Model,this.secureKeys)},getSecureKey:function(a){var b=this.secureKeys;return b?b.get(a):void 0},setSecureKey:function(a,b){return this.getSecureKeys().set(a,b)},clearSecureKeys:function(){return this.getSecureKeys().clear()},clearSecureKey:function(a){return this.getSecureKeys().unset(a)},execute:function(a){a=a||{};var d,e,f=a.attributes,g=this.name,h=this.parent,i=h&&h.siren&&h.siren.store,j={url:this.href,actionName:g,success:function(a,b,d){h.trigger("sync:"+g,a,b,d),c.Siren.parse(b,{store:i,silent:d.silent})},error:function(a,b,c){h.trigger("error:"+g,a,b,c)}};return delete a.attributes,h?(this.method&&(j.type=this.method),this.type&&(j.contentType=this.type),"PATCH"==j.type&&(a.patch=!0),h instanceof c.Model?(d=h.clone(),d._data=h._data,d._actions=h._actions,d.on("request",function(a,b,c){h.trigger("request",a,b,c),h.trigger("request:"+g,a,b,c)})):(d=h,h.on("request",function(a,b,c){h.trigger("request:"+g,a,b,c)})),a=b.extend(j,h.siren.ajaxOptions||{},a),f=b.extend(h.toJSON({actionName:this.name}),f),e=d.save(f,a),h.validationError=d.validationError,e):void 0}};var B=c.Siren.Store=function(){this.data={},this.requests={}};B.prototype={addModel:function(a){return this.data[a.url()]=a,this},addCollection:function(a,b){return this.data[a.link(b||"self")]=a,this},get:function(a){return this.data["object"==typeof a?e(a):a]},getCurrentCollection:function(a){return y.isLoaded(a)?this.data[d(a,"current")]:this.data[e(a)]},filter:function(a){var c=new RegExp(a);return b.filter(this.data,function(a,b){return c.test(b)})},exists:function(a){return!!this.get(c.Siren.isHydratedObject(a)?a.url():a)},addRequest:function(a,b){var c=this;return b.done(function(){c.requests[a]=null}),this.requests[a]=b,this},getRequest:function(a){return this.requests[a]}},c.Siren.FormView=c.View.extend({tagName:"form",_events:{submit:"handleFormSubmit"},handleFormSubmit:function(a){a.preventDefault();var d=this,e={};b.each(this.fieldAttributes,function(a,b){var f=a.model;f&&(f instanceof c.Model?e[b]=f.get(b):a.isSecure?(e[b]=f.action.getSecureKey(b),f.action.clearSecurekeys()):"function"==typeof f&&(e[b]=f.call(d)))}),this.model.getActionByName(this.action.name).execute({attributes:e})},template:function(a){var c='<% _.each(data.fieldAttributes, function (field, fieldName) { %>
<% if (field.label) { %><% } %> <% if ((field.type == "radio" || field.type == "checkbox") && _.isArray(field.value)) { %> <% _.each(field.options, function (checked, val) { %> /><% }); %> <% } else if ((field.type == "radio" || field.type == "checkbox") && _.isObject(field.value)) { %> <% _.each(field.options, function (option, name) { %> /><% }); %> <% } else { %> id="<%= field.id %>" <% } if (field.value) { %> value="<%= field.value %>" <% } %> <%= field.checked %> <%= field.required %> /> <% } %>
<% }); %> ';return b.template(c,a,{variable:"data"})},parseAttributes:function(a,b){return b=b||{},{id:b.id||a.name+"-form",enctype:b.enctype||a.type,method:b.method||a.method,action:b.action||a.href,title:b.title||a.title,novalidate:!b.validation}},parseFieldAttributes:function(a,c){c=c||{};var d={},e=a.fields;return b.each(e,function(e){var f,g,h;if("entity"==e.type?console.log("@todo - how to handle sub-entity views?"):"entity"!=e.type&&(f=e.name,h=a.parent.get(f),g=b.extend({value:h,type:"text"},e,c[f]),"checkbox"==g.type?b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)?(g.options=[],b.each(g.value,function(a,c){g.options.push({value:a,label:c,checked:b.indexOf(h,a)>-1?"checked":""})})):g.value?g.checked="checked":g.checked="":"radio"==g.type&&(b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)&&(g.options=[],b.each(g.value,function(a,b){g.options.push({value:b,label:a,checked:h==b?"checked":""})}))),g.required=g.required?"required":""),g){var i=f.split("."),j=d,k=i.length;b.each(i,function(a,b){j[a]||(b==k-1?j[a]=g:j[a]={}),j=j[a]})}}),d},setFieldAttributes:function(c){var d={};return b.each(this.fieldAttributes,function(b,e){d[e]=a.extend(b,c[e])}),this.fieldAttributes=d,this},getFieldAttributes:function(){return this.fieldAttributes},render:function(){var a={fieldAttributes:this.fieldAttributes};return this.templateHelpers&&b.extend(a,this.templateHelpers),this.$el.html(this.template(a)),this},setAction:function(a){if(!(a.parent instanceof c.Siren.Model))throw'Action object either missing required "parent" or "parent" is not a Backbone.Siren Model';return this.action=a,this.model=a.parent,this},initializeForm:function(a){var b=a.action;if(!b)throw'Missing required property: "action"';this.setAction(b),this.cid?this.$el.attr(this.parseAttributes(b,a.attributes)):a.attributes=this.parseAttributes(a.action,a.attributes),this.fieldAttributes=this.parseFieldAttributes(b,a.fieldAttributes)},initialize:function(){this.render()},constructor:function(a){a=a||{},a.action&&this.initializeForm(a),this.events=b.extend(this._events,this.events),c.View.call(this,a)}})}(jQuery,_,Backbone); \ No newline at end of file +!function(a,b,c){"use strict";function d(a,c){var d,e;return d=b.filter(a.links,function(a){return!(!a.rel||!b.filter(a.rel,function(a){return a==c}).length)})[0],d&&(e=d.href),e}function e(a){var b;return b=a.href?a.href:a.links?d(a,"self"):""}function f(a){var c;return b.find(a.rel,function(a){return c=/name:(.*)/.exec(a)}),b.last(c)}function g(a){return a.name||f(a)}function h(a,c){return b.indexOf(a["class"],c)>-1}function i(a){return b.indexOf(this.classes(),a)>-1}function j(){return this._data["class"]||[]}function k(){return this._data.title}function l(){return this._data.rel||[]}function m(a){return b.indexOf(this.rel(),a)>-1}function n(a){return"self"==a?e(this._data):d(this._data,a)}function o(){return this._data.links||[]}function p(){return this.link("self")}function q(a){var c={};return b.each(a,function(a,d){b.each(a,function(a){c[a]=d})}),c}function r(){return this._actions||[]}function s(a){return b.find(this._actions,function(b){return b.name==a})}function t(a){var b=!0;return a["class"]&&(b=this.hasClass(a["class"])),a.rel&&(b=this.hasRel(a.rel)),b}function u(a){var c=b.find(this._data.links,function(c){return b.indexOf(c.rel,a)>-1});if(c)return y.resolveOne(c.href)}function v(c){c=a.extend(this.siren.ajaxOptions||{},c);var d=new a.Deferred;if(this.once("sync",function(a){d.resolve(a)}),c.forceFetch||!this.isLoaded)this.fetch(c);else if(b.isEmpty(this._data)){if(c.url){var e=this,f=y.parseChain(c.url),g=f.pop();delete c.url,g&&b.isEmpty(f)?this.resolve(b.extend(b.clone(c),{url:g,forceFetch:!0})).done(function(a){d.resolve(a)}):g&&y.resolveOne(y.stringifyChain(f),c).done(function(a){e.resolve(b.extend(b.clone(c),{url:a.get(g).url(),forceFetch:!0})).done(function(a){d.resolve(a)})})}}else d.resolve(this);return d.promise()}function w(c,d){d=d||{};var e,f,g;if(d.deferred||(d.deferred=new a.Deferred),!b.isArray(c)||b.isEmpty(c))return d.deferred.resolve(this);if(e=c.shift(),f=y.isCollection(this)?this.at(e):this.get(e),!f)throw new ReferenceError('The entity you are looking for, "'+e+'" is not a sub-entity at '+this.url()+".");return g=y.stringifyChain(c),g=g?f.url()+"#"+g:f.url(),y.resolveOne(g,d)}function x(){var a=this,c=[];if(this._data)return b.each(this._data.actions,function(b){var d=new y.Action(b,a);c.push(d)}),a._actions=c,c}var y,z=function(){y.settings.showWarnings&&console&&console.warn.apply(console,arguments)};y=c.Siren=function(a,b){this.store=new c.Siren.Store,this.init(a,b)},b.extend(y,{settings:{showWarnings:!0},warn:z,isHydratedObject:function(a){return!(!a||!a.cid&&!a.models||!a._data)},isLoaded:function(a){return!(!a.links||a.href)},isCollection:function(a){return a instanceof c.Siren.Collection},isRawCollection:function(a){return h(a,"collection")},isRawError:function(a){return h(a,"error")},isRawSiren:function(a){return!!e(a)},addModelToStore:function(a,b){a.addModel(b)},addCollectionToStore:function(a,b,c){var d;return c?void a.addCollection(b,c):(d=b.link("current"),d&&a.addCollection(b,"current"),void a.addCollection(b,"self"))},serializeData:function(a,c){return c=c||{},y.isHydratedObject(a)?b.indexOf(c.renderedEntities,a.url())<0?a.toJSON(c):void 0:a},parseModel:function(a,b){b=b||{};var d,e=b.store;return e&&(d=e.get(a)),d?d.update(a,b):d=new c.Siren.Model(a,b),d},parseCollection:function(a,b){b=b||{};var e,f,g,h,i=b.store;return i?(e=i.get(a),e?e.update(a,b):(b.representationToStore="self",e=new c.Siren.Collection(a,b)),h=d(a,"current"),h&&(f=i.get(h),f?f.update(a,b):(b.representationToStore="current",f=new c.Siren.Collection(a,b))),g=f||e):g=new c.Siren.Collection(a,b),g},parse:function(a,b){return b=b||{},y.isRawCollection(a)?this.parseCollection(a,b):y.isRawError(a)?new c.Siren.Model(a,b):y.isRawSiren?this.parseModel(a,b):void 0},ajax:function(a,d){return d=b.extend({url:a,dataType:"json"},d),c.ajax(d)},parseChain:function(a){return"string"!=typeof a&&new TypeError("Must be a string"),a.replace(/^#|#$/,"").split("#")},stringifyChain:function(a){return b.isArray(a)||new TypeError("Must be an array"),a.join("#")},resolve:function(a,c){return b.isArray(a)?y.resolveMany(a,c):y.resolveOne(a,c)},resolveMany:function(c,d){d=d||{};var e=this,f=b.map(c,function(a){return e.resolveOne(a,b.clone(d))});return a.when.apply(a,f)},resolveOne:function(c,d){d=d||{};var e,f,g,h,i,j=y.parseChain(c),k=j.shift(),l=d.deferred;return d.store&&(e=d.store),e&&(h=e.getRequest(k),h&&(f=h.state())),b.isEmpty(j)&&("resolved"==f&&!d.forceFetch||"pending"==f)?l?h.done(function(a){l.resolve(a)}):h:(l||(l=new a.Deferred),"pending"==f?h.done(function(a){d.deferred=l,a.resolveNextInChain(j,d)}):(e&&(i=e.get(k)),i&&i.isLoaded&&!d.forceFetch?(d.deferred=l,i.resolveNextInChain(j,d)):(g=new a.Deferred,e&&e.addRequest(d.data?k+"?"+a.param(d.data):k,g.promise()),y.ajax(k,d).done(function(a){var b=y.parse(a,d);g.resolve(b),d.deferred=l,b.resolveNextInChain(j,d)}).fail(function(a){var b,c;try{b=JSON.parse(a.responseText)}catch(e){b={}}c=y.parse(b,d),g.reject(c,a),l.reject(c,a)}))),l.promise())},Model:c.Model.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,resolveEntities:function(c){var d=this,e=[];return b.each(this._data.entities,function(a){e.push(d.resolveEntity(a,c))}),a.when(e).done(function(){d.trigger("resolve",d)})},resolveEntity:function(b,c){c=c||{};var d,f,h=this,i=new a.Deferred;return b.href&&"linked"==c.autoFetch||"all"==c.autoFetch?y.resolveOne(e(b),c).done(function(a){i.resolve(h.setEntity(a,b.rel,g(b)))}):(d=y.parse(b,c),f=i.resolve(this.setEntity(d,b.rel,g(b)))),f},setEntity:function(a,b,c){var d={rel:b,entity:a};return c&&(this.set(c,a),d.name=c),this._entities.push(d),a},parse:function(a,b){return this._data=a,this._entities=[],this.isLoaded=y.isLoaded(a),this.resolveEntities(b),a.properties},toJSON:function(a){a=a||{},a.renderedEntities=a.renderedEntities||[];var c,d={},e=this;return a&&a.actionName&&(c=this.getActionByName(a.actionName)),a.renderedEntities.push(this.url()),c?b.each(c.fields,function(b){a.actionName=b.action,d[b.name]=y.serializeData(e.get(b.name),a)}):b.each(this.attributes,function(b,c){d[c]=y.serializeData(b,a)}),d},entities:function(a){var c=b.map(this._entities,function(a){return a.entity});return a&&(c=b.filter(c,function(b){return b.match(a)})),c},isNew:function(){return!this.url()},update:function(a,b){return y.isLoaded(a)&&(this.set(this.parse(a,b),b),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Model.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addModelToStore(b.store,this)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}}),Collection:c.Collection.extend({url:p,classes:j,rel:l,actions:r,link:n,links:o,title:k,hasClass:i,hasRel:m,getActionByName:s,parseActions:x,match:t,request:u,resolve:v,resolveNextInChain:w,parse:function(a,c){c=c||{},this._data=a,this._meta=a.properties||{},this.isLoaded=y.isLoaded(a);var d=c.preParsedModels||b.map(a.entities,function(a){return y.parse(a,c)});return d},meta:function(a){return this._meta[a]},toJSON:function(a){return a=a||{},a.renderedEntities=a.renderedEntities||[],a.renderedEntities.push(this.url()),this.map(function(b){var c=b.toJSON(a);return a.actionName&&(c.id=b.id),c})},save:function(a,c){return c=b.extend({validate:!0},c),this._validate&&this._validate(a,c),void 0===c.parse&&(c.parse=!0),this.sync("create",this,c)},update:function(a,b){return y.isLoaded(a)&&(this.add(this.parse(a,b)),this.parseActions()),this},constructor:function(a,b){b=b||{},b.parse=!0,c.Collection.call(this,a,b),this.siren={},b.store&&(this.siren.store=b.store,y.addCollectionToStore(b.store,this,b.representationToStore)),b.ajaxOptions&&(this.siren.ajaxOptions=b.ajaxOptions),this.parseActions()}})}),y.prototype={init:function(a,b){b=b||{},this.apiRoot=a,this.options=b,this.isAbsoluteRegExp=new RegExp("^(?:[a-z]+:)?//","i"),this.alternateRoots=q(b.alternateRoots)},entityPathToUrl:function(a){return this.isAbsoluteRegExp.test(a)?a:this.getRootForPath(a)+"/"+a},getRootForPath:function(a){var b=a.split(/[\?#]/)[0],c=b.split("/")[0];return this.alternateRoots[b]?this.alternateRoots[b]:this.alternateRoots[c]?this.alternateRoots[c]:this.apiRoot},resolve:function(c,d){d=a.extend({},this.options,d),d.store=this.store;var e=this,f=[];return f="string"==typeof c?this.entityPathToUrl(c):b.map(c,function(a){return e.entityPathToUrl(a)}),y.resolve(f,d)}};var A=c.Siren.Action=function(a,c){var d;b.extend(this,{"class":[],method:"GET",type:"application/x-www-form-urlencoded"},a),b.indexOf(this["class"],"batch")>-1&&b.isEmpty(this.fields)&&(d=c.first(),d&&(this.fields=d.getActionByName(this.name).fields)),this.parent=c};A.prototype={hasClass:function(a){return b.indexOf(this["class"],a)>-1},match:function(a){var b=!0;return a?(a["class"]&&(b=this.hasClass(a["class"])),a.name&&(b=this.name==a.name),b):b},getFieldByName:function(a){return b.find(this.fields,function(b){return b.name==a})},getSecureKeys:function(){var a=this.secureKeys;return a?a:(this.secureKeys=new c.Model,this.secureKeys)},getSecureKey:function(a){var b=this.secureKeys;return b?b.get(a):void 0},setSecureKey:function(a,b){return this.getSecureKeys().set(a,b)},clearSecureKeys:function(){return this.getSecureKeys().clear()},clearSecureKey:function(a){return this.getSecureKeys().unset(a)},execute:function(a){a=a||{};var d,e,f=a.attributes,g=this.name,h=this.parent,i=h&&h.siren&&h.siren.store,j={url:this.href,actionName:g,success:function(a,b,d){h.trigger("sync:"+g,a,b,d),c.Siren.parse(b,{store:i,silent:d.silent})},error:function(a,b,c){h.trigger("error:"+g,a,b,c)}};return delete a.attributes,h?(this.method&&(j.type=this.method),this.type&&(j.contentType=this.type),"PATCH"==j.type&&(a.patch=!0),h instanceof c.Model?(d=h.clone(),d._data=h._data,d._actions=h._actions,d.on("request",function(a,b,c){h.trigger("request",a,b,c),h.trigger("request:"+g,a,b,c)})):(d=h,h.on("request",function(a,b,c){h.trigger("request:"+g,a,b,c)})),a=b.extend(j,h.siren.ajaxOptions||{},a),f=b.extend(h.toJSON({actionName:this.name}),f),e=d.save(f,a),h.validationError=d.validationError,e):void 0}};var B=c.Siren.Store=function(){this.data={},this.requests={}};B.prototype={addModel:function(a){return this.data[a.url()]=a,this},addCollection:function(a,b){return this.data[a.link(b||"self")]=a,this},get:function(a){return this.data["object"==typeof a?e(a):a]},getCurrentCollection:function(a){return y.isLoaded(a)?this.data[d(a,"current")]:this.data[e(a)]},filter:function(a){var c=new RegExp(a);return b.filter(this.data,function(a,b){return c.test(b)})},exists:function(a){return!!this.get(c.Siren.isHydratedObject(a)?a.url():a)},addRequest:function(a,b){var c=this;return b.done(function(){c.requests[a]=null}),this.requests[a]=b,this},getRequest:function(a){return this.requests[a]}},c.Siren.FormView=c.View.extend({tagName:"form",_events:{submit:"handleFormSubmit"},handleFormSubmit:function(a){a.preventDefault();var d=this,e={};b.each(this.fieldAttributes,function(a,b){var f=a.model;f&&(f instanceof c.Model?e[b]=f.get(b):a.isSecure?(e[b]=f.action.getSecureKey(b),f.action.clearSecurekeys()):"function"==typeof f&&(e[b]=f.call(d)))}),this.model.getActionByName(this.action.name).execute({attributes:e})},template:function(a){var c='<% _.each(data.fieldAttributes, function (field, fieldName) { %>
<% if (field.label) { %><% } %> <% if ((field.type == "radio" || field.type == "checkbox") && _.isArray(field.value)) { %> <% _.each(field.options, function (checked, val) { %> /><% }); %> <% } else if ((field.type == "radio" || field.type == "checkbox") && _.isObject(field.value)) { %> <% _.each(field.options, function (option, name) { %> /><% }); %> <% } else { %> id="<%= field.id %>" <% } if (field.value) { %> value="<%= field.value %>" <% } %> <%= field.checked %> <%= field.required %> /> <% } %>
<% }); %> ';return b.template(c,a,{variable:"data"})},parseAttributes:function(a,b){return b=b||{},{id:b.id||a.name+"-form",enctype:b.enctype||a.type,method:b.method||a.method,action:b.action||a.href,title:b.title||a.title,novalidate:!b.validation}},parseFieldAttributes:function(a,c){c=c||{};var d={},e=a.fields;return b.each(e,function(e){var f,g,h;if("entity"==e.type?console.log("@todo - how to handle sub-entity views?"):"entity"!=e.type&&(f=e.name,h=a.parent.get(f),g=b.extend({value:h,type:"text"},e,c[f]),"checkbox"==g.type?b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)?(g.options=[],b.each(g.value,function(a,c){g.options.push({value:a,label:c,checked:b.indexOf(h,a)>-1?"checked":""})})):g.value?g.checked="checked":g.checked="":"radio"==g.type&&(b.isArray(g.value)?(g.options={},b.each(g.value,function(a){g.options[a]=h==a?"checked":""})):b.isObject(g.value)&&(g.options=[],b.each(g.value,function(a,b){g.options.push({value:b,label:a,checked:h==b?"checked":""})}))),g.required=g.required?"required":""),g){var i=f.split("."),j=d,k=i.length;b.each(i,function(a,b){j[a]||(b==k-1?j[a]=g:j[a]={}),j=j[a]})}}),d},setFieldAttributes:function(c){var d={};return b.each(this.fieldAttributes,function(b,e){d[e]=a.extend(b,c[e])}),this.fieldAttributes=d,this},getFieldAttributes:function(){return this.fieldAttributes},render:function(){var a={fieldAttributes:this.fieldAttributes};return this.templateHelpers&&b.extend(a,this.templateHelpers),this.$el.html(this.template(a)),this},setAction:function(a){if(!(a.parent instanceof c.Siren.Model))throw'Action object either missing required "parent" or "parent" is not a Backbone.Siren Model';return this.action=a,this.model=a.parent,this},initializeForm:function(a){var b=a.action;if(!b)throw'Missing required property: "action"';this.setAction(b),this.cid?this.$el.attr(this.parseAttributes(b,a.attributes)):a.attributes=this.parseAttributes(a.action,a.attributes),this.fieldAttributes=this.parseFieldAttributes(b,a.fieldAttributes)},initialize:function(){this.render()},constructor:function(a){a=a||{},a.action&&this.initializeForm(a),this.events=b.extend(this._events,this.events),c.View.call(this,a)}})}(jQuery,_,Backbone); \ No newline at end of file diff --git a/package.json b/package.json index be65bae..c7863be 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "backbone.siren", - "version": "0.4.1", + "version": "0.4.2", "description": "Converts Siren JSON representations into Backbone Models and Collections", "main": "index.js", "scripts": {