From 22ab41462b84046748e3afd90e3d3b60c4749a01 Mon Sep 17 00:00:00 2001 From: Evan Sharp Date: Sun, 15 Feb 2015 16:27:15 -0500 Subject: [PATCH] Chore(release): Bump Release 1.1.0 --- bower.json | 2 +- dist/angular-sails.js | 346 +++++++++++++++++++++++++++++--------- dist/angular-sails.min.js | 2 +- package.json | 2 +- 4 files changed, 269 insertions(+), 83 deletions(-) diff --git a/bower.json b/bower.json index 4592cc4..3196fc9 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-sails", - "version": "1.0.5", + "version": "1.1.0", "authors": [ "Jan-Oliver Pantel " ], diff --git a/dist/angular-sails.js b/dist/angular-sails.js index 330803b..e638df8 100644 --- a/dist/angular-sails.js +++ b/dist/angular-sails.js @@ -2,100 +2,286 @@ 'use strict'/*global angular */ angular.module('ngSails', ['ng']); -/*jslint sloppy:true*/ /*global angular, io */ -angular.module('ngSails').provider('$sails', function () { - var provider = this, - httpVerbs = ['get', 'post', 'put', 'delete'], - eventNames = ['on', 'once']; - - this.url = undefined; - this.interceptors = []; - this.responseHandler = undefined; - - this.$get = ['$q', '$timeout', function ($q, $timeout) { - var socket = io.connect(provider.url), - defer = function () { - var deferred = $q.defer(), - promise = deferred.promise; - - promise.success = function (fn) { - promise.then(function(response) { - fn(response.data, response.status, response.headers); - }); - return promise; - }; +(function(angular, io) { + 'use strict'; + io.sails.autoConnect = false; - promise.error = function (fn) { - promise.then(null, function(response) { - fn(response.data, response.status, response.headers); - }); - return promise; + // copied from angular + function parseHeaders(headers) { + var parsed = {}, + key, val, i; + if (!headers) return parsed; + angular.forEach(headers.split('\n'), function(line) { + i = line.indexOf(':'); + key = lowercase(trim(line.substr(0, i))); + val = trim(line.substr(i + 1)); + if (key) { + parsed[key] = parsed[key] ? parsed[key] + ', ' + val : val; + } + }); + + return parsed; + } + + function trim(value) { + return angular.isString(value) ? value.trim() : value; + } + + function isPromiseLike (obj){ + return obj && angular.isFunction(obj.then); + } + + // copied from angular + function headersGetter(headers) { + var headersObj = angular.isObject(headers) ? headers : undefined; + return function(name) { + if (!headersObj) headersObj = parseHeaders(headers); + if (name) { + var value = headersObj[lowercase(name)]; + if (value === void 0) { + value = null; + } + return value; + } + return headersObj; + }; + } + + angular.module('ngSails').provider('$sails', function() { + var provider = this; + + this.httpVerbs = ['get', 'post', 'put', 'delete']; + + this.eventNames = ['on', 'off', 'once']; + + this.url = undefined; + + this.urlPrefix = ''; + + this.config = { + transports: ['websocket', 'polling'], + useCORSRouteToGetCookie: false + }; + + this.debug = false; + + // like https://docs.angularjs.org/api/ng/service/$http#interceptors + // but with sails.io arguments + var interceptorFactories = this.interceptors = [ + /*function($injectables) { + return { + request: function(config) {}, + response: function(response) {}, + requestError: function(rejection) {}, + responseError: function(rejection) {} }; + }*/ + ]; - return deferred; - }, - resolveOrReject = this.responseHandler || function (deferred, response) { - var jwr = response; - - // backward compatibility with older sails.io (no JWR) - if(!(response instanceof Object && response.constructor.name === "JWR")){ - jwr = { - body: response, - headers: response.headers || {}, - statusCode: response.statusCode || response.status - }; + /*@ngInject*/ + this.$get = ["$q", "$injector", "$rootScope", "$log", "$timeout", function($q, $injector, $rootScope, $log, $timeout) { + var socket = (io.sails && io.sails.connect || io.connect)(provider.url, provider.config); + + socket.connect = function(opts){ + if(!socket.isConnected()){ + var _opts = opts||{}; + _opts = angular.extend({},provider.config,opts); + + // These are the options sails.io.js actually sets when making the connection. + socket.useCORSRouteToGetCookie = _opts.useCORSRouteToGetCookie; + socket.url = _opts.url || provider.url; + socket.multiplex = _opts.multiplex; + + socket._connect(); } + return socket; + } - // angular $http returns the 'body' as 'data'. - jwr.data = jwr.body; + // TODO: separate out interceptors into its own file (and provider?). + // build interceptor chain + var reversedInterceptors = []; + angular.forEach(interceptorFactories, function(interceptorFactory) { + reversedInterceptors.unshift( + angular.isString(interceptorFactory) ? + $injector.get(interceptorFactory) : $injector.invoke(interceptorFactory) + ); + }); - // angular $http returns the 'statusCode' as 'status'. - jwr.status = jwr.statusCode; + // Send the request using the socket + function serverRequest(config) { + var defer = $q.defer(); + if (provider.debug) $log.info('$sails ' + config.method + ' ' + config.url, config.data || ''); - // TODO: map 'status'/'statusCode' to a 'statusText' to mimic angular $http + if (config.timeout > 0) { + $timeout(timeoutRequest, config.timeout); + } else if (isPromiseLike(config.timeout)) { + config.timeout.then(timeoutRequest); + } + + socket['legacy_' + config.method.toLowerCase()](config.url, config.data, serverResponse); - if (jwr.error) { - deferred.reject(jwr); - } else { - deferred.resolve(jwr); + function timeoutRequest(){ + serverResponse(null); } - }, - angularify = function (cb, data) { - $timeout(function () { - cb(data); - }); - }, - promisify = function (methodName) { - socket['legacy_' + methodName] = socket[methodName]; - socket[methodName] = function (url, data, cb) { - var deferred = defer(); - if (cb === undefined && angular.isFunction(data)) { - cb = data; - data = null; + + function serverResponse(result, jwr) { + + if (!jwr) { + jwr = { + body: result, + headers: result.headers || {}, + statusCode: result.statusCode || result.status || 0, + error: (function() { + if (this.statusCode < 200 || this.statusCode >= 400) { + return this.body || this.statusCode; + } + })() + }; + } + + jwr.data = jwr.body; // $http compat + jwr.status = jwr.statusCode; // $http compat + jwr.socket = socket; + jwr.url = config.url; + jwr.method = config.method; + jwr.config = config.config; + if (jwr.error) { + if (provider.debug) $log.warn('$sails response ' + jwr.statusCode + ' ' + config.url, jwr); + defer.reject(jwr); + } else { + if (provider.debug) $log.info('$sails response ' + config.url, jwr); + defer.resolve(jwr); } - deferred.promise.then(cb); - socket['legacy_' + methodName](url, data, function (emulatedHTTPBody, jsonWebSocketResponse) { - resolveOrReject(deferred, jsonWebSocketResponse || emulatedHTTPBody); + } + + return defer.promise; + } + + function promisify(methodName) { + socket['legacy_' + methodName] = socket[methodName]; + + socket[methodName] = function(url, data, config) { + + var chain = [serverRequest, undefined]; + + //TODO: more compatible with $http methods and config + + var promise = $q.when({ + url: provider.urlPrefix + url, + data: data, + socket: socket, + config: config || {}, + method: methodName.toUpperCase() }); - return deferred.promise; - }; - }, - wrapEvent = function (eventName) { - socket['legacy_' + eventName] = socket[eventName]; - socket[eventName] = function (event, cb) { - if (cb !== null && angular.isFunction(cb)) { - socket['legacy_' + eventName](event, function (result) { - angularify(cb, result); - }); + + // apply interceptors + angular.forEach(reversedInterceptors, function(interceptor) { + if (interceptor.request || interceptor.requestError) { + chain.unshift(interceptor.request, interceptor.requestError); + } + if (interceptor.response || interceptor.responseError) { + chain.push(interceptor.response, interceptor.responseError); + } + }); + + while (chain.length) { + var thenFn = chain.shift(); + var rejectFn = chain.shift(); + + promise = promise.then(thenFn, rejectFn); } + + // be $http compatible + promise.success = function(fn) { + promise.then(function(jwr) { + fn(jwr.body, jwr.statusCode, headersGetter(jwr.headers), jwr); + }); + return promise; + }; + promise.error = function(fn) { + promise.then(null, function(jwr) { + fn(jwr.body, jwr.statusCode, headersGetter(jwr.headers), jwr); + }); + return promise; + }; + + return promise; }; - }; + } + + function wrapEvent(eventName) { + if(socket[eventName] || socket._raw[eventName]){ + socket['legacy_' + eventName] = socket[eventName] || socket._raw[eventName]; + socket[eventName] = function(event, cb) { + if (cb !== null && angular.isFunction(cb)) { + socket['legacy_' + eventName](event, function(result) { + $rootScope.$evalAsync(cb.bind(socket, result)); + }); + } + }; + } + } + + angular.forEach(provider.httpVerbs, promisify); + angular.forEach(provider.eventNames, wrapEvent); + + + /** + * Update a model on sails pushes + * @param {String} name Sails model name + * @param {Array} models Array with model objects + */ + socket.$modelUpdater = function(name, models) { + + socket.on(name, function(message) { + var i; + + switch (message.verb) { - angular.forEach(httpVerbs, promisify); - angular.forEach(eventNames, wrapEvent); + case "created": + // create new model item + models.push(message.data); + break; + + case "updated": + var obj; + for (i = 0; i < models.length; i++) { + if (models[i].id === message.id) { + obj = models[i]; + break; + } + } + + // cant update if the angular-model does not have the item and the + // sails message does not give us the previous record + if (!obj && !message.previous) return; + + if (!obj) { + // sails has given us the previous record, create it in our model + obj = message.previous; + models.push(obj); + } + + // update the model item + angular.extend(obj, message.data); + break; + + case "destroyed": + for (i = 0; i < models.length; i++) { + if (models[i].id === message.id) { + models.splice(i, 1); + break; + } + } + break; + } + }); + }; - return socket; - }]; -}); + return socket; + }]; + this.$get.$inject = ["$q", "$injector", "$rootScope", "$log", "$timeout"]; + }); +}(angular, io)); }(angular, io)); \ No newline at end of file diff --git a/dist/angular-sails.min.js b/dist/angular-sails.min.js index c365442..67c8e1c 100644 --- a/dist/angular-sails.min.js +++ b/dist/angular-sails.min.js @@ -1 +1 @@ -!function(t,n){"use strict";t.module("ngSails",["ng"]),t.module("ngSails").provider("$sails",function(){var e=this,o=["get","post","put","delete"],r=["on","once"];this.url=void 0,this.interceptors=[],this.responseHandler=void 0,this.$get=["$q","$timeout",function(s,u){var i=n.connect(e.url),a=function(){var t=s.defer(),n=t.promise;return n.success=function(t){return n.then(function(n){t(n.data,n.status,n.headers)}),n},n.error=function(t){return n.then(null,function(n){t(n.data,n.status,n.headers)}),n},t},c=this.responseHandler||function(t,n){var e=n;n instanceof Object&&"JWR"===n.constructor.name||(e={body:n,headers:n.headers||{},statusCode:n.statusCode||n.status}),e.data=e.body,e.status=e.statusCode,e.error?t.reject(e):t.resolve(e)},d=function(t,n){u(function(){t(n)})},l=function(n){i["legacy_"+n]=i[n],i[n]=function(e,o,r){var s=a();return void 0===r&&t.isFunction(o)&&(r=o,o=null),s.promise.then(r),i["legacy_"+n](e,o,function(t,n){c(s,n||t)}),s.promise}},f=function(n){i["legacy_"+n]=i[n],i[n]=function(e,o){null!==o&&t.isFunction(o)&&i["legacy_"+n](e,function(t){d(o,t)})}};return t.forEach(o,l),t.forEach(r,f),i}]})}(angular,io); \ No newline at end of file +!function(e,t){"use strict";e.module("ngSails",["ng"]),function(e,t){function o(t){var o,r,s,i={};return t?(e.forEach(t.split("\n"),function(e){s=e.indexOf(":"),o=lowercase(n(e.substr(0,s))),r=n(e.substr(s+1)),o&&(i[o]=i[o]?i[o]+", "+r:r)}),i):i}function n(t){return e.isString(t)?t.trim():t}function r(t){return t&&e.isFunction(t.then)}function s(t){var n=e.isObject(t)?t:void 0;return function(e){if(n||(n=o(t)),e){var r=n[lowercase(e)];return void 0===r&&(r=null),r}return n}}t.sails.autoConnect=!1,e.module("ngSails").provider("$sails",function(){var o=this;this.httpVerbs=["get","post","put","delete"],this.eventNames=["on","off","once"],this.url=void 0,this.urlPrefix="",this.config={transports:["websocket","polling"],useCORSRouteToGetCookie:!1},this.debug=!1;var n=this.interceptors=[];this.$get=["$q","$injector","$rootScope","$log","$timeout",function(i,u,a,c,d){function f(e){function t(){n(null)}function n(t,n){n||(n={body:t,headers:t.headers||{},statusCode:t.statusCode||t.status||0,error:function(){return this.statusCode<200||this.statusCode>=400?this.body||this.statusCode:void 0}()}),n.data=n.body,n.status=n.statusCode,n.socket=g,n.url=e.url,n.method=e.method,n.config=e.config,n.error?(o.debug&&c.warn("$sails response "+n.statusCode+" "+e.url,n),s.reject(n)):(o.debug&&c.info("$sails response "+e.url,n),s.resolve(n))}var s=i.defer();return o.debug&&c.info("$sails "+e.method+" "+e.url,e.data||""),e.timeout>0?d(t,e.timeout):r(e.timeout)&&e.timeout.then(t),g["legacy_"+e.method.toLowerCase()](e.url,e.data,n),s.promise}function l(t){g["legacy_"+t]=g[t],g[t]=function(n,r,u){var a=[f,void 0],c=i.when({url:o.urlPrefix+n,data:r,socket:g,config:u||{},method:t.toUpperCase()});for(e.forEach(p,function(e){(e.request||e.requestError)&&a.unshift(e.request,e.requestError),(e.response||e.responseError)&&a.push(e.response,e.responseError)});a.length;){var d=a.shift(),l=a.shift();c=c.then(d,l)}return c.success=function(e){return c.then(function(t){e(t.body,t.statusCode,s(t.headers),t)}),c},c.error=function(e){return c.then(null,function(t){e(t.body,t.statusCode,s(t.headers),t)}),c},c}}function h(t){(g[t]||g._raw[t])&&(g["legacy_"+t]=g[t]||g._raw[t],g[t]=function(o,n){null!==n&&e.isFunction(n)&&g["legacy_"+t](o,function(e){a.$evalAsync(n.bind(g,e))})})}var g=(t.sails&&t.sails.connect||t.connect)(o.url,o.config);g.connect=function(t){if(!g.isConnected()){var n=t||{};n=e.extend({},o.config,t),g.useCORSRouteToGetCookie=n.useCORSRouteToGetCookie,g.url=n.url||o.url,g.multiplex=n.multiplex,g._connect()}return g};var p=[];return e.forEach(n,function(t){p.unshift(e.isString(t)?u.get(t):u.invoke(t))}),e.forEach(o.httpVerbs,l),e.forEach(o.eventNames,h),g.$modelUpdater=function(t,o){g.on(t,function(t){var n;switch(t.verb){case"created":o.push(t.data);break;case"updated":var r;for(n=0;n