diff --git a/.gitignore b/.gitignore
index 54827f7960..bc84c44c73 100644
--- a/.gitignore
+++ b/.gitignore
@@ -76,7 +76,8 @@ src/Umbraco.Web.UI/umbraco/[V]iews/**/*.css
src/Umbraco.Web.UI/umbraco/[V]iews/**/*.html
src/Umbraco.Web.UI/umbraco/assets/*
src/Umbraco.Web.UI.Client/build/*
-src/Umbraco.Web.UI.Client/build/*
+src/Umbraco.Web.UI.Client/build/**/*.*
src/Umbraco.Web.UI.Client/build/belle/
src/Umbraco.Web.UI/UserControls/
build/_BuildOutput/
+build/belle/
diff --git a/src/Umbraco.Web.UI.Client/gruntFile.js b/src/Umbraco.Web.UI.Client/gruntFile.js
index 9acd5611d3..c765cba57d 100644
--- a/src/Umbraco.Web.UI.Client/gruntFile.js
+++ b/src/Umbraco.Web.UI.Client/gruntFile.js
@@ -105,8 +105,8 @@ module.exports = function (grunt) {
},
app: {
files: [
- { dest: '<%= distdir %>/js', src : 'main.js', expand: true, cwd: 'src/' },
- { dest: '<%= distdir %>/js', src : 'routes.js', expand: true, cwd: 'src/' }]
+ { dest: '<%= distdir %>/js', src : '*.js', expand: true, cwd: 'src/' }
+ ]
},
media: {
files: [{ dest: 'build/media', src : '*.*', expand: true, cwd: 'media/' }]
@@ -130,65 +130,37 @@ module.exports = function (grunt) {
process: true
}
},
- app: {
- src: ['src/app.js'],
- dest: '<%= distdir %>/js/app.js',
- options:{
- banner: "<%= banner %>'use strict';\ndefine(['angular'], function (angular) {\n",
- footer: "\n\nreturn app;\n});"
- }
- },
angular: {
src:['vendor/angular/angular.min.js'],
dest: '<%= distdir %>/lib/angular/angular.min.js'
},
controllers: {
src:['src/views/**/*.controller.js'],
- dest: '<%= distdir %>/js/umbraco.controllers.js',
- options:{
- banner: "'use strict';\n<%= banner %>\ndefine(['app', 'angular'], function (app, angular) {\n",
- footer: "\n\nreturn angular;\n});"
- }
+ dest: '<%= distdir %>/js/umbraco.controllers.js'
},
services: {
src:['src/common/services/*.js'],
- dest: '<%= distdir %>/js/umbraco.services.js',
- options:{
- banner: "'use strict';\ndefine(['app','angular'], function (app, angular) {\n",
- footer: "\n\nreturn angular;\n});"
- }
+ dest: '<%= distdir %>/js/umbraco.services.js'
+ },
+ security: {
+ src:['src/common/security/*.js'],
+ dest: '<%= distdir %>/js/umbraco.security.js'
},
resources: {
src:['src/common/resources/*.js'],
- dest: '<%= distdir %>/js/umbraco.resources.js',
- options:{
- banner: "<%= banner %>'use strict';\ndefine(['app', 'angular'], function (app, angular) {\n",
- footer: "\n\nreturn angular;\n});"
- }
+ dest: '<%= distdir %>/js/umbraco.resources.js'
},
mocks: {
src:['src/common/mocks/**/*.js'],
- dest: '<%= distdir %>/js/umbraco.mocks.js',
- options:{
- banner: "<%= banner %>'use strict';\ndefine(['app', 'angular'], function (app, angular) {\n",
- footer: "\n\nreturn angular;\n});"
- }
+ dest: '<%= distdir %>/js/umbraco.mocks.js'
},
directives: {
src:['src/common/directives/*.js'],
- dest: '<%= distdir %>/js/umbraco.directives.js',
- options:{
- banner: "<%= banner %>'use strict';\ndefine(['app','angular','underscore'], function (app, angular,_) {\n",
- footer: "\n\nreturn angular;\n});"
- }
+ dest: '<%= distdir %>/js/umbraco.directives.js'
},
filters: {
src:['src/common/filters/*.js'],
- dest: '<%= distdir %>/js/umbraco.filters.js',
- options:{
- banner: "<%= banner %>'use strict';\ndefine([ 'app','angular'], function (app,angular) {\n",
- footer: "\n\nreturn app;\n});"
- }
+ dest: '<%= distdir %>/js/umbraco.filters.js'
}
},
diff --git a/src/Umbraco.Web.UI.Client/lib/yepnope/yepnope.min.js b/src/Umbraco.Web.UI.Client/lib/yepnope/yepnope.min.js
new file mode 100644
index 0000000000..73655a5b27
--- /dev/null
+++ b/src/Umbraco.Web.UI.Client/lib/yepnope/yepnope.min.js
@@ -0,0 +1,2 @@
+/*yepnope1.5.x|WTFPL*/
+(function(a,b,c){function d(a){return"[object Function]"==o.call(a)}function e(a){return"string"==typeof a}function f(){}function g(a){return!a||"loaded"==a||"complete"==a||"uninitialized"==a}function h(){var a=p.shift();q=1,a?a.t?m(function(){("c"==a.t?B.injectCss:B.injectJs)(a.s,0,a.a,a.x,a.e,1)},0):(a(),h()):q=0}function i(a,c,d,e,f,i,j){function k(b){if(!o&&g(l.readyState)&&(u.r=o=1,!q&&h(),l.onload=l.onreadystatechange=null,b)){"img"!=a&&m(function(){t.removeChild(l)},50);for(var d in y[c])y[c].hasOwnProperty(d)&&y[c][d].onload()}}var j=j||B.errorTimeout,l=b.createElement(a),o=0,r=0,u={t:d,s:c,e:f,a:i,x:j};1===y[c]&&(r=1,y[c]=[]),"object"==a?l.data=c:(l.src=c,l.type=a),l.width=l.height="0",l.onerror=l.onload=l.onreadystatechange=function(){k.call(this,r)},p.splice(e,0,u),"img"!=a&&(r||2===y[c]?(t.insertBefore(l,s?null:n),m(k,j)):y[c].push(l))}function j(a,b,c,d,f){return q=0,b=b||"j",e(a)?i("c"==b?v:u,a,b,this.i++,c,d,f):(p.splice(this.i++,0,a),1==p.length&&h()),this}function k(){var a=B;return a.loader={load:j,i:0},a}var l=b.documentElement,m=a.setTimeout,n=b.getElementsByTagName("script")[0],o={}.toString,p=[],q=0,r="MozAppearance"in l.style,s=r&&!!b.createRange().compareNode,t=s?l:n.parentNode,l=a.opera&&"[object Opera]"==o.call(a.opera),l=!!b.attachEvent&&!l,u=r?"object":l?"script":"img",v=l?"script":u,w=Array.isArray||function(a){return"[object Array]"==o.call(a)},x=[],y={},z={timeout:function(a,b){return b.length&&(a.timeout=b[0]),a}},A,B;B=function(a){function b(a){var a=a.split("!"),b=x.length,c=a.pop(),d=a.length,c={url:c,origUrl:c,prefixes:a},e,f,g;for(f=0;f
askjdkasj lasjd
" }, - { alias: "textarea", label: "textarea", view: "umbraco.textarea", value: "ajsdka sdjkds", config: { rows: 4 } }, - { alias: "map", label: "Map", view: "umbraco.googlemaps", value: "37.4419,-122.1419", config: { mapType: "ROADMAP", zoom: 4 } }, - { alias: "media", label: "Media picker", view: "umbraco.mediapicker", value: "" }, - { alias: "content", label: "Content picker", view: "umbraco.contentpicker", value: "" } - ] - }, - { - label: "Sample Editor", - alias: "tab02", - id: 2, - properties: [ - { alias: "datepicker", label: "Datepicker", view: "umbraco.datepicker", config: { rows: 7 } }, - { alias: "tags", label: "Tags", view: "umbraco.tags", value: ""} - ] - }, - { - label: "Grid", - alias: "tab03", - id: 3, - properties: [ - { alias: "grid", label: "Grid", view: "umbraco.grid", controller: "umbraco.grid", value: "test", hideLabel: true } - ] - },{ - label: "WIP", - alias: "tab04", - id: 4, - properties: [ - { alias: "tes", label: "Stuff", view: "umbraco.test", controller: "umbraco.embeddedcontent", value: "", - - config: { - fields: [ - { alias: "embedded", label: "Embbeded", view: "umbraco.textstring", value: ""}, - { alias: "embedded2", label: "Embbeded 2", view: "umbraco.contentpicker", value: ""}, - { alias: "embedded3", label: "Embbeded 3", view: "umbraco.textarea", value: ""}, - { alias: "embedded4", label: "Embbeded 4", view: "umbraco.datepicker", value: ""} - ] - } - } - ] - } - - - ] - }; - - // return undefined; - - return content; + return deferred.promise; }, //returns an empty content object which can be persistent on the content service @@ -131,7 +131,7 @@ angular.module('umbraco.mocks.resources') var _id = 0; for (var i = 0; i < collection.take; i++) { _id = (parentId + i) * options.offset; - var cnt = this.getContent(_id); + var cnt = this.getById(_id); //here we fake filtering if(options.filter !== ''){ diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.resource.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.resource.js index 9eddb304d8..7fe28ecab1 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/media.resource.js @@ -1,13 +1,19 @@ angular.module('umbraco.mocks.resources') -.factory('mediaResource', function () { +.factory('mediaResource', function ($q) { var mediaArray = []; return { rootMedia: function(){ - return [ - {id: 1234, src: "/Media/boston.jpg", thumbnail: "/Media/boston.jpg" }, - {src: "/Media/bird.jpg", thumbnail: "/Media/bird.jpg" }, - {src: "/Media/frog.jpg", thumbnail: "/Media/frog.jpg" } - ]; + + var deferred = $q.defer(); + + deferred.resolve( + [ + {id: 1234, src: "/Media/boston.jpg", thumbnail: "/Media/boston.jpg" }, + {src: "/Media/bird.jpg", thumbnail: "/Media/bird.jpg" }, + {src: "/Media/frog.jpg", thumbnail: "/Media/frog.jpg" } + ]); + + return deferred.promise; } }; }); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.resource.js b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.resource.js index 0158f0a8ad..2489631ea2 100644 --- a/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/mocks/resources/tree.resource.js @@ -21,10 +21,10 @@ function treeResource($q) { } return [ - { name: "child-of-" + treeItem.name, id: iLevel + "" + 1234, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1234, children: [], expanded: false, level: iLevel, defaultAction: action }, - { name: "random-name-" + section, id: iLevel + "" + 1235, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1235, children: [], expanded: false, level: iLevel, defaultAction: action }, - { name: "random-name-" + section, id: iLevel + "" + 1236, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1236, children: [], expanded: false, level: iLevel, defaultAction: action }, - { name: "random-name-" + section, id: iLevel + "" + 1237, icon: "icon-file-alt", view: "common/legacy/1237?p=" + encodeURI("developer/contentType.aspx?idequal1234"), children: [], expanded: false, level: iLevel, defaultAction: action } + { name: "child-of-" + treeItem.name, id: iLevel + "" + 1234, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1234, children: [], expanded: false, hasChildren: true, level: iLevel, defaultAction: action }, + { name: "random-name-" + section, id: iLevel + "" + 1235, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1235, children: [], expanded: false, hasChildren: true, level: iLevel, defaultAction: action }, + { name: "random-name-" + section, id: iLevel + "" + 1236, icon: "icon-file-alt", view: section + "/edit/" + iLevel + "" + 1236, children: [], expanded: false, hasChildren: true, level: iLevel, defaultAction: action }, + { name: "random-name-" + section, id: iLevel + "" + 1237, icon: "icon-file-alt", view: "common/legacy/1237?p=" + encodeURI("developer/contentType.aspx?idequal1234"), children: [], expanded: false, hasChildren: true, level: iLevel, defaultAction: action } ]; } @@ -36,7 +36,7 @@ function treeResource($q) { var section = options.section || 'content'; var cacheKey = options.cachekey || ''; - cacheKey += "_" + section; + cacheKey += "_" + section; if (treeArray[cacheKey] !== undefined){ return treeArray[cacheKey]; @@ -46,59 +46,39 @@ function treeResource($q) { switch(section){ case "content": - t = { - name: section, - alias: section, - - children: [ - { name: "My website", id: 1234, icon: "icon-home", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1, defaultAction: "create" }, - { name: "Components", id: 1235, icon: "icon-cogs", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1, defaultAction: "create" }, - { name: "Archieve", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1, defaultAction: "create" }, - { name: "Recycle Bin", id: 1237, icon: "icon-trash", view: section + "/trash/view/", children: [], expanded: false, level: 1, defaultAction: "create" } - ] - }; + t = [ + { name: "My website", id: 1234, icon: "icon-home", view: section + "/edit/" + 1234, children: [], expanded: false, hasChildren: true, level: 1, defaultAction: "create" }, + { name: "Components", id: 1235, icon: "icon-cogs", view: section + "/edit/" + 1235, children: [], expanded: false, hasChildren: true, level: 1, defaultAction: "create" }, + { name: "Archieve", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, hasChildren: true, level: 1, defaultAction: "create" }, + { name: "Recycle Bin", id: 1237, icon: "icon-trash", view: section + "/trash/view/", children: [], expanded: false, hasChildren: true, level: 1, defaultAction: "create" } + ]; break; case "developer": - t = { - name: section, - alias: section, - - children: [ - { name: "Data types", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, - { name: "Macros", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, - { name: "Pacakges", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, - { name: "XSLT Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 }, - { name: "Razor Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } - ] - }; + t = [ + { name: "Data types", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "Macros", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "Pacakges", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "XSLT Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "Razor Files", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, hasChildren: true, level: 1 } + ]; break; case "settings": - t = { - name: section, - alias: section, - - children: [ - { name: "Stylesheets", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, - { name: "Templates", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, - { name: "Dictionary", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, - { name: "Media types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 }, - { name: "Document types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } - ] - }; + t = [ + { name: "Stylesheets", id: 1234, icon: "icon-folder-close", view: section + "/edit/" + 1234, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "Templates", id: 1235, icon: "icon-folder-close", view: section + "/edit/" + 1235, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "Dictionary", id: 1236, icon: "icon-folder-close", view: section + "/edit/" + 1236, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "Media types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "Document types", id: 1237, icon: "icon-folder-close", view: section + "/edit/" + 1237, children: [], expanded: false, hasChildren: true, level: 1 } + ]; break; default: - t = { - name: section, - alias: section, - - children: [ - { name: "random-name-" + section, id: 1234, icon: "icon-home", defaultAction: "create", view: section + "/edit/" + 1234, children: [], expanded: false, level: 1 }, - { name: "random-name-" + section, id: 1235, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1235, children: [], expanded: false, level: 1 }, - { name: "random-name-" + section, id: 1236, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1236, children: [], expanded: false, level: 1 }, - { name: "random-name-" + section, id: 1237, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1237, children: [], expanded: false, level: 1 } - ] - }; + t = [ + { name: "random-name-" + section, id: 1234, icon: "icon-home", defaultAction: "create", view: section + "/edit/" + 1234, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "random-name-" + section, id: 1235, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1235, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "random-name-" + section, id: 1236, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1236, children: [], expanded: false, hasChildren: true, level: 1 }, + { name: "random-name-" + section, id: 1237, icon: "icon-folder-close", defaultAction: "create", view: section + "/edit/" + 1237, children: [], expanded: false, hasChildren: true, level: 1 } + ]; break; } @@ -121,7 +101,6 @@ function treeResource($q) { var deferred = $q.defer(); var data = _getChildren(options); - deferred.resolve(data); return deferred.promise; } diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js index 24cdc63116..c33e6aacf8 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/content.resource.js @@ -52,7 +52,7 @@ function contentResource($q, $http, umbDataFormatter, umbRequestHelper) { deferred.reject('Failed to retreive data for content id ' + id); }); - return deferred.promise; + return deferred.promise; }, getByIds: function (ids) { diff --git a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js index 51373415a8..2673bbd343 100644 --- a/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js +++ b/src/Umbraco.Web.UI.Client/src/common/resources/media.resource.js @@ -121,7 +121,7 @@ function mediaResource($q, $http, umbDataFormatter, umbRequestHelper) { /** saves or updates a media object */ saveMedia: function (media, isNew, files) { return saveMediaItem(media, "save" + (isNew ? "New" : ""), files); - }, + } }; } diff --git a/src/Umbraco.Web.UI.Client/src/common/security/_module.js b/src/Umbraco.Web.UI.Client/src/common/security/_module.js new file mode 100644 index 0000000000..93b0f58c1d --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/security/_module.js @@ -0,0 +1,4 @@ +// Based loosely around work by Witold Szczerba - https://github.com/witoldsz/angular-http-auth +angular.module('umbraco.security', [ + 'umbraco.security.service', + 'umbraco.security.interceptor']); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js b/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js new file mode 100644 index 0000000000..892b46fe24 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/security/interceptor.js @@ -0,0 +1,23 @@ +angular.module('umbraco.security.interceptor', ['umbraco.security.retryQueue']) + +// This http interceptor listens for authentication failures +.factory('securityInterceptor', ['$injector', 'securityRetryQueue', function($injector, queue) { + return function(promise) { + // Intercept failed requests + return promise.then(null, function(originalResponse) { + if(originalResponse.status === 401) { + // The request bounced because it was not authorized - add a new request to the retry queue + promise = queue.pushRetryFn('unauthorized-server', function retryRequest() { + // We must use $injector to get the $http service to prevent circular dependency + return $injector.get('$http')(originalResponse.config); + }); + } + return promise; + }); + }; +}]) + +// We have to add the interceptor to the queue as a string because the interceptor depends upon service instances that are not available in the config block. +.config(['$httpProvider', function($httpProvider) { + $httpProvider.responseInterceptors.push('securityInterceptor'); +}]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/security/retryqueue.js b/src/Umbraco.Web.UI.Client/src/common/security/retryqueue.js new file mode 100644 index 0000000000..f734eecb87 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/security/retryqueue.js @@ -0,0 +1,68 @@ +angular.module('umbraco.security.retryQueue', []) + +// This is a generic retry queue for security failures. Each item is expected to expose two functions: retry and cancel. +.factory('securityRetryQueue', ['$q', '$log', function($q, $log) { + var retryQueue = []; + var service = { + // The security service puts its own handler in here! + onItemAddedCallbacks: [], + + hasMore: function() { + return retryQueue.length > 0; + }, + push: function(retryItem) { + retryQueue.push(retryItem); + // Call all the onItemAdded callbacks + angular.forEach(service.onItemAddedCallbacks, function(cb) { + try { + cb(retryItem); + } catch(e) { + $log.error('securityRetryQueue.push(retryItem): callback threw an error' + e); + } + }); + }, + pushRetryFn: function(reason, retryFn) { + // The reason parameter is optional + if ( arguments.length === 1) { + retryFn = reason; + reason = undefined; + } + + // The deferred object that will be resolved or rejected by calling retry or cancel + var deferred = $q.defer(); + var retryItem = { + reason: reason, + retry: function() { + // Wrap the result of the retryFn into a promise if it is not already + $q.when(retryFn()).then(function(value) { + // If it was successful then resolve our deferred + deferred.resolve(value); + }, function(value) { + // Othewise reject it + deferred.reject(value); + }); + }, + cancel: function() { + // Give up on retrying and reject our deferred + deferred.reject(); + } + }; + service.push(retryItem); + return deferred.promise; + }, + retryReason: function() { + return service.hasMore() && retryQueue[0].reason; + }, + cancelAll: function() { + while(service.hasMore()) { + retryQueue.shift().cancel(); + } + }, + retryAll: function() { + while(service.hasMore()) { + retryQueue.shift().retry(); + } + } + }; + return service; +}]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/security/security.service.js b/src/Umbraco.Web.UI.Client/src/common/security/security.service.js new file mode 100644 index 0000000000..bc6406d744 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/security/security.service.js @@ -0,0 +1,114 @@ +// Based loosely around work by Witold Szczerba - https://github.com/witoldsz/angular-http-auth +angular.module('umbraco.security.service', [ + 'umbraco.security.retryQueue', // Keeps track of failed requests that need to be retried once the user logs in + 'umbraco.services' +]) + +.factory('security', ['$http', '$q', '$location', 'securityRetryQueue', 'dialogService', function($http, $q, $location, queue, $dialog) { + + // Redirect to the given url (defaults to '/') + function redirect(url) { + url = url || '/'; + $location.path(url); + } + + // Login form dialog stuff + var loginDialog = null; + + function openLoginDialog() { + if ( loginDialog ) { + throw new Error('Trying to open a dialog that is already open!'); + } + + //loginDialog = $dialog.dialog(); + //loginDialog.open('security/login/form.tpl.html', 'LoginFormController').then(onLoginDialogClose); + } + function closeLoginDialog(success) { + if (loginDialog) { + loginDialog.close(success); + } + } + + function onLoginDialogClose(success) { + loginDialog = null; + if ( success ) { + queue.retryAll(); + } else { + queue.cancelAll(); + redirect(); + } + } + + // Register a handler for when an item is added to the retry queue + queue.onItemAddedCallbacks.push(function(retryItem) { + if ( queue.hasMore() ) { + service.showLogin(); + } + }); + + // The public API of the service + var service = { + + // Get the first reason for needing a login + getLoginReason: function() { + return queue.retryReason(); + }, + + // Show the modal login dialog + showLogin: function() { + openLoginDialog(); + }, + + // Attempt to authenticate a user by the given email and password + login: function(email, password) { + var request = $http.post('/login', {email: email, password: password}); + return request.then(function(response) { + service.currentUser = response.data.user; + if ( service.isAuthenticated() ) { + closeLoginDialog(true); + } + }); + }, + + // Give up trying to login and clear the retry queue + cancelLogin: function() { + closeLoginDialog(false); + redirect(); + }, + + // Logout the current user and redirect + logout: function(redirectTo) { + $http.post('/logout').then(function() { + service.currentUser = null; + redirect(redirectTo); + }); + }, + + // Ask the backend to see if a user is already authenticated - this may be from a previous session. + requestCurrentUser: function() { + if ( service.isAuthenticated() ) { + return $q.when(service.currentUser); + } else { + return $http.get('/current-user').then(function(response) { + service.currentUser = response.data.user; + return service.currentUser; + }); + } + }, + + // Information about the current user + currentUser: null, + + // Is the current user authenticated? + isAuthenticated: function(){ + return !!service.currentUser; + }, + + // Is the current user an adminstrator? + isAdmin: function() { + return !!(service.currentUser && service.currentUser.admin); + } + }; + + return service; +}]); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/scriptloader.service.js b/src/Umbraco.Web.UI.Client/src/common/services/scriptloader.service.js new file mode 100644 index 0000000000..6e4f04364b --- /dev/null +++ b/src/Umbraco.Web.UI.Client/src/common/services/scriptloader.service.js @@ -0,0 +1,19 @@ +//script loader wrapping around 3rd party loader +angular.module('umbraco.services') +.factory('scriptLoader', function ($q) { + + return { + load: function (pathArray) { + var deferred = $q.defer(); + + yepnope({ + load: pathArray, + complete: function () { + deferred.resolve(true); + } + }); + + return deferred.promise; + } + }; +}); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/scripts.js b/src/Umbraco.Web.UI.Client/src/common/services/scripts.js deleted file mode 100644 index e4300f8a80..0000000000 --- a/src/Umbraco.Web.UI.Client/src/common/services/scripts.js +++ /dev/null @@ -1 +0,0 @@ -//script loader wrapping around 3rd party loader \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/common/services/utill.service.js b/src/Umbraco.Web.UI.Client/src/common/services/utill.service.js index d6391f0c9d..741d00d55f 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/utill.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/utill.service.js @@ -12,9 +12,9 @@ function umbImageHelper() { if (!options && !options.imageModel && !options.scope) { throw "The options objet does not contain the required parameters: imageModel, scope"; } - if (options.imageModel.contentTypeAlias.toLowerCase() == "image") { + if (options.imageModel.contentTypeAlias.toLowerCase() === "image") { var imageProp = _.find(options.imageModel.properties, function (item) { - return item.alias == 'umbracoFile'; + return item.alias === 'umbracoFile'; }); var imageVal; //Legacy images will be saved as a string, not an array so we will convert the legacy values @@ -40,7 +40,7 @@ function umbImageHelper() { } var imagePropVal = this.getImagePropertyVaue(options); - if (imagePropVal != "") { + if (imagePropVal !== "") { return this.getThumbnailFromPath(imagePropVal); } return ""; diff --git a/src/Umbraco.Web.UI.Client/src/index.html b/src/Umbraco.Web.UI.Client/src/index.html index d08d84172e..3d8f30376a 100644 --- a/src/Umbraco.Web.UI.Client/src/index.html +++ b/src/Umbraco.Web.UI.Client/src/index.html @@ -146,7 +146,12 @@ + + + +