diff --git a/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js new file mode 100644 index 0000000000..7fdd2c4c25 --- /dev/null +++ b/src/Umbraco.Web.UI.Client/lib/umbraco/LegacyUmbClientMgr.js @@ -0,0 +1,254 @@ + +//TODO: WE NEED TO CONVERT ALL OF THESE METHODS TO PROXY TO OUR APPLICATION SINCE MANY CUSTOM APPS USE THIS! + +Umbraco.Sys.registerNamespace("Umbraco.Application"); + +(function($) { + Umbraco.Application.ClientManager = function() { + + /** + * @ngdoc function + * @name getRootScope + * @methodOf UmbClientMgr + * @function + * + * @description + * Returns the root angular scope + */ + function getRootScope() { + return angular.element(document.getElementById("umbracoMainPageBody")).scope(); + } + + /** + * @ngdoc function + * @name getRootInjector + * @methodOf UmbClientMgr + * @function + * + * @description + * Returns the root angular injector + */ + function getRootInjector() { + return angular.element(document.getElementById("umbracoMainPageBody")).injector(); + } + + + return { + _isDirty: false, + _isDebug: false, + _mainTree: null, + _appActions: null, + _historyMgr: null, + _rootPath: "/umbraco", //this is the default + _modal: new Array(), //track all modal window objects (they get stacked) + + historyManager: function() { + if (!this._historyMgr) { + this._historyMgr = new Umbraco.Controls.HistoryManager(); + } + return this._historyMgr; + }, + + setUmbracoPath: function(strPath) { + /// + /// sets the Umbraco root path folder + /// + this._debug("setUmbracoPath: " + strPath); + this._rootPath = strPath; + }, + + mainWindow: function() { + /// + /// Returns a reference to the main frame of the application + /// + return top; + }, + mainTree: function() { + /// + /// Returns a reference to the main UmbracoTree API object. + /// Sometimes an Umbraco page will need to be opened without being contained in the iFrame from the main window + /// so this method is will construct a false tree to be returned if this is the case as to avoid errors. + /// + /// + + if (this._mainTree == null) { + if (this.mainWindow().jQuery == null + || this.mainWindow().jQuery(".umbTree").length == 0 + || this.mainWindow().jQuery(".umbTree").UmbracoTreeAPI() == null) { + //creates a false tree with all the public tree params set to a false method. + var tmpTree = {}; + var treeProps = ["init", "setRecycleBinNodeId", "clearTreeCache", "toggleEditMode", "refreshTree", "rebuildTree", "saveTreeState", "syncTree", "childNodeCreated", "moveNode", "copyNode", "findNode", "selectNode", "reloadActionNode", "getActionNode", "setActiveTreeType", "getNodeDef"]; + for (var p in treeProps) { + tmpTree[treeProps[p]] = function() { return false; }; + } + this._mainTree = tmpTree; + } + else { + this._mainTree = this.mainWindow().jQuery(".umbTree").UmbracoTreeAPI(); + } + } + return this._mainTree; + }, + appActions: function() { + /// + /// Returns a reference to the application actions object + /// + + //if the main window has no actions, we'll create some + if (this._appActions == null) { + if (typeof this.mainWindow().appActions == 'undefined') { + this._appActions = new Umbraco.Application.Actions(); + } + else this._appActions = this.mainWindow().appActions; + } + return this._appActions; + }, + uiKeys: function() { + /// + /// Returns a reference to the main windows uiKeys object for globalization + /// + + //TODO: If there is no main window, we need to go retrieve the appActions from the server! + return this.mainWindow().uiKeys; + }, + // windowMgr: function() + // return null; + // }, + contentFrameAndSection: function(app, rightFrameUrl) { + //this.appActions().shiftApp(app, this.uiKeys()['sections_' + app]); + var self = this; + self.mainWindow().UmbClientMgr.historyManager().addHistory(app, true); + window.setTimeout(function() { + self.mainWindow().UmbClientMgr.contentFrame(rightFrameUrl); + }, 200); + }, + + /** + * @ngdoc function + * @name contentFrame + * @methodOf UmbClientMgr + * @function + * + * @description + * This will tell our angular app to create and load in an iframe at the specified location + * @param strLocation {String} The URL to load the iframe in + */ + contentFrame: function (strLocation) { + + if (!strLocation || strLocation == "") { + //SD: NOTE: We used to return the content iframe object but now I'm not sure we should do that ?! + return null; + } + + this._debug("contentFrame: " + strLocation); + + //get our angular navigation service + var injector = getRootInjector(); + var navService = injector.get("navigationService"); + + //if the path doesn't start with "/" or with the root path then + //prepend the root path + if (!strLocation.startsWith("/")) { + strLocation = this._rootPath + "/" + strLocation; + } + else if (strLocation.length >= this._rootPath.length + && strLocation.substr(0, this._rootPath.length) != this._rootPath) { + strLocation = this._rootPath + "/" + strLocation; + } + + navService.loadLegacyIFrame(strLocation); + + //if (strLocation == null || strLocation == "") { + // if (typeof this.mainWindow().right != "undefined") { + // return this.mainWindow().right; + // } + // else { + // return this.mainWindow(); //return the current window if the content frame doesn't exist in the current context + // } + //} + //else { + // //if the path doesn't start with "/" or with the root path then + // //prepend the root path + // if (strLocation.substr(0, 1) != "/") { + // strLocation = this._rootPath + "/" + strLocation; + // } + // else if (strLocation.length >= this._rootPath.length + // && strLocation.substr(0, this._rootPath.length) != this._rootPath) { + // strLocation = this._rootPath + "/" + strLocation; + // } + + // this._debug("contentFrame: parsed location: " + strLocation); + // var self = this; + // window.setTimeout(function() { + // if (typeof self.mainWindow().right != "undefined") { + // self.mainWindow().right.location.href = strLocation; + // } + // else { + // self.mainWindow().location.href = strLocation; //set the current windows location if the right frame doesn't exist int he current context + // } + // }, 200); + //} + }, + openModalWindow: function(url, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback) { + //need to create the modal on the top window if the top window has a client manager, if not, create it on the current window + + //if this is the top window, or if the top window doesn't have a client manager, create the modal in this manager + if (window == this.mainWindow() || !this.mainWindow().UmbClientMgr) { + var m = new Umbraco.Controls.ModalWindow(); + this._modal.push(m); + m.open(url, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback); + } + else { + //if the main window has a client manager, then call the main window's open modal method whilst keeping the context of it's manager. + if (this.mainWindow().UmbClientMgr) { + this.mainWindow().UmbClientMgr.openModalWindow.apply(this.mainWindow().UmbClientMgr, + [url, name, showHeader, width, height, top, leftOffset, closeTriggers, onCloseCallback]); + } + else { + return; //exit recurse. + } + } + }, + closeModalWindow: function(rVal) { + /// + /// will close the latest open modal window. + /// if an rVal is passed in, then this will be sent to the onCloseCallback method if it was specified. + /// + if (this._modal != null && this._modal.length > 0) { + this._modal.pop().close(rVal); + } + else { + //this will recursively try to close a modal window until the parent window has a modal object or the window is the top and has the modal object + var mgr = null; + if (window.parent == null || window.parent == window) { + //we are at the root window, check if we can close the modal window from here + if (window.UmbClientMgr != null && window.UmbClientMgr._modal != null && window.UmbClientMgr._modal.length > 0) { + mgr = window.UmbClientMgr; + } + else { + return; //exit recursion. + } + } + else if (typeof window.parent.UmbClientMgr != "undefined") { + mgr = window.parent.UmbClientMgr; + } + mgr.closeModalWindow.call(mgr, rVal); + } + }, + _debug: function(strMsg) { + if (this._isDebug) { + Sys.Debug.trace("UmbClientMgr: " + strMsg); + } + }, + get_isDirty: function() { + return this._isDirty; + }, + set_isDirty: function(value) { + this._isDirty = value; + } + }; + }; +})(jQuery); + +//define alias for use throughout application +var UmbClientMgr = new Umbraco.Application.ClientManager(); diff --git a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js index e32304cd9b..282eb05ff7 100644 --- a/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js +++ b/src/Umbraco.Web.UI.Client/src/common/directives/umbtreeitem.directive.js @@ -1,5 +1,5 @@ angular.module("umbraco.directives") -.directive('umbTreeItem', function($compile, $http, $templateCache, $interpolate, $log, treeService) { +.directive('umbTreeItem', function($compile, $http, $templateCache, $interpolate, $log, $location, treeService) { return { restrict: 'E', replace: true, @@ -14,7 +14,7 @@ angular.module("umbraco.directives") '' + '' + '' + - '{{node.name}}' + + '{{node.name}}' + '' + ''+ '', @@ -25,8 +25,46 @@ angular.module("umbraco.directives") scope.$emit("treeOptionsClick", {element: e, node: n, event: ev}); }; + /** + * @ngdoc function + * @name select + * @methodOf umbraco.directives.umbTreeItem + * @function + * + * @description + * Handles the click event of a tree node + + * @param n {object} The tree node object associated with the click + */ scope.select = function(e,n,ev){ - scope.$emit("treeNodeSelect", {element: e, node: n, event: ev}); + + //here we need to check for some legacy tree code + if (n.jsClickCallback && n.jsClickCallback != "") { + //this is a legacy tree node! + var js; + if (n.jsClickCallback.startsWith("javascript:")) { + js = n.jsClickCallback.substr("javascript:".length); + } + else { + js = n.jsClickCallback; + } + try { + var func = eval(js); + //this is normally not necessary since the eval above should execute the method and will return nothing. + if (func != null && (typeof func === "function")) { + func.call(); + } + } + catch(e) { + $log.error("Error evaluating js callback from legacy tree node: " + e); + } + } + else { + //not legacy, lets just set the route value + $location.path(n.view); + } + + scope.$emit("treeNodeSelect", { element: e, node: n, event: ev }); }; scope.load = function (node) { diff --git a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js index 08fd919ccd..66bdfd76db 100644 --- a/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js +++ b/src/Umbraco.Web.UI.Client/src/common/services/navigation.service.js @@ -1,55 +1,55 @@ angular.module('umbraco.services') -.factory('navigationService', function ($rootScope, $routeParams, $log, dialogService, treeService) { +.factory('navigationService', function ($rootScope, $routeParams, $log, $location, dialogService, treeService) { - var _currentSection = $routeParams.section; - var _currentId = $routeParams.id; - var _currentNode; - var _ui = {}; + var currentSection = $routeParams.section; + var currentId = $routeParams.id; + var currentNode; + var ui = {}; - function _setMode(mode){ + function setMode(mode){ switch(mode) { case 'tree': - _ui.showNavigation = true; - _ui.showContextMenu = false; - _ui.showContextMenuDialog = false; - _ui.stickyNavigation = false; + ui.showNavigation = true; + ui.showContextMenu = false; + ui.showContextMenuDialog = false; + ui.stickyNavigation = false; $("#search-form input").focus(); break; case 'menu': - _ui.showNavigation = true; - _ui.showContextMenu = true; - _ui.showContextMenuDialog = false; - _ui.stickyNavigation = true; + ui.showNavigation = true; + ui.showContextMenu = true; + ui.showContextMenuDialog = false; + ui.stickyNavigation = true; break; case 'dialog': - _ui.stickyNavigation = true; - _ui.showNavigation = true; - _ui.showContextMenu = false; - _ui.showContextMenuDialog = true; + ui.stickyNavigation = true; + ui.showNavigation = true; + ui.showContextMenu = false; + ui.showContextMenuDialog = true; break; case 'search': - _ui.stickyNavigation = false; - _ui.showNavigation = true; - _ui.showContextMenu = false; - _ui.showSearchResults = true; - _ui.showContextMenuDialog = false; + ui.stickyNavigation = false; + ui.showNavigation = true; + ui.showContextMenu = false; + ui.showSearchResults = true; + ui.showContextMenuDialog = false; break; default: - _ui.showNavigation = false; - _ui.showContextMenu = false; - _ui.showContextMenuDialog = false; - _ui.showSearchResults = false; - _ui.stickyNavigation = false; + ui.showNavigation = false; + ui.showContextMenu = false; + ui.showContextMenuDialog = false; + ui.showSearchResults = false; + ui.stickyNavigation = false; break; } } return { - currentNode: _currentNode, + currentNode: currentNode, mode: "default", - ui: _ui, + ui: ui, sections: function(){ return [ @@ -61,9 +61,23 @@ angular.module('umbraco.services') ]; }, + /** + * @ngdoc function + * @name loadLegacyIFrame + * @methodOf navigationService + * @function + * + * @description + * Shows the legacy iframe and loads in the content based on the source url + * @param source {String} The URL to load into the iframe + */ + loadLegacyIFrame: function (source) { + $location.path("/framed/" + encodeURIComponent(source)); + }, + changeSection: function(sectionAlias){ if(this.ui.stickyNavigation){ - _setMode("default-opensection"); + setMode("default-opensection"); this.ui.currentSection = selectedSection; this.showTree(selectedSection); } @@ -73,7 +87,7 @@ angular.module('umbraco.services') if(!this.ui.stickyNavigation && sectionAlias !== this.ui.currentTree){ $log.log("show tree" + sectionAlias); this.ui.currentTree = sectionAlias; - _setMode("tree"); + setMode("tree"); } }, @@ -81,7 +95,7 @@ angular.module('umbraco.services') if(!this.ui.stickyNavigation){ $log.log("hide tree"); this.ui.currentTree = ""; - _setMode("default-hidesectiontree"); + setMode("default-hidesectiontree"); } }, @@ -101,9 +115,10 @@ angular.module('umbraco.services') action: act, section: this.ui.currentTree }); - }else{ - _setMode("menu"); - _ui.actions = treeService.getActions({node: args.node, section: this.ui.currentTree}); + } + else { + setMode("menu"); + ui.actions = treeService.getActions({node: args.node, section: this.ui.currentTree}); this.ui.currentNode = args.node; @@ -112,17 +127,17 @@ angular.module('umbraco.services') }, hideMenu: function () { - _selectedId = $routeParams.id; + var selectedId = $routeParams.id; this.ui.currentNode = undefined; this.ui.actions = []; - _setMode("tree"); + setMode("tree"); }, showDialog: function (args) { - _setMode("dialog"); + setMode("dialog"); - var _scope = args.scope || $rootScope.$new(); - _scope.currentNode = args.node; + var scope = args.scope || $rootScope.$new(); + scope.currentNode = args.node; //this.currentNode = item; this.ui.dialogTitle = args.action.name; @@ -131,7 +146,7 @@ angular.module('umbraco.services') var d = dialogService.append( { container: $("#dialog div.umb-panel-body"), - scope: _scope, + scope: scope, template: templateUrl }); }, @@ -142,11 +157,11 @@ angular.module('umbraco.services') }, showSearch: function() { - _setMode("search"); + setMode("search"); }, hideSearch: function() { - _setMode("default-hidesearch"); + setMode("default-hidesearch"); }, hideNavigation: function(){ @@ -154,7 +169,7 @@ angular.module('umbraco.services') this.ui.actions = []; this.ui.currentNode = undefined; - _setMode("default"); + setMode("default"); } }; diff --git a/src/Umbraco.Web.UI.Client/src/less/tree.less b/src/Umbraco.Web.UI.Client/src/less/tree.less index b502499ec8..65099406ac 100644 --- a/src/Umbraco.Web.UI.Client/src/less/tree.less +++ b/src/Umbraco.Web.UI.Client/src/less/tree.less @@ -43,6 +43,7 @@ .umb-tree a { vertical-align: middle; display: inline-block; + cursor:pointer; } .umb-tree a:hover { diff --git a/src/Umbraco.Web.UI.Client/src/routes.js b/src/Umbraco.Web.UI.Client/src/routes.js index 92ff159370..8b6d809ba4 100644 --- a/src/Umbraco.Web.UI.Client/src/routes.js +++ b/src/Umbraco.Web.UI.Client/src/routes.js @@ -3,6 +3,15 @@ app.config(function ($routeProvider) { .when('/:section', { templateUrl: "views/common/dashboard.html" }) + .when('/framed/:url', { + //This occurs when we need to launch some content in an iframe + templateUrl: function (rp) { + if (!rp.url) + throw "A framed resource must have a url route parameter"; + + return 'views/common/legacy.html'; + } + }) .when('/:section/:method', { templateUrl: function(rp) { if (!rp.method) @@ -12,13 +21,13 @@ app.config(function ($routeProvider) { } }) .when('/:section/:method/:id', { - templateUrl: function(rp) { - if (!rp.method) + templateUrl: function (rp) { + if (!rp.method) return "views/common/dashboard.html"; - + return 'views/' + rp.section + '/' + rp.method + '.html'; } - }) + }) .otherwise({ redirectTo: '/content' }); }).config(function ($locationProvider) { //$locationProvider.html5Mode(false).hashPrefix('!'); //turn html5 mode off diff --git a/src/Umbraco.Web.UI.Client/src/views/common/legacy.controller.js b/src/Umbraco.Web.UI.Client/src/views/common/legacy.controller.js index de1ef5afef..a5da3970b6 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/legacy.controller.js +++ b/src/Umbraco.Web.UI.Client/src/views/common/legacy.controller.js @@ -1,4 +1,19 @@ -angular.module("umbraco").controller("Umbraco.Common.LegacyController", - function($scope, $routeParams){ - $scope.legacyPath = decodeURI($routeParams.p); - }); \ No newline at end of file +/** + * @ngdoc controller + * @name LegacyController + * @function + * + * @description + * A controller to control the legacy iframe injection + * + * @param myParam {object} Enter param description here +*/ +function LegacyController($scope, $routeParams, $element) { + //set the legacy path + $scope.legacyPath = decodeURIComponent($routeParams.url); + + //$scope.$on('$routeChangeSuccess', function () { + // var asdf = $element; + //}); +} +angular.module("umbraco").controller('LegacyController', LegacyController); \ No newline at end of file diff --git a/src/Umbraco.Web.UI.Client/src/views/common/legacy.html b/src/Umbraco.Web.UI.Client/src/views/common/legacy.html index 8e61774783..10ac1a378b 100644 --- a/src/Umbraco.Web.UI.Client/src/views/common/legacy.html +++ b/src/Umbraco.Web.UI.Client/src/views/common/legacy.html @@ -1 +1,3 @@ - \ No newline at end of file +
+ +
\ No newline at end of file diff --git a/src/Umbraco.Web.UI/config/ClientDependency.config b/src/Umbraco.Web.UI/config/ClientDependency.config index 6c1ff881cf..87bd6c9da4 100644 --- a/src/Umbraco.Web.UI/config/ClientDependency.config +++ b/src/Umbraco.Web.UI/config/ClientDependency.config @@ -10,7 +10,7 @@ NOTES: * Compression/Combination/Minification is not enabled unless debug="false" is specified on the 'compiliation' element in the web.config * A new version will invalidate both client and server cache and create new persisted files --> - +