diff --git a/dist/restangular.js b/dist/restangular.js index dd2e369e..bff968f9 100644 --- a/dist/restangular.js +++ b/dist/restangular.js @@ -1,9 +1,19 @@ /** * Restful Resources service for AngularJS apps - * @version v1.5.2 - 2016-02-08 * @link https://github.com/mgonto/restangular + * @version v1.6.0 - 2016-12-25 * @link https://github.com/mgonto/restangular * @author Martin Gontovnikas * @license MIT License, http://www.opensource.org/licenses/MIT - */(function() { + */(function (root, factory) { + // https://github.com/umdjs/umd/blob/master/templates/returnExports.js + if (typeof define === 'function' && define.amd) { + define(['lodash', 'angular'], factory); + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('lodash'), require('angular')); + } else { + // No global export, Restangular will register itself as Angular.js module + factory(root._, root.angular); + } +}(this, function (_, angular) { var restangular = angular.module('restangular', []); @@ -61,6 +71,15 @@ restangular.provider('Restangular', function() { return this; }; + /** + * Always return plain data, no restangularized object + **/ + config.plainByDefault = config.plainByDefault || false; + object.setPlainByDefault = function(value) { + config.plainByDefault = value === true ? true : false; + return this; + }; + config.withHttpValues = function(httpLocalConfig, obj) { return _.defaults(obj, httpLocalConfig, config.defaultHttpFields); }; @@ -188,12 +207,14 @@ restangular.provider('Restangular', function() { oneUrl: 'oneUrl', allUrl: 'allUrl', customPUT: 'customPUT', + customPATCH: 'customPATCH', customPOST: 'customPOST', customDELETE: 'customDELETE', customGET: 'customGET', customGETLIST: 'customGETLIST', customOperation: 'customOperation', doPUT: 'doPUT', + doPATCH: 'doPATCH', doPOST: 'doPOST', doDELETE: 'doDELETE', doGET: 'doGET', @@ -424,6 +445,7 @@ restangular.provider('Restangular', function() { * Add element transformers for certain routes. */ config.transformers = config.transformers || {}; + config.matchTransformers = config.matchTransformers || []; object.addElementTransformer = function(type, secondArg, thirdArg) { var isCollection = null; var transformer = null; @@ -434,17 +456,24 @@ restangular.provider('Restangular', function() { isCollection = secondArg; } - var typeTransformers = config.transformers[type]; - if (!typeTransformers) { - typeTransformers = config.transformers[type] = []; - } - - typeTransformers.push(function(coll, elem) { + var transformerFn = function(coll, elem) { if (_.isNull(isCollection) || (coll === isCollection)) { return transformer(elem); } return elem; - }); + }; + + if (_.isRegExp(type)) { + config.matchTransformers.push({ + regexp: type, + transformer: transformerFn + }); + } else { + if (!config.transformers[type]) { + config.transformers[type] = []; + } + config.transformers[type].push(transformerFn); + } return object; }; @@ -461,8 +490,19 @@ restangular.provider('Restangular', function() { if (!force && !config.transformLocalElements && !elem[config.restangularFields.fromServer]) { return elem; } - var typeTransformers = config.transformers[route]; + var changedElem = elem; + + var matchTransformers = config.matchTransformers; + if (matchTransformers) { + _.each(matchTransformers, function (transformer) { + if (route.match(transformer.regexp)) { + changedElem = transformer.transformer(isCollection, changedElem); + } + }); + } + + var typeTransformers = config.transformers[route]; if (typeTransformers) { _.each(typeTransformers, function(transformer) { changedElem = transformer(isCollection, changedElem); @@ -560,7 +600,7 @@ restangular.provider('Restangular', function() { var url = this.base(current); - if (what) { + if (what || what === 0) { var add = ''; if (!/\/$/.test(url)) { add += '/'; @@ -641,7 +681,7 @@ restangular.provider('Restangular', function() { Path.prototype = new BaseCreator(); Path.prototype.normalizeUrl = function (url){ - var parts = /(http[s]?:\/\/)?(.*)?/.exec(url); + var parts = /((?:http[s]?:)?\/\/)?(.*)?/.exec(url); parts[2] = parts[2].replace(/[\\\/]+/g, '/'); return (typeof parts[1] !== 'undefined')? parts[1] + parts[2] : parts[2]; }; @@ -927,20 +967,16 @@ restangular.provider('Restangular', function() { function addCustomOperation(elem) { elem[config.restangularFields.customOperation] = _.bind(customFunction, elem); - _.each(['put', 'post', 'get', 'delete'], function(oper) { + var requestMethods = { get: customFunction, delete: customFunction }; + _.each(['put', 'patch', 'post'], function(name) { + requestMethods[name] = function(operation, elem, path, params, headers) { + return _.bind(customFunction, this)(operation, path, params, headers, elem); + }; + }); + _.each(requestMethods, function(requestFunc, name) { + var callOperation = name === 'delete' ? 'remove' : name; _.each(['do', 'custom'], function(alias) { - var callOperation = oper === 'delete' ? 'remove' : oper; - var name = alias + oper.toUpperCase(); - var callFunction; - - if (callOperation !== 'put' && callOperation !== 'post') { - callFunction = customFunction; - } else { - callFunction = function(operation, elem, path, params, headers) { - return _.bind(customFunction, this)(operation, path, params, headers, elem); - }; - } - elem[name] = _.bind(callFunction, elem, callOperation); + elem[alias + name.toUpperCase()] = _.bind(requestFunc, elem, callOperation); }); }); elem[config.restangularFields.customGETLIST] = _.bind(fetchFunction, elem); @@ -950,7 +986,7 @@ restangular.provider('Restangular', function() { function copyRestangularizedElement(fromElement, toElement) { var copiedElement = angular.copy(fromElement, toElement); return restangularizeElem(copiedElement[config.restangularFields.parentResource], - copiedElement, copiedElement[config.restangularFields.route], true); + copiedElement, copiedElement[config.restangularFields.route], copiedElement[config.restangularFields.fromServer]); } function restangularizeElem(parent, element, route, fromServer, collection, reqParams) { @@ -1003,10 +1039,12 @@ restangular.provider('Restangular', function() { return config.transformElem(localElem, true, route, service, true); } - function restangularizeCollectionAndElements(parent, element, route) { - var collection = restangularizeCollection(parent, element, route, false); + function restangularizeCollectionAndElements(parent, element, route, fromServer) { + var collection = restangularizeCollection(parent, element, route, fromServer); _.each(collection, function(elem) { - restangularizeElem(parent, elem, route, false); + if (elem) { + restangularizeElem(parent, elem, route, fromServer); + } }); return collection; } @@ -1074,6 +1112,11 @@ restangular.provider('Restangular', function() { if (!_.isArray(data)) { throw new Error('Response for getList SHOULD be an array and not an object or something else'); } + + if (true === config.plainByDefault) { + return resolvePromise(deferred, response, data, filledArray); + } + var processedData = _.map(data, function(elem) { if (!__this[config.restangularFields.restangularCollection]) { return restangularizeElem(__this, elem, what, true, data); @@ -1164,8 +1207,15 @@ restangular.provider('Restangular', function() { var resData = response.data; var fullParams = response.config.params; var elem = parseResponse(resData, operation, route, fetchUrl, response, deferred); - if (elem) { + + // accept 0 as response + if (elem !== null && elem !== undefined && elem !== '') { var data; + + if (true === config.plainByDefault) { + return resolvePromise(deferred, response, elem, filledObject); + } + if (operation === 'post' && !__this[config.restangularFields.restangularCollection]) { data = restangularizeElem( __this[config.restangularFields.parentResource], @@ -1310,6 +1360,8 @@ restangular.provider('Restangular', function() { serv.one = _.bind(one, (parent || service), parent, route); serv.post = _.bind(collection.post, collection); serv.getList = _.bind(collection.getList, collection); + serv.withHttpConfig = _.bind(collection.withHttpConfig, collection); + serv.get = _.bind(collection.get, collection); for (var prop in collection) { if (collection.hasOwnProperty(prop) && _.isFunction(collection[prop]) && !_.includes(knownCollectionMethods, prop)) { @@ -1351,5 +1403,5 @@ restangular.provider('Restangular', function() { return createServiceForConfiguration(globalConfiguration); }]; }); - -})(); + return restangular.name; +})); diff --git a/dist/restangular.min.js b/dist/restangular.min.js index f0599d58..7e481e41 100644 --- a/dist/restangular.min.js +++ b/dist/restangular.min.js @@ -1,6 +1,6 @@ /** * Restful Resources service for AngularJS apps - * @version v1.5.2 - 2016-02-08 * @link https://github.com/mgonto/restangular + * @version v1.6.0 - 2016-12-25 * @link https://github.com/mgonto/restangular * @author Martin Gontovnikas * @license MIT License, http://www.opensource.org/licenses/MIT - */!function(){var a=angular.module("restangular",[]);a.provider("Restangular",function(){var a={};a.init=function(a,b){function c(a,b,c,d){var e={};return _.each(_.keys(d),function(f){var g=d[f];g.params=_.extend({},g.params,a.defaultRequestParams[g.method.toLowerCase()]),_.isEmpty(g.params)&&delete g.params,a.isSafe(g.method)?e[f]=function(){return b(_.extend(g,{url:c}))}:e[f]=function(a){return b(_.extend(g,{url:c,data:a}))}}),e}a.configuration=b;var d=["get","head","options","trace","getlist"];b.isSafe=function(a){return _.includes(d,a.toLowerCase())};var e=/^https?:\/\//i;b.isAbsoluteUrl=function(a){return _.isUndefined(b.absoluteUrl)||_.isNull(b.absoluteUrl)?a&&e.test(a):b.absoluteUrl},b.absoluteUrl=_.isUndefined(b.absoluteUrl)?!0:b.absoluteUrl,a.setSelfLinkAbsoluteUrl=function(a){b.absoluteUrl=a},b.baseUrl=_.isUndefined(b.baseUrl)?"":b.baseUrl,a.setBaseUrl=function(a){return b.baseUrl=/\/$/.test(a)?a.substring(0,a.length-1):a,this},b.extraFields=b.extraFields||[],a.setExtraFields=function(a){return b.extraFields=a,this},b.defaultHttpFields=b.defaultHttpFields||{},a.setDefaultHttpFields=function(a){return b.defaultHttpFields=a,this},b.withHttpValues=function(a,c){return _.defaults(c,a,b.defaultHttpFields)},b.encodeIds=_.isUndefined(b.encodeIds)?!0:b.encodeIds,a.setEncodeIds=function(a){b.encodeIds=a},b.defaultRequestParams=b.defaultRequestParams||{get:{},post:{},put:{},remove:{},common:{}},a.setDefaultRequestParams=function(a,c){var d=[],e=c||a;return _.isUndefined(c)?d.push("common"):_.isArray(a)?d=a:d.push(a),_.each(d,function(a){b.defaultRequestParams[a]=e}),this},a.requestParams=b.defaultRequestParams,b.defaultHeaders=b.defaultHeaders||{},a.setDefaultHeaders=function(c){return b.defaultHeaders=c,a.defaultHeaders=b.defaultHeaders,this},a.defaultHeaders=b.defaultHeaders,b.methodOverriders=b.methodOverriders||[],a.setMethodOverriders=function(a){var c=_.extend([],a);return b.isOverridenMethod("delete",c)&&c.push("remove"),b.methodOverriders=c,this},b.jsonp=_.isUndefined(b.jsonp)?!1:b.jsonp,a.setJsonp=function(a){b.jsonp=a},b.isOverridenMethod=function(a,c){var d=c||b.methodOverriders;return!_.isUndefined(_.find(d,function(b){return b.toLowerCase()===a.toLowerCase()}))},b.urlCreator=b.urlCreator||"path",a.setUrlCreator=function(a){if(!_.has(b.urlCreatorFactory,a))throw new Error("URL Path selected isn't valid");return b.urlCreator=a,this},b.restangularFields=b.restangularFields||{id:"id",route:"route",parentResource:"parentResource",restangularCollection:"restangularCollection",cannonicalId:"__cannonicalId",etag:"restangularEtag",selfLink:"href",get:"get",getList:"getList",put:"put",post:"post",remove:"remove",head:"head",trace:"trace",options:"options",patch:"patch",getRestangularUrl:"getRestangularUrl",getRequestedUrl:"getRequestedUrl",putElement:"putElement",addRestangularMethod:"addRestangularMethod",getParentList:"getParentList",clone:"clone",ids:"ids",httpConfig:"_$httpConfig",reqParams:"reqParams",one:"one",all:"all",several:"several",oneUrl:"oneUrl",allUrl:"allUrl",customPUT:"customPUT",customPOST:"customPOST",customDELETE:"customDELETE",customGET:"customGET",customGETLIST:"customGETLIST",customOperation:"customOperation",doPUT:"doPUT",doPOST:"doPOST",doDELETE:"doDELETE",doGET:"doGET",doGETLIST:"doGETLIST",fromServer:"fromServer",withConfig:"withConfig",withHttpConfig:"withHttpConfig",singleOne:"singleOne",plain:"plain",save:"save",restangularized:"restangularized"},a.setRestangularFields=function(a){return b.restangularFields=_.extend(b.restangularFields,a),this},b.isRestangularized=function(a){return!!a[b.restangularFields.restangularized]},b.setFieldToElem=function(a,b,c){var d=a.split("."),e=b;return _.each(_.initial(d),function(a){e[a]={},e=e[a]}),e[_.last(d)]=c,this},b.getFieldFromElem=function(a,b){var c=a.split("."),d=b;return _.each(c,function(a){d&&(d=d[a])}),angular.copy(d)},b.setIdToElem=function(a,c){return b.setFieldToElem(b.restangularFields.id,a,c),this},b.getIdFromElem=function(a){return b.getFieldFromElem(b.restangularFields.id,a)},b.isValidId=function(a){return""!==a&&!_.isUndefined(a)&&!_.isNull(a)},b.setUrlToElem=function(a,c){return b.setFieldToElem(b.restangularFields.selfLink,a,c),this},b.getUrlFromElem=function(a){return b.getFieldFromElem(b.restangularFields.selfLink,a)},b.useCannonicalId=_.isUndefined(b.useCannonicalId)?!1:b.useCannonicalId,a.setUseCannonicalId=function(a){return b.useCannonicalId=a,this},b.getCannonicalIdFromElem=function(a){var c=a[b.restangularFields.cannonicalId],d=b.isValidId(c)?c:b.getIdFromElem(a);return d},b.responseInterceptors=b.responseInterceptors||[],b.defaultResponseInterceptor=function(a){return a},b.responseExtractor=function(a,c,d,e,f,g){var h=angular.copy(b.responseInterceptors);h.push(b.defaultResponseInterceptor);var i=a;return _.each(h,function(a){i=a(i,c,d,e,f,g)}),i},a.addResponseInterceptor=function(a){return b.responseInterceptors.push(a),this},b.errorInterceptors=b.errorInterceptors||[],a.addErrorInterceptor=function(a){return b.errorInterceptors.push(a),this},a.setResponseInterceptor=a.addResponseInterceptor,a.setResponseExtractor=a.addResponseInterceptor,a.setErrorInterceptor=a.addErrorInterceptor,b.requestInterceptors=b.requestInterceptors||[],b.defaultInterceptor=function(a,b,c,d,e,f,g){return{element:a,headers:e,params:f,httpConfig:g}},b.fullRequestInterceptor=function(a,c,d,e,f,g,h){var i=angular.copy(b.requestInterceptors),j=b.defaultInterceptor(a,c,d,e,f,g,h);return _.reduce(i,function(a,b){return _.extend(a,b(a.element,c,d,e,a.headers,a.params,a.httpConfig))},j)},a.addRequestInterceptor=function(a){return b.requestInterceptors.push(function(b,c,d,e,f,g,h){return{headers:f,params:g,element:a(b,c,d,e),httpConfig:h}}),this},a.setRequestInterceptor=a.addRequestInterceptor,a.addFullRequestInterceptor=function(a){return b.requestInterceptors.push(a),this},a.setFullRequestInterceptor=a.addFullRequestInterceptor,b.onBeforeElemRestangularized=b.onBeforeElemRestangularized||function(a){return a},a.setOnBeforeElemRestangularized=function(a){return b.onBeforeElemRestangularized=a,this},a.setRestangularizePromiseInterceptor=function(a){return b.restangularizePromiseInterceptor=a,this},b.onElemRestangularized=b.onElemRestangularized||function(a){return a},a.setOnElemRestangularized=function(a){return b.onElemRestangularized=a,this},b.shouldSaveParent=b.shouldSaveParent||function(){return!0},a.setParentless=function(a){return _.isArray(a)?b.shouldSaveParent=function(b){return!_.includes(a,b)}:_.isBoolean(a)&&(b.shouldSaveParent=function(){return!a}),this},b.suffix=_.isUndefined(b.suffix)?null:b.suffix,a.setRequestSuffix=function(a){return b.suffix=a,this},b.transformers=b.transformers||{},a.addElementTransformer=function(c,d,e){var f=null,g=null;2===arguments.length?g=d:(g=e,f=d);var h=b.transformers[c];return h||(h=b.transformers[c]=[]),h.push(function(a,b){return _.isNull(f)||a===f?g(b):b}),a},a.extendCollection=function(b,c){return a.addElementTransformer(b,!0,c)},a.extendModel=function(b,c){return a.addElementTransformer(b,!1,c)},b.transformElem=function(a,c,d,e,f){if(!f&&!b.transformLocalElements&&!a[b.restangularFields.fromServer])return a;var g=b.transformers[d],h=a;return g&&_.each(g,function(a){h=a(c,h)}),b.onElemRestangularized(h,c,d,e)},b.transformLocalElements=_.isUndefined(b.transformLocalElements)?!1:b.transformLocalElements,a.setTransformOnlyServerElements=function(a){b.transformLocalElements=!a},b.fullResponse=_.isUndefined(b.fullResponse)?!1:b.fullResponse,a.setFullResponse=function(a){return b.fullResponse=a,this},b.urlCreatorFactory={};var f=function(){};f.prototype.setConfig=function(a){return this.config=a,this},f.prototype.parentsArray=function(a){for(var b=[];a;)b.push(a),a=a[this.config.restangularFields.parentResource];return b.reverse()},f.prototype.resource=function(a,d,e,f,g,h,i,j){var k=_.defaults(g||{},this.config.defaultRequestParams.common),l=_.defaults(f||{},this.config.defaultHeaders);i&&(b.isSafe(j)?l["If-None-Match"]=i:l["If-Match"]=i);var m=this.base(a);if(h){var n="";/\/$/.test(m)||(n+="/"),n+=h,m+=n}return this.config.suffix&&-1===m.indexOf(this.config.suffix,m.length-this.config.suffix.length)&&!this.config.getUrlFromElem(a)&&(m+=this.config.suffix),a[this.config.restangularFields.httpConfig]=void 0,c(this.config,d,m,{getList:this.config.withHttpValues(e,{method:"GET",params:k,headers:l}),get:this.config.withHttpValues(e,{method:"GET",params:k,headers:l}),jsonp:this.config.withHttpValues(e,{method:"jsonp",params:k,headers:l}),put:this.config.withHttpValues(e,{method:"PUT",params:k,headers:l}),post:this.config.withHttpValues(e,{method:"POST",params:k,headers:l}),remove:this.config.withHttpValues(e,{method:"DELETE",params:k,headers:l}),head:this.config.withHttpValues(e,{method:"HEAD",params:k,headers:l}),trace:this.config.withHttpValues(e,{method:"TRACE",params:k,headers:l}),options:this.config.withHttpValues(e,{method:"OPTIONS",params:k,headers:l}),patch:this.config.withHttpValues(e,{method:"PATCH",params:k,headers:l})})};var g=function(){};g.prototype=new f,g.prototype.normalizeUrl=function(a){var b=/(http[s]?:\/\/)?(.*)?/.exec(a);return b[2]=b[2].replace(/[\\\/]+/g,"/"),"undefined"!=typeof b[1]?b[1]+b[2]:b[2]},g.prototype.base=function(a){var c=this;return _.reduce(this.parentsArray(a),function(a,d){var e,f=c.config.getUrlFromElem(d);if(f){if(c.config.isAbsoluteUrl(f))return f;e=f}else if(e=d[c.config.restangularFields.route],d[c.config.restangularFields.restangularCollection]){var g=d[c.config.restangularFields.ids];g&&(e+="/"+g.join(","))}else{var h;h=c.config.useCannonicalId?c.config.getCannonicalIdFromElem(d):c.config.getIdFromElem(d),b.isValidId(h)&&!d.singleOne&&(e+="/"+(c.config.encodeIds?encodeURIComponent(h):h))}return a=a.replace(/\/$/,"")+"/"+e,c.normalizeUrl(a)},this.config.baseUrl)},g.prototype.fetchUrl=function(a,b){var c=this.base(a);return b&&(c+="/"+b),c},g.prototype.fetchRequestedUrl=function(a,c){function d(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b.sort()}function e(a,b,c){for(var e=d(a),f=0;f