Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*! umbraco
- * https://github.com/umbraco/umbraco-cms/
- * Copyright (c) 2015 Umbraco HQ;
- * Licensed MIT
- */
- (function() {
- /**
- * @ngdoc controller
- * @name Umbraco.MainController
- * @function
- *
- * @description
- * The main application controller
- *
- */
- function MainController($scope, $rootScope, $location, $routeParams, $timeout, $http, $log, appState, treeService, notificationsService, userService, navigationService, historyService, updateChecker, assetsService, eventsService, umbRequestHelper, tmhDynamicLocale) {
- //the null is important because we do an explicit bool check on this in the view
- //the avatar is by default the umbraco logo
- $scope.authenticated = null;
- $scope.avatar = "assets/img/application/logo.png";
- $scope.touchDevice = appState.getGlobalState("touchDevice");
- //subscribes to notifications in the notification service
- $scope.notifications = notificationsService.current;
- $scope.$watch('notificationsService.current', function (newVal, oldVal, scope) {
- if (newVal) {
- $scope.notifications = newVal;
- }
- });
- $scope.removeNotification = function (index) {
- notificationsService.remove(index);
- };
- $scope.closeDialogs = function (event) {
- //only close dialogs if non-link and non-buttons are clicked
- var el = event.target.nodeName;
- var els = ["INPUT","A","BUTTON"];
- if(els.indexOf(el) >= 0){return;}
- var parents = $(event.target).parents("a,button");
- if(parents.length > 0){
- return;
- }
- //SD: I've updated this so that we don't close the dialog when clicking inside of the dialog
- var nav = $(event.target).parents("#dialog");
- if (nav.length === 1) {
- return;
- }
- eventsService.emit("app.closeDialogs", event);
- };
- var evts = [];
- //when a user logs out or timesout
- evts.push(eventsService.on("app.notAuthenticated", function() {
- $scope.authenticated = null;
- $scope.user = null;
- }));
- //when the app is read/user is logged in, setup the data
- evts.push(eventsService.on("app.ready", function (evt, data) {
- $scope.authenticated = data.authenticated;
- $scope.user = data.user;
- updateChecker.check().then(function(update){
- if(update && update !== "null"){
- if(update.type !== "None"){
- var notification = {
- headline: "Update available",
- message: "Click to download",
- sticky: true,
- type: "info",
- url: update.url
- };
- notificationsService.add(notification);
- }
- }
- })
- //if the user has changed we need to redirect to the root so they don't try to continue editing the
- //last item in the URL (NOTE: the user id can equal zero, so we cannot just do !data.lastUserId since that will resolve to true)
- if (data.lastUserId !== undefined && data.lastUserId !== null && data.lastUserId !== data.user.id) {
- $location.path("/").search("");
- historyService.removeAll();
- treeService.clearCache();
- }
- //Load locale file
- if ($scope.user.locale) {
- tmhDynamicLocale.set($scope.user.locale);
- }
- if($scope.user.emailHash){
- $timeout(function () {
- //yes this is wrong..
- $("#avatar-img").fadeTo(1000, 0, function () {
- $timeout(function () {
- //this can be null if they time out
- if ($scope.user && $scope.user.emailHash) {
- $scope.avatar = "//www.gravatar.com/avatar/" + $scope.user.emailHash + ".jpg?s=64&d=mm";
- }
- });
- $("#avatar-img").fadeTo(1000, 1);
- });
- }, 3000);
- }
- }));
- //ensure to unregister from all events!
- $scope.$on('$destroy', function () {
- for (var e in evts) {
- eventsService.unsubscribe(evts[e]);
- }
- });
- }
- //register it
- angular.module('umbraco').controller("Umbraco.MainController", MainController).
- config(function (tmhDynamicLocaleProvider) {
- //Set url for locale files
- tmhDynamicLocaleProvider.localeLocationPattern('lib/angular/1.1.5/i18n/angular-locale_{{locale}}.js');
- });
- /**
- * @ngdoc controller
- * @name Umbraco.NavigationController
- * @function
- *
- * @description
- * Handles the section area of the app
- *
- * @param {navigationService} navigationService A reference to the navigationService
- */
- function NavigationController($scope, $rootScope, $location, $log, $routeParams, $timeout, appState, navigationService, keyboardService, dialogService, historyService, eventsService, sectionResource, angularHelper) {
- //TODO: Need to think about this and an nicer way to acheive what this is doing.
- //the tree event handler i used to subscribe to the main tree click events
- $scope.treeEventHandler = $({});
- navigationService.setupTreeEvents($scope.treeEventHandler);
- //Put the navigation service on this scope so we can use it's methods/properties in the view.
- // IMPORTANT: all properties assigned to this scope are generally available on the scope object on dialogs since
- // when we create a dialog we pass in this scope to be used for the dialog's scope instead of creating a new one.
- $scope.nav = navigationService;
- // TODO: Lets fix this, it is less than ideal to be passing in the navigationController scope to something else to be used as it's scope,
- // this is going to lead to problems/confusion. I really don't think passing scope's around is very good practice.
- $rootScope.nav = navigationService;
- //set up our scope vars
- $scope.showContextMenuDialog = false;
- $scope.showContextMenu = false;
- $scope.showSearchResults = false;
- $scope.menuDialogTitle = null;
- $scope.menuActions = [];
- $scope.menuNode = null;
- $scope.currentSection = appState.getSectionState("currentSection");
- $scope.showNavigation = appState.getGlobalState("showNavigation");
- //trigger search with a hotkey:
- keyboardService.bind("ctrl+shift+s", function () {
- navigationService.showSearch();
- });
- //trigger dialods with a hotkey:
- keyboardService.bind("esc", function () {
- eventsService.emit("app.closeDialogs");
- });
- $scope.selectedId = navigationService.currentId;
- var evts = [];
- //Listen for global state changes
- evts.push(eventsService.on("appState.globalState.changed", function(e, args) {
- if (args.key === "showNavigation") {
- $scope.showNavigation = args.value;
- }
- }));
- //Listen for menu state changes
- evts.push(eventsService.on("appState.menuState.changed", function(e, args) {
- if (args.key === "showMenuDialog") {
- $scope.showContextMenuDialog = args.value;
- }
- if (args.key === "showMenu") {
- $scope.showContextMenu = args.value;
- }
- if (args.key === "dialogTitle") {
- $scope.menuDialogTitle = args.value;
- }
- if (args.key === "menuActions") {
- $scope.menuActions = args.value;
- }
- if (args.key === "currentNode") {
- $scope.menuNode = args.value;
- }
- }));
- //Listen for section state changes
- evts.push(eventsService.on("appState.treeState.changed", function(e, args) {
- var f = args;
- if (args.value.root && args.value.root.metaData.containsTrees === false) {
- $rootScope.emptySection = true;
- }
- else {
- $rootScope.emptySection = false;
- }
- }));
- //Listen for section state changes
- evts.push(eventsService.on("appState.sectionState.changed", function(e, args) {
- //section changed
- if (args.key === "currentSection") {
- $scope.currentSection = args.value;
- }
- //show/hide search results
- if (args.key === "showSearchResults") {
- $scope.showSearchResults = args.value;
- }
- }));
- //This reacts to clicks passed to the body element which emits a global call to close all dialogs
- evts.push(eventsService.on("app.closeDialogs", function(event) {
- if (appState.getGlobalState("stickyNavigation")) {
- navigationService.hideNavigation();
- //TODO: don't know why we need this? - we are inside of an angular event listener.
- angularHelper.safeApply($scope);
- }
- }));
- //when a user logs out or timesout
- evts.push(eventsService.on("app.notAuthenticated", function() {
- $scope.authenticated = false;
- }));
- //when the application is ready and the user is authorized setup the data
- evts.push(eventsService.on("app.ready", function(evt, data) {
- $scope.authenticated = true;
- }));
- //this reacts to the options item in the tree
- //todo, migrate to nav service
- $scope.searchShowMenu = function (ev, args) {
- //always skip default
- args.skipDefault = true;
- navigationService.showMenu(ev, args);
- };
- //todo, migrate to nav service
- $scope.searchHide = function () {
- navigationService.hideSearch();
- };
- //the below assists with hiding/showing the tree
- var treeActive = false;
- //Sets a service variable as soon as the user hovers the navigation with the mouse
- //used by the leaveTree method to delay hiding
- $scope.enterTree = function (event) {
- treeActive = true;
- };
- // Hides navigation tree, with a short delay, is cancelled if the user moves the mouse over the tree again
- $scope.leaveTree = function(event) {
- //this is a hack to handle IE touch events which freaks out due to no mouse events so the tree instantly shuts down
- if (!event) {
- return;
- }
- if (!appState.getGlobalState("touchDevice")) {
- treeActive = false;
- $timeout(function() {
- if (!treeActive) {
- navigationService.hideTree();
- }
- }, 300);
- }
- };
- //ensure to unregister from all events!
- $scope.$on('$destroy', function () {
- for (var e in evts) {
- eventsService.unsubscribe(evts[e]);
- }
- });
- }
- //register it
- angular.module('umbraco').controller("Umbraco.NavigationController", NavigationController);
- /**
- * @ngdoc controller
- * @name Umbraco.SearchController
- * @function
- *
- * @description
- * Controls the search functionality in the site
- *
- */
- function SearchController($scope, searchService, $log, $location, navigationService, $q) {
- $scope.searchTerm = null;
- $scope.searchResults = [];
- $scope.isSearching = false;
- $scope.selectedResult = -1;
- $scope.navigateResults = function(ev){
- //38: up 40: down, 13: enter
- switch(ev.keyCode){
- case 38:
- iterateResults(true);
- break;
- case 40:
- iterateResults(false);
- break;
- case 13:
- if ($scope.selectedItem) {
- $location.path($scope.selectedItem.editorPath);
- navigationService.hideSearch();
- }
- break;
- }
- };
- var group = undefined;
- var groupIndex = -1;
- var itemIndex = -1;
- $scope.selectedItem = undefined;
- function iterateResults(up){
- //default group
- if(!group){
- group = $scope.groups[0];
- groupIndex = 0;
- }
- if(up){
- if(itemIndex === 0){
- if(groupIndex === 0){
- gotoGroup($scope.groups.length-1, true);
- }else{
- gotoGroup(groupIndex-1, true);
- }
- }else{
- gotoItem(itemIndex-1);
- }
- }else{
- if(itemIndex < group.results.length-1){
- gotoItem(itemIndex+1);
- }else{
- if(groupIndex === $scope.groups.length-1){
- gotoGroup(0);
- }else{
- gotoGroup(groupIndex+1);
- }
- }
- }
- }
- function gotoGroup(index, up){
- groupIndex = index;
- group = $scope.groups[groupIndex];
- if(up){
- gotoItem(group.results.length-1);
- }else{
- gotoItem(0);
- }
- }
- function gotoItem(index){
- itemIndex = index;
- $scope.selectedItem = group.results[itemIndex];
- }
- //used to cancel any request in progress if another one needs to take it's place
- var canceler = null;
- $scope.$watch("searchTerm", _.debounce(function (newVal, oldVal) {
- $scope.$apply(function() {
- if ($scope.searchTerm) {
- if (newVal !== null && newVal !== undefined && newVal !== oldVal) {
- $scope.isSearching = true;
- navigationService.showSearch();
- $scope.selectedItem = undefined;
- //a canceler exists, so perform the cancelation operation and reset
- if (canceler) {
- console.log("CANCELED!");
- canceler.resolve();
- canceler = $q.defer();
- }
- else {
- canceler = $q.defer();
- }
- searchService.searchAll({ term: $scope.searchTerm, canceler: canceler }).then(function(result) {
- $scope.groups = _.filter(result, function (group) { return group.results.length > 0; });
- //set back to null so it can be re-created
- canceler = null;
- });
- }
- }
- else {
- $scope.isSearching = false;
- navigationService.hideSearch();
- $scope.selectedItem = undefined;
- }
- });
- }, 200));
- }
- //register it
- angular.module('umbraco').controller("Umbraco.SearchController", SearchController);
- /**
- * @ngdoc controller
- * @name Umbraco.MainController
- * @function
- *
- * @description
- * The controller for the AuthorizeUpgrade login page
- *
- */
- function AuthorizeUpgradeController($scope, $window) {
- //Add this method to the scope - this method will be called by the login dialog controller when the login is successful
- // then we'll handle the redirect.
- $scope.submit = function (event) {
- var qry = $window.location.search.trimStart("?").split("&");
- var redir = _.find(qry, function(item) {
- return item.startsWith("redir=");
- });
- if (redir) {
- $window.location = decodeURIComponent(redir.split("=")[1]);
- }
- else {
- $window.location = "/";
- }
- };
- }
- angular.module('umbraco').controller("Umbraco.AuthorizeUpgradeController", AuthorizeUpgradeController);
- /**
- * @ngdoc controller
- * @name Umbraco.DashboardController
- * @function
- *
- * @description
- * Controls the dashboards of the application
- *
- */
- function DashboardController($scope, $routeParams, dashboardResource, localizationService) {
- $scope.dashboard = {};
- localizationService.localize("sections_" + $routeParams.section).then(function(name){
- $scope.dashboard.name = name;
- });
- dashboardResource.getDashboard($routeParams.section).then(function(tabs){
- $scope.dashboard.tabs = tabs;
- });
- }
- //register it
- angular.module('umbraco').controller("Umbraco.DashboardController", DashboardController);
- angular.module("umbraco")
- .controller("Umbraco.Dialogs.ApprovedColorPickerController", function ($scope, $http, umbPropEditorHelper, assetsService) {
- assetsService.loadJs("lib/cssparser/cssparser.js")
- .then(function () {
- var cssPath = $scope.dialogData.cssPath;
- $scope.cssClass = $scope.dialogData.cssClass;
- $scope.classes = [];
- $scope.change = function (newClass) {
- $scope.model.value = newClass;
- }
- $http.get(cssPath)
- .success(function (data) {
- var parser = new CSSParser();
- $scope.classes = parser.parse(data, false, false).cssRules;
- $scope.classes.splice(0, 0, "noclass");
- })
- assetsService.loadCss("/App_Plugins/Lecoati.uSky.Grid/lib/uSky.Grid.ApprovedColorPicker.css");
- assetsService.loadCss(cssPath);
- });
- });
- function ContentEditDialogController($scope, editorState, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, umbModelMapper, $http) {
- $scope.defaultButton = null;
- $scope.subButtons = [];
- var dialogOptions = $scope.$parent.dialogOptions;
- // This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish
- function performSave(args) {
- contentEditingHelper.contentEditorPerformSave({
- statusMessage: args.statusMessage,
- saveMethod: args.saveMethod,
- scope: $scope,
- content: $scope.content
- }).then(function (content) {
- //success
- if (dialogOptions.closeOnSave) {
- $scope.submit(content);
- }
- }, function(err) {
- //error
- });
- }
- function filterTabs(entity, blackList) {
- if (blackList) {
- _.each(entity.tabs, function (tab) {
- tab.hide = _.contains(blackList, tab.alias);
- });
- }
- return entity;
- };
- function init(content) {
- var buttons = contentEditingHelper.configureContentEditorButtons({
- create: $routeParams.create,
- content: content,
- methods: {
- saveAndPublish: $scope.saveAndPublish,
- sendToPublish: $scope.sendToPublish,
- save: $scope.save,
- unPublish: angular.noop
- }
- });
- $scope.defaultButton = buttons.defaultButton;
- $scope.subButtons = buttons.subButtons;
- //This is a total hack but we have really no other way of sharing data to the property editors of this
- // content item, so we'll just set the property on the content item directly
- $scope.content.isDialogEditor = true;
- editorState.set($scope.content);
- }
- //check if the entity is being passed in, otherwise load it from the server
- if (angular.isObject(dialogOptions.entity)) {
- $scope.loaded = true;
- $scope.content = filterTabs(dialogOptions.entity, dialogOptions.tabFilter);
- init($scope.content);
- }
- else {
- contentResource.getById(dialogOptions.id)
- .then(function(data) {
- $scope.loaded = true;
- $scope.content = filterTabs(data, dialogOptions.tabFilter);
- init($scope.content);
- //in one particular special case, after we've created a new item we redirect back to the edit
- // route but there might be server validation errors in the collection which we need to display
- // after the redirect, so we will bind all subscriptions which will show the server validation errors
- // if there are any and then clear them so the collection no longer persists them.
- serverValidationManager.executeAndClearAllSubscriptions();
- });
- }
- $scope.sendToPublish = function () {
- performSave({ saveMethod: contentResource.sendToPublish, statusMessage: "Sending..." });
- };
- $scope.saveAndPublish = function () {
- performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." });
- };
- $scope.save = function () {
- performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." });
- };
- // this method is called for all action buttons and then we proxy based on the btn definition
- $scope.performAction = function (btn) {
- if (!btn || !angular.isFunction(btn.handler)) {
- throw "btn.handler must be a function reference";
- }
- if (!$scope.busy) {
- btn.handler.apply(this);
- }
- };
- }
- angular.module("umbraco")
- .controller("Umbraco.Dialogs.Content.EditController", ContentEditDialogController);
- angular.module("umbraco")
- .controller("Umbraco.Dialogs.HelpController", function ($scope, $location, $routeParams, helpService, userService) {
- $scope.section = $routeParams.section;
- $scope.version = Umbraco.Sys.ServerVariables.application.version + " assembly: " + Umbraco.Sys.ServerVariables.application.assemblyVersion;
- if(!$scope.section){
- $scope.section ="content";
- }
- var rq = {};
- rq.section = $scope.section;
- userService.getCurrentUser().then(function(user){
- rq.usertype = user.userType;
- rq.lang = user.locale;
- if($routeParams.url){
- rq.path = decodeURIComponent($routeParams.url);
- if(rq.path.indexOf(Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath) === 0){
- rq.path = rq.path.substring(Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath.length);
- }
- if(rq.path.indexOf(".aspx") > 0){
- rq.path = rq.path.substring(0, rq.path.indexOf(".aspx"));
- }
- }else{
- rq.path = rq.section + "/" + $routeParams.tree + "/" + $routeParams.method;
- }
- helpService.findHelp(rq).then(function(topics){
- $scope.topics = topics;
- });
- helpService.findVideos(rq).then(function(videos){
- $scope.videos = videos;
- });
- });
- });
- //used for the icon picker dialog
- angular.module("umbraco")
- .controller("Umbraco.Dialogs.IconPickerController",
- function ($scope, iconHelper) {
- iconHelper.getIcons().then(function(icons){
- $scope.icons = icons;
- });
- $scope.submitClass = function(icon){
- if($scope.color)
- {
- $scope.submit(icon + " " + $scope.color);
- }else{
- $scope.submit(icon);
- }
- };
- }
- );
- /**
- * @ngdoc controller
- * @name Umbraco.Dialogs.InsertMacroController
- * @function
- *
- * @description
- * The controller for the custom insert macro dialog. Until we upgrade the template editor to be angular this
- * is actually loaded into an iframe with full html.
- */
- function InsertMacroController($scope, entityResource, macroResource, umbPropEditorHelper, macroService, formHelper) {
- /** changes the view to edit the params of the selected macro */
- function editParams() {
- //get the macro params if there are any
- macroResource.getMacroParameters($scope.selectedMacro.id)
- .then(function (data) {
- //go to next page if there are params otherwise we can just exit
- if (!angular.isArray(data) || data.length === 0) {
- //we can just exist!
- submitForm();
- } else {
- $scope.wizardStep = "paramSelect";
- $scope.macroParams = data;
- //fill in the data if we are editing this macro
- if ($scope.dialogData && $scope.dialogData.macroData && $scope.dialogData.macroData.macroParamsDictionary) {
- _.each($scope.dialogData.macroData.macroParamsDictionary, function (val, key) {
- var prop = _.find($scope.macroParams, function (item) {
- return item.alias == key;
- });
- if (prop) {
- if (_.isString(val)) {
- //we need to unescape values as they have most likely been escaped while inserted
- val = _.unescape(val);
- //detect if it is a json string
- if (val.detectIsJson()) {
- try {
- //Parse it to json
- prop.value = angular.fromJson(val);
- }
- catch (e) {
- // not json
- prop.value = val;
- }
- }
- else {
- prop.value = val;
- }
- }
- else {
- prop.value = val;
- }
- }
- });
- }
- }
- });
- }
- /** submit the filled out macro params */
- function submitForm() {
- //collect the value data, close the dialog and send the data back to the caller
- //create a dictionary for the macro params
- var paramDictionary = {};
- _.each($scope.macroParams, function (item) {
- var val = item.value;
- if (item.value != null && item.value != undefined && !_.isString(item.value)) {
- try {
- val = angular.toJson(val);
- }
- catch (e) {
- // not json
- }
- }
- //each value needs to be xml escaped!! since the value get's stored as an xml attribute
- paramDictionary[item.alias] = _.escape(val);
- });
- //need to find the macro alias for the selected id
- var macroAlias = $scope.selectedMacro.alias;
- //get the syntax based on the rendering engine
- var syntax;
- if ($scope.dialogData.renderingEngine && $scope.dialogData.renderingEngine === "WebForms") {
- syntax = macroService.generateWebFormsSyntax({ macroAlias: macroAlias, macroParamsDictionary: paramDictionary });
- }
- else if ($scope.dialogData.renderingEngine && $scope.dialogData.renderingEngine === "Mvc") {
- syntax = macroService.generateMvcSyntax({ macroAlias: macroAlias, macroParamsDictionary: paramDictionary });
- }
- else {
- syntax = macroService.generateMacroSyntax({ macroAlias: macroAlias, macroParamsDictionary: paramDictionary });
- }
- $scope.submit({ syntax: syntax, macroAlias: macroAlias, macroParamsDictionary: paramDictionary });
- }
- $scope.macros = [];
- $scope.selectedMacro = null;
- $scope.wizardStep = "macroSelect";
- $scope.macroParams = [];
- $scope.submitForm = function () {
- if (formHelper.submitForm({ scope: $scope })) {
- formHelper.resetForm({ scope: $scope });
- if ($scope.wizardStep === "macroSelect") {
- editParams();
- }
- else {
- submitForm();
- }
- }
- };
- //here we check to see if we've been passed a selected macro and if so we'll set the
- //editor to start with parameter editing
- if ($scope.dialogData && $scope.dialogData.macroData) {
- $scope.wizardStep = "paramSelect";
- }
- //get the macro list - pass in a filter if it is only for rte
- entityResource.getAll("Macro", ($scope.dialogData && $scope.dialogData.richTextEditor && $scope.dialogData.richTextEditor === true) ? "UseInEditor=true" : null)
- .then(function (data) {
- //if 'allowedMacros' is specified, we need to filter
- if (angular.isArray($scope.dialogData.allowedMacros) && $scope.dialogData.allowedMacros.length > 0) {
- $scope.macros = _.filter(data, function(d) {
- return _.contains($scope.dialogData.allowedMacros, d.alias);
- });
- }
- else {
- $scope.macros = data;
- }
- //check if there's a pre-selected macro and if it exists
- if ($scope.dialogData && $scope.dialogData.macroData && $scope.dialogData.macroData.macroAlias) {
- var found = _.find(data, function (item) {
- return item.alias === $scope.dialogData.macroData.macroAlias;
- });
- if (found) {
- //select the macro and go to next screen
- $scope.selectedMacro = found;
- editParams();
- return;
- }
- }
- //we don't have a pre-selected macro so ensure the correct step is set
- $scope.wizardStep = "macroSelect";
- });
- }
- angular.module("umbraco").controller("Umbraco.Dialogs.InsertMacroController", InsertMacroController);
- /**
- * @ngdoc controller
- * @name Umbraco.Dialogs.LegacyDeleteController
- * @function
- *
- * @description
- * The controller for deleting content
- */
- function LegacyDeleteController($scope, legacyResource, treeService, navigationService) {
- $scope.performDelete = function() {
- //mark it for deletion (used in the UI)
- $scope.currentNode.loading = true;
- legacyResource.deleteItem({
- nodeId: $scope.currentNode.id,
- nodeType: $scope.currentNode.nodeType,
- alias: $scope.currentNode.name,
- }).then(function () {
- $scope.currentNode.loading = false;
- //TODO: Need to sync tree, etc...
- treeService.removeNode($scope.currentNode);
- navigationService.hideMenu();
- });
- };
- $scope.cancel = function() {
- navigationService.hideDialog();
- };
- }
- angular.module("umbraco").controller("Umbraco.Dialogs.LegacyDeleteController", LegacyDeleteController);
- //used for the media picker dialog
- angular.module("umbraco").controller("Umbraco.Dialogs.LinkPickerController",
- function ($scope, eventsService, dialogService, entityResource, contentResource, mediaHelper, userService, localizationService) {
- var dialogOptions = $scope.dialogOptions;
- var searchText = "Search...";
- localizationService.localize("general_search").then(function (value) {
- searchText = value + "...";
- });
- $scope.dialogTreeEventHandler = $({});
- $scope.target = {};
- $scope.searchInfo = {
- searchFromId: null,
- searchFromName: null,
- showSearch: false,
- results: [],
- selectedSearchResults: []
- }
- if (dialogOptions.currentTarget) {
- $scope.target = dialogOptions.currentTarget;
- //if we have a node ID, we fetch the current node to build the form data
- if ($scope.target.id) {
- if (!$scope.target.path) {
- entityResource.getPath($scope.target.id, "Document").then(function (path) {
- $scope.target.path = path;
- //now sync the tree to this path
- $scope.dialogTreeEventHandler.syncTree({ path: $scope.target.path, tree: "content" });
- });
- }
- contentResource.getNiceUrl($scope.target.id).then(function (url) {
- $scope.target.url = url;
- });
- }
- }
- function nodeSelectHandler(ev, args) {
- args.event.preventDefault();
- args.event.stopPropagation();
- if (args.node.metaData.listViewNode) {
- //check if list view 'search' node was selected
- $scope.searchInfo.showSearch = true;
- $scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id;
- $scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name;
- }
- else {
- eventsService.emit("dialogs.linkPicker.select", args);
- if ($scope.currentNode) {
- //un-select if there's a current one selected
- $scope.currentNode.selected = false;
- }
- $scope.currentNode = args.node;
- $scope.currentNode.selected = true;
- $scope.target.id = args.node.id;
- $scope.target.name = args.node.name;
- if (args.node.id < 0) {
- $scope.target.url = "/";
- }
- else {
- contentResource.getNiceUrl(args.node.id).then(function (url) {
- $scope.target.url = url;
- });
- }
- if (!angular.isUndefined($scope.target.isMedia)) {
- delete $scope.target.isMedia;
- }
- }
- }
- function nodeExpandedHandler(ev, args) {
- if (angular.isArray(args.children)) {
- //iterate children
- _.each(args.children, function (child) {
- //check if any of the items are list views, if so we need to add a custom
- // child: A node to activate the search
- if (child.metaData.isContainer) {
- child.hasChildren = true;
- child.children = [
- {
- level: child.level + 1,
- hasChildren: false,
- name: searchText,
- metaData: {
- listViewNode: child,
- },
- cssClass: "icon umb-tree-icon sprTree icon-search",
- cssClasses: ["not-published"]
- }
- ];
- }
- });
- }
- }
- $scope.switchToMediaPicker = function () {
- userService.getCurrentUser().then(function (userData) {
- dialogService.mediaPicker({
- startNodeId: userData.startMediaId,
- callback: function (media) {
- $scope.target.id = media.id;
- $scope.target.isMedia = true;
- $scope.target.name = media.name;
- $scope.target.url = mediaHelper.resolveFile(media);
- }
- });
- });
- };
- $scope.hideSearch = function () {
- $scope.searchInfo.showSearch = false;
- $scope.searchInfo.searchFromId = null;
- $scope.searchInfo.searchFromName = null;
- $scope.searchInfo.results = [];
- }
- // method to select a search result
- $scope.selectResult = function (evt, result) {
- result.selected = result.selected === true ? false : true;
- nodeSelectHandler(evt, {event: evt, node: result});
- };
- //callback when there are search results
- $scope.onSearchResults = function (results) {
- $scope.searchInfo.results = results;
- $scope.searchInfo.showSearch = true;
- };
- $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
- $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
- $scope.$on('$destroy', function () {
- $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
- $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
- });
- });
- angular.module("umbraco").controller("Umbraco.Dialogs.LoginController", function ($scope, localizationService, userService) {
- /**
- * @ngdoc function
- * @name signin
- * @methodOf MainController
- * @function
- *
- * @description
- * signs the user in
- */
- var d = new Date();
- //var weekday = new Array("Super Sunday", "Manic Monday", "Tremendous Tuesday", "Wonderful Wednesday", "Thunder Thursday", "Friendly Friday", "Shiny Saturday");
- localizationService.localize("login_greeting"+d.getDay()).then(function(label){
- $scope.greeting = label;
- }); // weekday[d.getDay()];
- $scope.errorMsg = "";
- $scope.loginSubmit = function (login, password) {
- //if the login and password are not empty we need to automatically
- // validate them - this is because if there are validation errors on the server
- // then the user has to change both username & password to resubmit which isn't ideal,
- // so if they're not empty , we'l just make sure to set them to valid.
- if (login && password && login.length > 0 && password.length > 0) {
- $scope.loginForm.username.$setValidity('auth', true);
- $scope.loginForm.password.$setValidity('auth', true);
- }
- if ($scope.loginForm.$invalid) {
- return;
- }
- userService.authenticate(login, password)
- .then(function (data) {
- $scope.submit(true);
- }, function (reason) {
- $scope.errorMsg = reason.errorMsg;
- //set the form inputs to invalid
- $scope.loginForm.username.$setValidity("auth", false);
- $scope.loginForm.password.$setValidity("auth", false);
- });
- //setup a watch for both of the model values changing, if they change
- // while the form is invalid, then revalidate them so that the form can
- // be submitted again.
- $scope.loginForm.username.$viewChangeListeners.push(function () {
- if ($scope.loginForm.username.$invalid) {
- $scope.loginForm.username.$setValidity('auth', true);
- }
- });
- $scope.loginForm.password.$viewChangeListeners.push(function () {
- if ($scope.loginForm.password.$invalid) {
- $scope.loginForm.password.$setValidity('auth', true);
- }
- });
- };
- });
- //used for the macro picker dialog
- angular.module("umbraco").controller("Umbraco.Dialogs.MacroPickerController", function ($scope, macroFactory, umbPropEditorHelper) {
- $scope.macros = macroFactory.all(true);
- $scope.dialogMode = "list";
- $scope.configureMacro = function(macro){
- $scope.dialogMode = "configure";
- $scope.dialogData.macro = macroFactory.getMacro(macro.alias);
- //set the correct view for each item
- for (var i = 0; i < dialogData.macro.properties.length; i++) {
- dialogData.macro.properties[i].editorView = umbPropEditorHelper.getViewPath(dialogData.macro.properties[i].view);
- }
- };
- });
- //used for the media picker dialog
- angular.module("umbraco")
- .controller("Umbraco.Dialogs.MediaPickerController",
- function ($scope, mediaResource, umbRequestHelper, entityResource, $log, mediaHelper, eventsService, treeService, $cookies, $element, $timeout) {
- var dialogOptions = $scope.dialogOptions;
- $scope.onlyImages = dialogOptions.onlyImages;
- $scope.showDetails = dialogOptions.showDetails;
- $scope.multiPicker = (dialogOptions.multiPicker && dialogOptions.multiPicker !== "0") ? true : false;
- $scope.startNodeId = dialogOptions.startNodeId ? dialogOptions.startNodeId : -1;
- $scope.cropSize = dialogOptions.cropSize;
- $scope.filesUploading = 0;
- $scope.dropping = false;
- $scope.progress = 0;
- $scope.options = {
- url: umbRequestHelper.getApiUrl("mediaApiBaseUrl", "PostAddFile") + "?origin=blueimp",
- autoUpload: true,
- dropZone: $element.find(".umb-dialogs-mediapicker.browser"),
- fileInput: $element.find("input.uploader"),
- formData: {
- currentFolder: -1
- }
- };
- //preload selected item
- $scope.target = undefined;
- if(dialogOptions.currentTarget){
- $scope.target = dialogOptions.currentTarget;
- }
- $scope.submitFolder = function(e) {
- if (e.keyCode === 13) {
- e.preventDefault();
- $scope.showFolderInput = false;
- mediaResource
- .addFolder($scope.newFolderName, $scope.options.formData.currentFolder)
- .then(function(data) {
- //we've added a new folder so lets clear the tree cache for that specific item
- treeService.clearCache({
- cacheKey: "__media", //this is the main media tree cache key
- childrenOf: data.parentId //clear the children of the parent
- });
- $scope.gotoFolder(data);
- });
- }
- };
- $scope.gotoFolder = function(folder) {
- if(!folder){
- folder = {id: -1, name: "Media", icon: "icon-folder"};
- }
- if (folder.id > 0) {
- entityResource.getAncestors(folder.id, "media")
- .then(function(anc) {
- // anc.splice(0,1);
- $scope.path = _.filter(anc, function (f) {
- return f.path.indexOf($scope.startNodeId) !== -1;
- });
- });
- }
- else {
- $scope.path = [];
- }
- //mediaResource.rootMedia()
- mediaResource.getChildren(folder.id)
- .then(function(data) {
- $scope.searchTerm = "";
- $scope.images = data.items ? data.items : [];
- });
- $scope.options.formData.currentFolder = folder.id;
- $scope.currentFolder = folder;
- };
- //This executes prior to the whole processing which we can use to get the UI going faster,
- //this also gives us the start callback to invoke to kick of the whole thing
- $scope.$on('fileuploadadd', function (e, data) {
- $scope.$apply(function () {
- $scope.filesUploading++;
- });
- });
- //when one is finished
- $scope.$on('fileuploaddone', function (e, data) {
- $scope.filesUploading--;
- if ($scope.filesUploading == 0) {
- $scope.$apply(function () {
- $scope.progress = 0;
- $scope.gotoFolder($scope.currentFolder);
- });
- }
- });
- // All these sit-ups are to add dropzone area and make sure it gets removed if dragging is aborted!
- $scope.$on('fileuploaddragover', function (e, data) {
- if (!$scope.dragClearTimeout) {
- $scope.$apply(function () {
- $scope.dropping = true;
- });
- }
- else {
- $timeout.cancel($scope.dragClearTimeout);
- }
- $scope.dragClearTimeout = $timeout(function () {
- $scope.dropping = null;
- $scope.dragClearTimeout = null;
- }, 300);
- });
- $scope.clickHandler = function(image, ev, select) {
- ev.preventDefault();
- if (image.isFolder && !select) {
- $scope.gotoFolder(image);
- }else{
- eventsService.emit("dialogs.mediaPicker.select", image);
- //we have 3 options add to collection (if multi) show details, or submit it right back to the callback
- if ($scope.multiPicker) {
- $scope.select(image);
- image.cssclass = ($scope.dialogData.selection.indexOf(image) > -1) ? "selected" : "";
- }else if($scope.showDetails) {
- $scope.target= image;
- $scope.target.url = mediaHelper.resolveFile(image);
- }else{
- $scope.submit(image);
- }
- }
- };
- $scope.exitDetails = function(){
- if(!$scope.currentFolder){
- $scope.gotoFolder();
- }
- $scope.target = undefined;
- };
- //default root item
- if(!$scope.target){
- $scope.gotoFolder({ id: $scope.startNodeId, name: "Media", icon: "icon-folder" });
- }
- });
- //used for the member picker dialog
- angular.module("umbraco").controller("Umbraco.Dialogs.MemberGroupPickerController",
- function($scope, eventsService, entityResource, searchService, $log) {
- var dialogOptions = $scope.dialogOptions;
- $scope.dialogTreeEventHandler = $({});
- $scope.multiPicker = dialogOptions.multiPicker;
- /** Method used for selecting a node */
- function select(text, id) {
- if (dialogOptions.multiPicker) {
- $scope.select(id);
- }
- else {
- $scope.submit(id);
- }
- }
- function nodeSelectHandler(ev, args) {
- args.event.preventDefault();
- args.event.stopPropagation();
- eventsService.emit("dialogs.memberGroupPicker.select", args);
- //This is a tree node, so we don't have an entity to pass in, it will need to be looked up
- //from the server in this method.
- select(args.node.name, args.node.id);
- //toggle checked state
- args.node.selected = args.node.selected === true ? false : true;
- }
- $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
- $scope.$on('$destroy', function () {
- $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
- });
- });
- angular.module("umbraco").controller("Umbraco.Dialogs.RteEmbedController", function ($scope, $http, umbRequestHelper) {
- $scope.form = {};
- $scope.form.url = "";
- $scope.form.width = 360;
- $scope.form.height = 240;
- $scope.form.constrain = true;
- $scope.form.preview = "";
- $scope.form.success = false;
- $scope.form.info = "";
- $scope.form.supportsDimensions = false;
- var origWidth = 500;
- var origHeight = 300;
- $scope.showPreview = function() {
- if ($scope.form.url) {
- $scope.form.show = true;
- $scope.form.preview = "<div class=\"umb-loader\" style=\"height: 10px; margin: 10px 0px;\"></div>";
- $scope.form.info = "";
- $scope.form.success = false;
- $http({ method: 'GET', url: umbRequestHelper.getApiUrl("embedApiBaseUrl", "GetEmbed"), params: { url: $scope.form.url, width: $scope.form.width, height: $scope.form.height } })
- .success(function (data) {
- $scope.form.preview = "";
- switch (data.Status) {
- case 0:
- //not supported
- $scope.form.info = "Not supported";
- break;
- case 1:
- //error
- $scope.form.info = "Computer says no";
- break;
- case 2:
- $scope.form.preview = data.Markup;
- $scope.form.supportsDimensions = data.SupportsDimensions;
- $scope.form.success = true;
- break;
- }
- })
- .error(function () {
- $scope.form.supportsDimensions = false;
- $scope.form.preview = "";
- $scope.form.info = "Computer says no";
- });
- } else {
- $scope.form.supportsDimensions = false;
- $scope.form.preview = "";
- $scope.form.info = "Please enter a URL";
- }
- };
- $scope.changeSize = function (type) {
- var width, height;
- if ($scope.form.constrain) {
- width = parseInt($scope.form.width, 10);
- height = parseInt($scope.form.height, 10);
- if (type == 'width') {
- origHeight = Math.round((width / origWidth) * height);
- $scope.form.height = origHeight;
- } else {
- origWidth = Math.round((height / origHeight) * width);
- $scope.form.width = origWidth;
- }
- }
- if ($scope.form.url != "") {
- $scope.showPreview();
- }
- };
- $scope.insert = function(){
- $scope.submit($scope.form.preview);
- };
- });
- angular.module("umbraco").controller('Umbraco.Dialogs.Template.QueryBuilderController',
- function($scope, $http, dialogService){
- $http.get("backoffice/UmbracoApi/TemplateQuery/GetAllowedProperties").then(function(response) {
- $scope.properties = response.data;
- });
- $http.get("backoffice/UmbracoApi/TemplateQuery/GetContentTypes").then(function (response) {
- $scope.contentTypes = response.data;
- });
- $http.get("backoffice/UmbracoApi/TemplateQuery/GetFilterConditions").then(function (response) {
- $scope.conditions = response.data;
- });
- $scope.query = {
- contentType: {
- name: "Everything"
- },
- source:{
- name: "My website"
- },
- filters:[
- {
- property:undefined,
- operator: undefined
- }
- ],
- sort:{
- property:{
- alias: "",
- name: "",
- },
- direction: "Ascending"
- }
- };
- $scope.chooseSource = function(query){
- dialogService.contentPicker({
- callback: function (data) {
- if (data.id > 0) {
- query.source = { id: data.id, name: data.name };
- } else {
- query.source.name = "My website";
- delete query.source.id;
- }
- }
- });
- };
- var throttledFunc = _.throttle(function() {
- $http.post("backoffice/UmbracoApi/TemplateQuery/PostTemplateQuery", $scope.query).then(function (response) {
- $scope.result = response.data;
- });
- }, 200);
- $scope.$watch("query", function(value) {
- throttledFunc();
- }, true);
- $scope.getPropertyOperators = function (property) {
- var conditions = _.filter($scope.conditions, function(condition) {
- var index = condition.appliesTo.indexOf(property.type);
- return index >= 0;
- });
- return conditions;
- };
- $scope.addFilter = function(query){
- query.filters.push({});
- };
- $scope.trashFilter = function (query) {
- query.filters.splice(query,1);
- };
- $scope.changeSortOrder = function(query){
- if(query.sort.direction === "ascending"){
- query.sort.direction = "descending";
- }else{
- query.sort.direction = "ascending";
- }
- };
- $scope.setSortProperty = function(query, property){
- query.sort.property = property;
- if(property.type === "datetime"){
- query.sort.direction = "descending";
- }else{
- query.sort.direction = "ascending";
- }
- };
- });
- //used for the media picker dialog
- angular.module("umbraco").controller("Umbraco.Dialogs.TreePickerController",
- function ($scope, entityResource, eventsService, $log, searchService, angularHelper, $timeout, localizationService, treeService) {
- var tree = null;
- var dialogOptions = $scope.dialogOptions;
- $scope.dialogTreeEventHandler = $({});
- $scope.section = dialogOptions.section;
- $scope.treeAlias = dialogOptions.treeAlias;
- $scope.multiPicker = dialogOptions.multiPicker;
- $scope.hideHeader = true;
- $scope.searchInfo = {
- searchFromId: dialogOptions.startNodeId,
- searchFromName: null,
- showSearch: false,
- results: [],
- selectedSearchResults: []
- }
- //create the custom query string param for this tree
- $scope.customTreeParams = dialogOptions.startNodeId ? "startNodeId=" + dialogOptions.startNodeId : "";
- $scope.customTreeParams += dialogOptions.customTreeParams ? "&" + dialogOptions.customTreeParams : "";
- var searchText = "Search...";
- localizationService.localize("general_search").then(function (value) {
- searchText = value + "...";
- });
- var entityType = "Document";
- //min / max values
- if (dialogOptions.minNumber) {
- dialogOptions.minNumber = parseInt(dialogOptions.minNumber, 10);
- }
- if (dialogOptions.maxNumber) {
- dialogOptions.maxNumber = parseInt(dialogOptions.maxNumber, 10);
- }
- if (dialogOptions.section === "member") {
- entityType = "Member";
- }
- else if (dialogOptions.section === "media") {
- entityType = "Media";
- }
- //Configures filtering
- if (dialogOptions.filter) {
- dialogOptions.filterExclude = false;
- dialogOptions.filterAdvanced = false;
- //used advanced filtering
- if (angular.isFunction(dialogOptions.filter)) {
- dialogOptions.filterAdvanced = true;
- }
- else if (angular.isObject(dialogOptions.filter)) {
- dialogOptions.filterAdvanced = true;
- }
- else {
- if (dialogOptions.filter.startsWith("!")) {
- dialogOptions.filterExclude = true;
- dialogOptions.filter = dialogOptions.filter.substring(1);
- }
- //used advanced filtering
- if (dialogOptions.filter.startsWith("{")) {
- dialogOptions.filterAdvanced = true;
- //convert to object
- dialogOptions.filter = angular.fromJson(dialogOptions.filter);
- }
- }
- }
- function nodeExpandedHandler(ev, args) {
- if (angular.isArray(args.children)) {
- //iterate children
- _.each(args.children, function (child) {
- //check if any of the items are list views, if so we need to add some custom
- // children: A node to activate the search, any nodes that have already been
- // selected in the search
- if (child.metaData.isContainer) {
- child.hasChildren = true;
- child.children = [
- {
- level: child.level + 1,
- hasChildren: false,
- parent: function () {
- return child;
- },
- name: searchText,
- metaData: {
- listViewNode: child,
- },
- cssClass: "icon-search",
- cssClasses: ["not-published"]
- }
- ];
- //add base transition classes to this node
- child.cssClasses.push("tree-node-slide-up");
- var listViewResults = _.filter($scope.searchInfo.selectedSearchResults, function(i) {
- return i.parentId == child.id;
- });
- _.each(listViewResults, function(item) {
- child.children.unshift({
- id: item.id,
- name: item.name,
- cssClass: "icon umb-tree-icon sprTree " + item.icon,
- level: child.level + 1,
- metaData: {
- isSearchResult: true
- },
- hasChildren: false,
- parent: function () {
- return child;
- }
- });
- });
- }
- //now we need to look in the already selected search results and
- // toggle the check boxes for those ones that are listed
- var exists = _.find($scope.searchInfo.selectedSearchResults, function (selected) {
- return child.id == selected.id;
- });
- if (exists) {
- child.selected = true;
- }
- });
- //check filter
- performFiltering(args.children);
- }
- }
- //gets the tree object when it loads
- function treeLoadedHandler(ev, args) {
- tree = args.tree;
- }
- //wires up selection
- function nodeSelectHandler(ev, args) {
- args.event.preventDefault();
- args.event.stopPropagation();
- if (args.node.metaData.listViewNode) {
- //check if list view 'search' node was selected
- $scope.searchInfo.showSearch = true;
- $scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id;
- $scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name;
- //add transition classes
- var listViewNode = args.node.parent();
- listViewNode.cssClasses.push('tree-node-slide-up-hide-active');
- }
- else if (args.node.metaData.isSearchResult) {
- //check if the item selected was a search result from a list view
- //unselect
- select(args.node.name, args.node.id);
- //remove it from the list view children
- var listView = args.node.parent();
- listView.children = _.reject(listView.children, function(child) {
- return child.id == args.node.id;
- });
- //remove it from the custom tracked search result list
- $scope.searchInfo.selectedSearchResults = _.reject($scope.searchInfo.selectedSearchResults, function (i) {
- return i.id == args.node.id;
- });
- }
- else {
- eventsService.emit("dialogs.treePickerController.select", args);
- if (args.node.filtered) {
- return;
- }
- //This is a tree node, so we don't have an entity to pass in, it will need to be looked up
- //from the server in this method.
- select(args.node.name, args.node.id);
- //toggle checked state
- args.node.selected = args.node.selected === true ? false : true;
- }
- }
- /** Method used for selecting a node */
- function select(text, id, entity) {
- //if we get the root, we just return a constructed entity, no need for server data
- if (id < 0) {
- if ($scope.multiPicker) {
- $scope.select(id);
- }
- else {
- var node = {
- alias: null,
- icon: "icon-folder",
- id: id,
- name: text
- };
- $scope.submit(node);
- }
- }
- else {
- if ($scope.multiPicker) {
- $scope.select(Number(id));
- }
- else {
- $scope.hideSearch();
- //if an entity has been passed in, use it
- if (entity) {
- $scope.submit(entity);
- } else {
- //otherwise we have to get it from the server
- entityResource.getById(id, entityType).then(function (ent) {
- $scope.submit(ent);
- });
- }
- }
- }
- }
- function performFiltering(nodes) {
- if (!dialogOptions.filter) {
- return;
- }
- //remove any list view search nodes from being filtered since these are special nodes that always must
- // be allowed to be clicked on
- nodes = _.filter(nodes, function(n) {
- return !angular.isObject(n.metaData.listViewNode);
- });
- if (dialogOptions.filterAdvanced) {
- //filter either based on a method or an object
- var filtered = angular.isFunction(dialogOptions.filter)
- ? _.filter(nodes, dialogOptions.filter)
- : _.where(nodes, dialogOptions.filter);
- angular.forEach(filtered, function (value, key) {
- value.filtered = true;
- if (dialogOptions.filterCssClass) {
- if (!value.cssClasses) {
- value.cssClasses = [];
- }
- value.cssClasses.push(dialogOptions.filterCssClass);
- }
- });
- } else {
- var a = dialogOptions.filter.toLowerCase().split(',');
- angular.forEach(nodes, function (value, key) {
- var found = a.indexOf(value.metaData.contentType.toLowerCase()) >= 0;
- if (!dialogOptions.filterExclude && !found || dialogOptions.filterExclude && found) {
- value.filtered = true;
- if (dialogOptions.filterCssClass) {
- if (!value.cssClasses) {
- value.cssClasses = [];
- }
- value.cssClasses.push(dialogOptions.filterCssClass);
- }
- }
- });
- }
- }
- $scope.multiSubmit = function (result) {
- entityResource.getByIds(result, entityType).then(function (ents) {
- $scope.submit(ents);
- });
- };
- /** method to select a search result */
- $scope.selectResult = function (evt, result) {
- if (result.filtered) {
- return;
- }
- result.selected = result.selected === true ? false : true;
- //since result = an entity, we'll pass it in so we don't have to go back to the server
- select(result.name, result.id, result);
- //add/remove to our custom tracked list of selected search results
- if (result.selected) {
- $scope.searchInfo.selectedSearchResults.push(result);
- }
- else {
- $scope.searchInfo.selectedSearchResults = _.reject($scope.searchInfo.selectedSearchResults, function(i) {
- return i.id == result.id;
- });
- }
- //ensure the tree node in the tree is checked/unchecked if it already exists there
- if (tree) {
- var found = treeService.getDescendantNode(tree.root, result.id);
- if (found) {
- found.selected = result.selected;
- }
- }
- };
- $scope.hideSearch = function () {
- //Traverse the entire displayed tree and update each node to sync with the selected search results
- if (tree) {
- //we need to ensure that any currently displayed nodes that get selected
- // from the search get updated to have a check box!
- function checkChildren(children) {
- _.each(children, function (child) {
- //check if the id is in the selection, if so ensure it's flagged as selected
- var exists = _.find($scope.searchInfo.selectedSearchResults, function (selected) {
- return child.id == selected.id;
- });
- //if the curr node exists in selected search results, ensure it's checked
- if (exists) {
- child.selected = true;
- }
- //if the curr node does not exist in the selected search result, and the curr node is a child of a list view search result
- else if (child.metaData.isSearchResult) {
- //if this tree node is under a list view it means that the node was added
- // to the tree dynamically under the list view that was searched, so we actually want to remove
- // it all together from the tree
- var listView = child.parent();
- listView.children = _.reject(listView.children, function(c) {
- return c.id == child.id;
- });
- }
- //check if the current node is a list view and if so, check if there's any new results
- // that need to be added as child nodes to it based on search results selected
- if (child.metaData.isContainer) {
- child.cssClasses = _.reject(child.cssClasses, function(c) {
- return c === 'tree-node-slide-up-hide-active';
- });
- var listViewResults = _.filter($scope.searchInfo.selectedSearchResults, function (i) {
- return i.parentId == child.id;
- });
- _.each(listViewResults, function (item) {
- var childExists = _.find(child.children, function(c) {
- return c.id == item.id;
- });
- if (!childExists) {
- var parent = child;
- child.children.unshift({
- id: item.id,
- name: item.name,
- cssClass: "icon umb-tree-icon sprTree " + item.icon,
- level: child.level + 1,
- metaData: {
- isSearchResult: true
- },
- hasChildren: false,
- parent: function () {
- return parent;
- }
- });
- }
- });
- }
- //recurse
- if (child.children && child.children.length > 0) {
- checkChildren(child.children);
- }
- });
- }
- checkChildren(tree.root.children);
- }
- $scope.searchInfo.showSearch = false;
- $scope.searchInfo.searchFromId = dialogOptions.startNodeId;
- $scope.searchInfo.searchFromName = null;
- $scope.searchInfo.results = [];
- }
- $scope.onSearchResults = function(results) {
- //filter all items - this will mark an item as filtered
- performFiltering(results);
- //now actually remove all filtered items so they are not even displayed
- results = _.filter(results, function(item) {
- return !item.filtered;
- });
- $scope.searchInfo.results = results;
- //sync with the curr selected results
- _.each($scope.searchInfo.results, function (result) {
- var exists = _.find($scope.dialogData.selection, function (selectedId) {
- return result.id == selectedId;
- });
- if (exists) {
- result.selected = true;
- }
- });
- $scope.searchInfo.showSearch = true;
- };
- $scope.dialogTreeEventHandler.bind("treeLoaded", treeLoadedHandler);
- $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
- $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
- $scope.$on('$destroy', function () {
- $scope.dialogTreeEventHandler.unbind("treeLoaded", treeLoadedHandler);
- $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
- $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
- });
- });
- angular.module("umbraco")
- .controller("Umbraco.Dialogs.UserController", function ($scope, $location, $timeout, userService, historyService, eventsService) {
- $scope.user = userService.getCurrentUser();
- $scope.history = historyService.getCurrent();
- $scope.version = Umbraco.Sys.ServerVariables.application.version + " assembly: " + Umbraco.Sys.ServerVariables.application.assemblyVersion;
- var evts = [];
- evts.push(eventsService.on("historyService.add", function (e, args) {
- $scope.history = args.all;
- }));
- evts.push(eventsService.on("historyService.remove", function (e, args) {
- $scope.history = args.all;
- }));
- evts.push(eventsService.on("historyService.removeAll", function (e, args) {
- $scope.history = [];
- }));
- $scope.logout = function () {
- //Add event listener for when there are pending changes on an editor which means our route was not successful
- var pendingChangeEvent = eventsService.on("valFormManager.pendingChanges", function (e, args) {
- //one time listener, remove the event
- pendingChangeEvent();
- $scope.close();
- });
- //perform the path change, if it is successful then the promise will resolve otherwise it will fail
- $scope.close();
- $location.path("/logout");
- };
- $scope.gotoHistory = function (link) {
- $location.path(link);
- $scope.close();
- };
- //Manually update the remaining timeout seconds
- function updateTimeout() {
- $timeout(function () {
- if ($scope.remainingAuthSeconds > 0) {
- $scope.remainingAuthSeconds--;
- $scope.$digest();
- //recurse
- updateTimeout();
- }
- }, 1000, false); // 1 second, do NOT execute a global digest
- }
- //get the user
- userService.getCurrentUser().then(function (user) {
- $scope.user = user;
- if ($scope.user) {
- $scope.remainingAuthSeconds = $scope.user.remainingAuthSeconds;
- $scope.canEditProfile = _.indexOf($scope.user.allowedSections, "users") > -1;
- //set the timer
- updateTimeout();
- }
- });
- //remove all event handlers
- $scope.$on('$destroy', function () {
- for (var e = 0; e < evts.length; e++) {
- evts[e]();
- }
- });
- });
- /**
- * @ngdoc controller
- * @name Umbraco.Dialogs.LegacyDeleteController
- * @function
- *
- * @description
- * The controller for deleting content
- */
- function YsodController($scope, legacyResource, treeService, navigationService) {
- if ($scope.error && $scope.error.data && $scope.error.data.StackTrace) {
- //trim whitespace
- $scope.error.data.StackTrace = $scope.error.data.StackTrace.trim();
- }
- $scope.closeDialog = function() {
- $scope.dismiss();
- };
- }
- angular.module("umbraco").controller("Umbraco.Dialogs.YsodController", YsodController);
- /**
- * @ngdoc controller
- * @name Umbraco.LegacyController
- * @function
- *
- * @description
- * A controller to control the legacy iframe injection
- *
- */
- function LegacyController($scope, $routeParams, $element) {
- var url = decodeURIComponent($routeParams.url.toLowerCase().replace(/javascript\:/g, ""));
- //split into path and query
- var urlParts = url.split("?");
- var extIndex = urlParts[0].lastIndexOf(".");
- var ext = extIndex === -1 ? "" : urlParts[0].substr(extIndex);
- //path cannot be a js file
- if (ext !== ".js" || ext === "") {
- //path cannot contain any of these chars
- var toClean = "*(){}[];:<>\\|'\"";
- for (var i = 0; i < toClean.length; i++) {
- var reg = new RegExp("\\" + toClean[i], "g");
- urlParts[0] = urlParts[0].replace(reg, "");
- }
- //join cleaned path and query back together
- url = urlParts[0] + (urlParts.length === 1 ? "" : ("?" + urlParts[1]));
- $scope.legacyPath = url;
- }
- else {
- throw "Invalid url";
- }
- }
- angular.module("umbraco").controller('Umbraco.LegacyController', LegacyController);
- /** This controller is simply here to launch the login dialog when the route is explicitly changed to /login */
- angular.module('umbraco').controller("Umbraco.LoginController", function (eventsService, $scope, userService, $location, $rootScope) {
- userService._showLoginDialog();
- var evtOn = eventsService.on("app.ready", function(evt, data){
- $scope.avatar = "assets/img/application/logo.png";
- var path = "/";
- //check if there's a returnPath query string, if so redirect to it
- var locationObj = $location.search();
- if (locationObj.returnPath) {
- path = decodeURIComponent(locationObj.returnPath);
- }
- $location.url(path);
- });
- $scope.$on('$destroy', function () {
- eventsService.unsubscribe(evtOn);
- });
- });
- //used for the media picker dialog
- angular.module("umbraco").controller("Umbraco.Notifications.ConfirmRouteChangeController",
- function ($scope, $location, $log, notificationsService) {
- $scope.discard = function(not){
- not.args.listener();
- $location.search("");
- //we need to break the path up into path and query
- var parts = not.args.path.split("?");
- var query = {};
- if (parts.length > 1) {
- _.each(parts[1].split("&"), function(q) {
- var keyVal = q.split("=");
- query[keyVal[0]] = keyVal[1];
- });
- }
- $location.path(parts[0]).search(query);
- notificationsService.remove(not);
- };
- $scope.stay = function(not){
- notificationsService.remove(not);
- };
- });
- angular.module("umbraco").controller("Umbraco.Editors.Content.CopyController",
- function ($scope, eventsService, contentResource, navigationService, appState, treeService, localizationService) {
- var dialogOptions = $scope.dialogOptions;
- var searchText = "Search...";
- localizationService.localize("general_search").then(function (value) {
- searchText = value + "...";
- });
- $scope.relateToOriginal = false;
- $scope.dialogTreeEventHandler = $({});
- $scope.busy = false;
- $scope.searchInfo = {
- searchFromId: null,
- searchFromName: null,
- showSearch: false,
- results: [],
- selectedSearchResults: []
- }
- var node = dialogOptions.currentNode;
- function nodeSelectHandler(ev, args) {
- args.event.preventDefault();
- args.event.stopPropagation();
- if (args.node.metaData.listViewNode) {
- //check if list view 'search' node was selected
- $scope.searchInfo.showSearch = true;
- $scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id;
- $scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name;
- }
- else {
- eventsService.emit("editors.content.copyController.select", args);
- if ($scope.target) {
- //un-select if there's a current one selected
- $scope.target.selected = false;
- }
- $scope.target = args.node;
- $scope.target.selected = true;
- }
- }
- function nodeExpandedHandler(ev, args) {
- if (angular.isArray(args.children)) {
- //iterate children
- _.each(args.children, function (child) {
- //check if any of the items are list views, if so we need to add a custom
- // child: A node to activate the search
- if (child.metaData.isContainer) {
- child.hasChildren = true;
- child.children = [
- {
- level: child.level + 1,
- hasChildren: false,
- name: searchText,
- metaData: {
- listViewNode: child,
- },
- cssClass: "icon umb-tree-icon sprTree icon-search",
- cssClasses: ["not-published"]
- }
- ];
- }
- });
- }
- }
- $scope.hideSearch = function () {
- $scope.searchInfo.showSearch = false;
- $scope.searchInfo.searchFromId = null;
- $scope.searchInfo.searchFromName = null;
- $scope.searchInfo.results = [];
- }
- // method to select a search result
- $scope.selectResult = function (evt, result) {
- result.selected = result.selected === true ? false : true;
- nodeSelectHandler(evt, { event: evt, node: result });
- };
- //callback when there are search results
- $scope.onSearchResults = function (results) {
- $scope.searchInfo.results = results;
- $scope.searchInfo.showSearch = true;
- };
- $scope.copy = function () {
- $scope.busy = true;
- $scope.error = false;
- contentResource.copy({ parentId: $scope.target.id, id: node.id, relateToOriginal: $scope.relateToOriginal })
- .then(function (path) {
- $scope.error = false;
- $scope.success = true;
- $scope.busy = false;
- //get the currently edited node (if any)
- var activeNode = appState.getTreeState("selectedNode");
- //we need to do a double sync here: first sync to the copied content - but don't activate the node,
- //then sync to the currenlty edited content (note: this might not be the content that was copied!!)
- navigationService.syncTree({ tree: "content", path: path, forceReload: true, activate: false }).then(function (args) {
- if (activeNode) {
- var activeNodePath = treeService.getPath(activeNode).join();
- //sync to this node now - depending on what was copied this might already be synced but might not be
- navigationService.syncTree({ tree: "content", path: activeNodePath, forceReload: false, activate: true });
- }
- });
- }, function (err) {
- $scope.success = false;
- $scope.error = err;
- $scope.busy = false;
- });
- };
- $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
- $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
- $scope.$on('$destroy', function () {
- $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
- $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
- });
- });
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Content.CreateController
- * @function
- *
- * @description
- * The controller for the content creation dialog
- */
- function contentCreateController($scope, $routeParams, contentTypeResource, iconHelper) {
- contentTypeResource.getAllowedTypes($scope.currentNode.id).then(function(data) {
- $scope.allowedTypes = iconHelper.formatContentTypeIcons(data);
- });
- }
- angular.module('umbraco').controller("Umbraco.Editors.Content.CreateController", contentCreateController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.ContentDeleteController
- * @function
- *
- * @description
- * The controller for deleting content
- */
- function ContentDeleteController($scope, contentResource, treeService, navigationService, editorState, $location) {
- $scope.performDelete = function() {
- //mark it for deletion (used in the UI)
- $scope.currentNode.loading = true;
- contentResource.deleteById($scope.currentNode.id).then(function () {
- $scope.currentNode.loading = false;
- //get the root node before we remove it
- var rootNode = treeService.getTreeRoot($scope.currentNode);
- treeService.removeNode($scope.currentNode);
- if (rootNode) {
- //ensure the recycle bin has child nodes now
- var recycleBin = treeService.getDescendantNode(rootNode, -20);
- if (recycleBin) {
- recycleBin.hasChildren = true;
- }
- }
- //if the current edited item is the same one as we're deleting, we need to navigate elsewhere
- if (editorState.current && editorState.current.id == $scope.currentNode.id) {
- $location.path("/content/content/edit/" + $scope.currentNode.parentId);
- }
- navigationService.hideMenu();
- });
- };
- $scope.cancel = function() {
- navigationService.hideDialog();
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.Content.DeleteController", ContentDeleteController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Content.EditController
- * @function
- *
- * @description
- * The controller for the content editor
- */
- function ContentEditController($scope, $rootScope, $routeParams, $q, $timeout, $window, appState, contentResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, treeService, fileManager, formHelper, umbRequestHelper, keyboardService, umbModelMapper, editorState, $http) {
- //setup scope vars
- $scope.defaultButton = null;
- $scope.subButtons = [];
- $scope.currentSection = appState.getSectionState("currentSection");
- $scope.currentNode = null; //the editors affiliated node
- $scope.isNew = $routeParams.create;
- function init(content) {
- var buttons = contentEditingHelper.configureContentEditorButtons({
- create: $routeParams.create,
- content: content,
- methods: {
- saveAndPublish: $scope.saveAndPublish,
- sendToPublish: $scope.sendToPublish,
- save: $scope.save,
- unPublish: $scope.unPublish
- }
- });
- $scope.defaultButton = buttons.defaultButton;
- $scope.subButtons = buttons.subButtons;
- editorState.set($scope.content);
- //We fetch all ancestors of the node to generate the footer breadcrumb navigation
- if (!$routeParams.create) {
- if (content.parentId && content.parentId != -1) {
- entityResource.getAncestors(content.id, "document")
- .then(function (anc) {
- $scope.ancestors = anc;
- });
- }
- }
- }
- /** Syncs the content item to it's tree node - this occurs on first load and after saving */
- function syncTreeNode(content, path, initialLoad) {
- if (!$scope.content.isChildOfListView) {
- navigationService.syncTree({ tree: "content", path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
- $scope.currentNode = syncArgs.node;
- });
- }
- else if (initialLoad === true) {
- //it's a child item, just sync the ui node to the parent
- navigationService.syncTree({ tree: "content", path: path.substring(0, path.lastIndexOf(",")).split(","), forceReload: initialLoad !== true });
- //if this is a child of a list view and it's the initial load of the editor, we need to get the tree node
- // from the server so that we can load in the actions menu.
- umbRequestHelper.resourcePromise(
- $http.get(content.treeNodeUrl),
- 'Failed to retrieve data for child node ' + content.id).then(function (node) {
- $scope.currentNode = node;
- });
- }
- }
- // This is a helper method to reduce the amount of code repitition for actions: Save, Publish, SendToPublish
- function performSave(args) {
- var deferred = $q.defer();
- contentEditingHelper.contentEditorPerformSave({
- statusMessage: args.statusMessage,
- saveMethod: args.saveMethod,
- scope: $scope,
- content: $scope.content
- }).then(function (data) {
- //success
- init($scope.content);
- syncTreeNode($scope.content, data.path);
- deferred.resolve(data);
- }, function (err) {
- //error
- if (err) {
- editorState.set($scope.content);
- }
- deferred.reject(err);
- });
- return deferred.promise;
- }
- function resetLastListPageNumber(content) {
- // We're using rootScope to store the page number for list views, so if returning to the list
- // we can restore the page. If we've moved on to edit a piece of content that's not the list or it's children
- // we should remove this so as not to confuse if navigating to a different list
- if (!content.isChildOfListView && !content.isContainer) {
- $rootScope.lastListViewPageViewed = null;
- }
- }
- if ($routeParams.create) {
- //we are creating so get an empty content item
- contentResource.getScaffold($routeParams.id, $routeParams.doctype)
- .then(function (data) {
- $scope.loaded = true;
- $scope.content = data;
- init($scope.content);
- resetLastListPageNumber($scope.content);
- });
- }
- else {
- //we are editing so get the content item from the server
- contentResource.getById($routeParams.id)
- .then(function (data) {
- $scope.loaded = true;
- $scope.content = data;
- if (data.isChildOfListView && data.trashed === false) {
- $scope.listViewPath = ($routeParams.page)
- ? "/content/content/edit/" + data.parentId + "?page=" + $routeParams.page
- : "/content/content/edit/" + data.parentId;
- }
- init($scope.content);
- //in one particular special case, after we've created a new item we redirect back to the edit
- // route but there might be server validation errors in the collection which we need to display
- // after the redirect, so we will bind all subscriptions which will show the server validation errors
- // if there are any and then clear them so the collection no longer persists them.
- serverValidationManager.executeAndClearAllSubscriptions();
- syncTreeNode($scope.content, data.path, true);
- resetLastListPageNumber($scope.content);
- });
- }
- $scope.unPublish = function () {
- if (formHelper.submitForm({ scope: $scope, statusMessage: "Unpublishing...", skipValidation: true })) {
- contentResource.unPublish($scope.content.id)
- .then(function (data) {
- formHelper.resetForm({ scope: $scope, notifications: data.notifications });
- contentEditingHelper.handleSuccessfulSave({
- scope: $scope,
- savedContent: data,
- rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
- });
- init($scope.content);
- syncTreeNode($scope.content, data.path);
- });
- }
- };
- $scope.sendToPublish = function () {
- return performSave({ saveMethod: contentResource.sendToPublish, statusMessage: "Sending..." });
- };
- $scope.saveAndPublish = function () {
- return performSave({ saveMethod: contentResource.publish, statusMessage: "Publishing..." });
- };
- $scope.save = function () {
- return performSave({ saveMethod: contentResource.save, statusMessage: "Saving..." });
- };
- $scope.preview = function (content) {
- if (!$scope.busy) {
- // Chromes popup blocker will kick in if a window is opened
- // outwith the initial scoped request. This trick will fix that.
- //
- var previewWindow = $window.open('preview/?id=' + content.id, 'umbpreview');
- $scope.save().then(function (data) {
- // Build the correct path so both /#/ and #/ work.
- var redirect = Umbraco.Sys.ServerVariables.umbracoSettings.umbracoPath + '/preview/?id=' + data.id;
- previewWindow.location.href = redirect;
- });
- }
- };
- // this method is called for all action buttons and then we proxy based on the btn definition
- $scope.performAction = function (btn) {
- if (!btn || !angular.isFunction(btn.handler)) {
- throw "btn.handler must be a function reference";
- }
- if (!$scope.busy) {
- btn.handler.apply(this);
- }
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.Content.EditController", ContentEditController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Content.EmptyRecycleBinController
- * @function
- *
- * @description
- * The controller for deleting content
- */
- function ContentEmptyRecycleBinController($scope, contentResource, treeService, navigationService) {
- $scope.performDelete = function() {
- //(used in the UI)
- $scope.currentNode.loading = true;
- contentResource.emptyRecycleBin($scope.currentNode.id).then(function () {
- $scope.currentNode.loading = false;
- //TODO: Need to sync tree, etc...
- treeService.removeChildNodes($scope.currentNode);
- navigationService.hideMenu();
- });
- };
- $scope.cancel = function() {
- navigationService.hideDialog();
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.Content.EmptyRecycleBinController", ContentEmptyRecycleBinController);
- angular.module("umbraco").controller("Umbraco.Editors.Content.MoveController",
- function ($scope, eventsService, contentResource, navigationService, appState, treeService, localizationService) {
- var dialogOptions = $scope.dialogOptions;
- var searchText = "Search...";
- localizationService.localize("general_search").then(function (value) {
- searchText = value + "...";
- });
- $scope.dialogTreeEventHandler = $({});
- $scope.busy = false;
- $scope.searchInfo = {
- searchFromId: null,
- searchFromName: null,
- showSearch: false,
- results: [],
- selectedSearchResults: []
- }
- var node = dialogOptions.currentNode;
- function nodeSelectHandler(ev, args) {
- args.event.preventDefault();
- args.event.stopPropagation();
- if (args.node.metaData.listViewNode) {
- //check if list view 'search' node was selected
- $scope.searchInfo.showSearch = true;
- $scope.searchInfo.searchFromId = args.node.metaData.listViewNode.id;
- $scope.searchInfo.searchFromName = args.node.metaData.listViewNode.name;
- }
- else {
- eventsService.emit("editors.content.moveController.select", args);
- if ($scope.target) {
- //un-select if there's a current one selected
- $scope.target.selected = false;
- }
- $scope.target = args.node;
- $scope.target.selected = true;
- }
- }
- function nodeExpandedHandler(ev, args) {
- if (angular.isArray(args.children)) {
- //iterate children
- _.each(args.children, function (child) {
- //check if any of the items are list views, if so we need to add a custom
- // child: A node to activate the search
- if (child.metaData.isContainer) {
- child.hasChildren = true;
- child.children = [
- {
- level: child.level + 1,
- hasChildren: false,
- name: searchText,
- metaData: {
- listViewNode: child,
- },
- cssClass: "icon umb-tree-icon sprTree icon-search",
- cssClasses: ["not-published"]
- }
- ];
- }
- });
- }
- }
- $scope.hideSearch = function () {
- $scope.searchInfo.showSearch = false;
- $scope.searchInfo.searchFromId = null;
- $scope.searchInfo.searchFromName = null;
- $scope.searchInfo.results = [];
- }
- // method to select a search result
- $scope.selectResult = function (evt, result) {
- result.selected = result.selected === true ? false : true;
- nodeSelectHandler(evt, { event: evt, node: result });
- };
- //callback when there are search results
- $scope.onSearchResults = function (results) {
- $scope.searchInfo.results = results;
- $scope.searchInfo.showSearch = true;
- };
- $scope.move = function () {
- $scope.busy = true;
- $scope.error = false;
- contentResource.move({ parentId: $scope.target.id, id: node.id })
- .then(function (path) {
- $scope.error = false;
- $scope.success = true;
- $scope.busy = false;
- //first we need to remove the node that launched the dialog
- treeService.removeNode($scope.currentNode);
- //get the currently edited node (if any)
- var activeNode = appState.getTreeState("selectedNode");
- //we need to do a double sync here: first sync to the moved content - but don't activate the node,
- //then sync to the currenlty edited content (note: this might not be the content that was moved!!)
- navigationService.syncTree({ tree: "content", path: path, forceReload: true, activate: false }).then(function (args) {
- if (activeNode) {
- var activeNodePath = treeService.getPath(activeNode).join();
- //sync to this node now - depending on what was copied this might already be synced but might not be
- navigationService.syncTree({ tree: "content", path: activeNodePath, forceReload: false, activate: true });
- }
- });
- }, function (err) {
- $scope.success = false;
- $scope.error = err;
- $scope.busy = false;
- });
- };
- $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
- $scope.dialogTreeEventHandler.bind("treeNodeExpanded", nodeExpandedHandler);
- $scope.$on('$destroy', function () {
- $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
- $scope.dialogTreeEventHandler.unbind("treeNodeExpanded", nodeExpandedHandler);
- });
- });
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Content.RecycleBinController
- * @function
- *
- * @description
- * Controls the recycle bin for content
- *
- */
- function ContentRecycleBinController($scope, $routeParams, dataTypeResource) {
- //ensures the list view doesn't actually load until we query for the list view config
- // for the section
- $scope.listViewPath = null;
- $routeParams.id = "-20";
- dataTypeResource.getById(-95).then(function (result) {
- _.each(result.preValues, function (i) {
- $scope.model.config[i.key] = i.value;
- });
- $scope.listViewPath = 'views/propertyeditors/listview/listview.html';
- });
- $scope.model = { config: { entityType: $routeParams.section } };
- }
- angular.module('umbraco').controller("Umbraco.Editors.Content.RecycleBinController", ContentRecycleBinController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.ContentType.EditController
- * @function
- *
- * @description
- * The controller for the content type editor
- */
- function ContentTypeEditController($scope, $routeParams, $log, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, entityResource) {
- $scope.tabs = [];
- $scope.page = {};
- $scope.contentType = {tabs: [], name: "My content type", alias:"myType", icon:"icon-folder", allowedChildren: [], allowedTemplate: []};
- $scope.contentType.tabs = [
- {name: "Content", properties:[ {name: "test"}]},
- {name: "Generic Properties", properties:[]}
- ];
- $scope.dataTypesOptions ={
- group: "properties",
- onDropHandler: function(item, args){
- args.sourceScope.move(args);
- },
- onReleaseHandler: function(item, args){
- var a = args;
- }
- };
- $scope.tabOptions ={
- group: "tabs",
- drop: false,
- nested: true,
- onDropHandler: function(item, args){
- },
- onReleaseHandler: function(item, args){
- }
- };
- $scope.propertiesOptions ={
- group: "properties",
- onDropHandler: function(item, args){
- //alert("dropped on properties");
- //args.targetScope.ngModel.$modelValue.push({name: "bong"});
- },
- onReleaseHandler: function(item, args){
- //alert("released from properties");
- //args.targetScope.ngModel.$modelValue.push({name: "bong"});
- },
- };
- $scope.omg = function(){
- alert("wat");
- };
- entityResource.getAll("Datatype").then(function(data){
- $scope.page.datatypes = data;
- });
- }
- angular.module("umbraco").controller("Umbraco.Editors.ContentType.EditController", ContentTypeEditController);
- function startUpVideosDashboardController($scope, xmlhelper, $log, $http) {
- $scope.videos = [];
- $scope.init = function(url){
- var proxyUrl = "dashboard/feedproxy.aspx?url=" + url;
- $http.get(proxyUrl).then(function(data){
- var feed = $(data.data);
- $('item', feed).each(function (i, item) {
- var video = {};
- video.thumbnail = $(item).find('thumbnail').attr('url');
- video.title = $("title", item).text();
- video.link = $("guid", item).text();
- $scope.videos.push(video);
- });
- });
- };
- }
- angular.module("umbraco").controller("Umbraco.Dashboard.StartupVideosController", startUpVideosDashboardController);
- function FormsController($scope, $route, $cookieStore, packageResource) {
- $scope.installForms = function(){
- $scope.state = "Installng package";
- packageResource
- .fetch("CD44CF39-3D71-4C19-B6EE-948E1FAF0525")
- .then(function(pack){
- $scope.state = "importing";
- return packageResource.import(pack);
- }, $scope.error)
- .then(function(pack){
- $scope.state = "Installing";
- return packageResource.installFiles(pack);
- }, $scope.error)
- .then(function(pack){
- $scope.state = "Restarting, please hold...";
- return packageResource.installData(pack);
- }, $scope.error)
- .then(function(pack){
- $scope.state = "All done, your browser will now refresh";
- return packageResource.cleanUp(pack);
- }, $scope.error)
- .then($scope.complete, $scope.error);
- };
- $scope.complete = function(result){
- var url = window.location.href + "?init=true";
- $cookieStore.put("umbPackageInstallId", result.packageGuid);
- window.location.reload(true);
- };
- $scope.error = function(err){
- $scope.state = undefined;
- $scope.error = err;
- };
- function Video_player (videoId) {
- // Get dom elements
- this.container = document.getElementById(videoId);
- this.video = this.container.getElementsByTagName('video')[0];
- //Create controls
- this.controls = document.createElement('div');
- this.controls.className="video-controls";
- this.seek_bar = document.createElement('input');
- this.seek_bar.className="seek-bar";
- this.seek_bar.type="range";
- this.seek_bar.setAttribute('value', '0');
- this.loader = document.createElement('div');
- this.loader.className="loader";
- this.progress_bar = document.createElement('span');
- this.progress_bar.className="progress-bar";
- // Insert controls
- this.controls.appendChild(this.seek_bar);
- this.container.appendChild(this.controls);
- this.controls.appendChild(this.loader);
- this.loader.appendChild(this.progress_bar);
- }
- Video_player.prototype
- .seeking = function() {
- // get the value of the seekbar (hidden input[type="range"])
- var time = this.video.duration * (this.seek_bar.value / 100);
- // Update video to seekbar value
- this.video.currentTime = time;
- };
- // Stop video when user initiates seeking
- Video_player.prototype
- .start_seek = function() {
- this.video.pause();
- };
- // Start video when user stops seeking
- Video_player.prototype
- .stop_seek = function() {
- this.video.play();
- };
- // Update the progressbar (span.loader) according to video.currentTime
- Video_player.prototype
- .update_progress_bar = function() {
- // Get video progress in %
- var value = (100 / this.video.duration) * this.video.currentTime;
- // Update progressbar
- this.progress_bar.style.width = value + '%';
- };
- // Bind progressbar to mouse when seeking
- Video_player.prototype
- .handle_mouse_move = function(event) {
- // Get position of progressbar relative to browser window
- var pos = this.progress_bar.getBoundingClientRect().left;
- // Make sure event is reckonized cross-browser
- event = event || window.event;
- // Update progressbar
- this.progress_bar.style.width = (event.clientX - pos) + "px";
- };
- // Eventlisteners for seeking
- Video_player.prototype
- .video_event_handler = function(videoPlayer, interval) {
- // Update the progress bar
- var animate_progress_bar = setInterval(function () {
- videoPlayer.update_progress_bar();
- }, interval);
- // Fire when input value changes (user seeking)
- videoPlayer.seek_bar
- .addEventListener("change", function() {
- videoPlayer.seeking();
- });
- // Fire when user clicks on seekbar
- videoPlayer.seek_bar
- .addEventListener("mousedown", function (clickEvent) {
- // Pause video playback
- videoPlayer.start_seek();
- // Stop updating progressbar according to video progress
- clearInterval(animate_progress_bar);
- // Update progressbar to where user clicks
- videoPlayer.handle_mouse_move(clickEvent);
- // Bind progressbar to cursor
- window.onmousemove = function(moveEvent){
- videoPlayer.handle_mouse_move(moveEvent);
- };
- });
- // Fire when user releases seekbar
- videoPlayer.seek_bar
- .addEventListener("mouseup", function () {
- // Unbind progressbar from cursor
- window.onmousemove = null;
- // Start video playback
- videoPlayer.stop_seek();
- // Animate the progressbar
- animate_progress_bar = setInterval(function () {
- videoPlayer.update_progress_bar();
- }, interval);
- });
- };
- var videoPlayer = new Video_player('video_1');
- videoPlayer.video_event_handler(videoPlayer, 17);
- }
- angular.module("umbraco").controller("Umbraco.Dashboard.FormsDashboardController", FormsController);
- function startupLatestEditsController($scope) {
- }
- angular.module("umbraco").controller("Umbraco.Dashboard.StartupLatestEditsController", startupLatestEditsController);
- function MediaFolderBrowserDashboardController($rootScope, $scope, assetsService, $routeParams, $timeout, $element, $location, umbRequestHelper,navigationService, mediaResource, $cookies) {
- var dialogOptions = $scope.dialogOptions;
- $scope.filesUploading = [];
- $scope.nodeId = -1;
- $scope.onUploadComplete = function () {
- navigationService.reloadSection("media");
- }
- }
- angular.module("umbraco").controller("Umbraco.Dashboard.MediaFolderBrowserDashboardController", MediaFolderBrowserDashboardController);
- function ChangePasswordDashboardController($scope, xmlhelper, $log, currentUserResource, formHelper) {
- //create the initial model for change password property editor
- $scope.changePasswordModel = {
- alias: "_umb_password",
- view: "changepassword",
- config: {},
- value: {}
- };
- //go get the config for the membership provider and add it to the model
- currentUserResource.getMembershipProviderConfig().then(function(data) {
- $scope.changePasswordModel.config = data;
- //ensure the hasPassword config option is set to true (the user of course has a password already assigned)
- //this will ensure the oldPassword is shown so they can change it
- $scope.changePasswordModel.config.hasPassword = true;
- $scope.changePasswordModel.config.disableToggle = true;
- });
- ////this is the model we will pass to the service
- //$scope.profile = {};
- $scope.changePassword = function() {
- if (formHelper.submitForm({ scope: $scope })) {
- currentUserResource.changePassword($scope.changePasswordModel.value).then(function(data) {
- //if the password has been reset, then update our model
- if (data.value) {
- $scope.changePasswordModel.value.generatedPassword = data.value;
- }
- formHelper.resetForm({ scope: $scope, notifications: data.notifications });
- }, function (err) {
- formHelper.handleError(err);
- });
- }
- };
- }
- angular.module("umbraco").controller("Umbraco.Dashboard.StartupChangePasswordController", ChangePasswordDashboardController);
- function examineMgmtController($scope, umbRequestHelper, $log, $http, $q, $timeout) {
- $scope.indexerDetails = [];
- $scope.searcherDetails = [];
- $scope.loading = true;
- function checkProcessing(indexer, checkActionName) {
- umbRequestHelper.resourcePromise(
- $http.post(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", checkActionName, { indexerName: indexer.name })),
- 'Failed to check index processing')
- .then(function(data) {
- if (data) {
- //copy all resulting properties
- for (var k in data) {
- indexer[k] = data[k];
- }
- indexer.isProcessing = false;
- }
- else {
- $timeout(function () {
- //don't continue if we've tried 100 times
- if (indexer.processingAttempts < 100) {
- checkProcessing(indexer, checkActionName);
- //add an attempt
- indexer.processingAttempts++;
- }
- else {
- //we've exceeded 100 attempts, stop processing
- indexer.isProcessing = false;
- }
- }, 1000);
- }
- });
- }
- $scope.search = function (searcher, e) {
- if (e && e.keyCode !== 13) {
- return;
- }
- umbRequestHelper.resourcePromise(
- $http.get(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "GetSearchResults", {
- searcherName: searcher.name,
- query: searcher.searchText,
- queryType: searcher.searchType
- })),
- 'Failed to search')
- .then(function(searchResults) {
- searcher.isSearching = true;
- searcher.searchResults = searchResults;
- });
- }
- $scope.toggle = function(provider, propName) {
- if (provider[propName] !== undefined) {
- provider[propName] = !provider[propName];
- }
- else {
- provider[propName] = true;
- }
- }
- $scope.rebuildIndex = function(indexer) {
- if (confirm("This will cause the index to be rebuilt. " +
- "Depending on how much content there is in your site this could take a while. " +
- "It is not recommended to rebuild an index during times of high website traffic " +
- "or when editors are editing content.")) {
- indexer.isProcessing = true;
- umbRequestHelper.resourcePromise(
- $http.post(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "PostRebuildIndex", { indexerName: indexer.name })),
- 'Failed to rebuild index')
- .then(function () {
- //rebuilding has started, nothing is returned accept a 200 status code.
- //lets poll to see if it is done.
- $timeout(function () {
- checkProcessing(indexer, "PostCheckRebuildIndex");
- }, 1000);
- });
- }
- }
- $scope.optimizeIndex = function(indexer) {
- if (confirm("This will cause the index to be optimized which will improve its performance. " +
- "It is not recommended to optimize an index during times of high website traffic " +
- "or when editors are editing content.")) {
- indexer.isProcessing = true;
- umbRequestHelper.resourcePromise(
- $http.post(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "PostOptimizeIndex", { indexerName: indexer.name })),
- 'Failed to optimize index')
- .then(function () {
- //optimizing has started, nothing is returned accept a 200 status code.
- //lets poll to see if it is done.
- $timeout(function () {
- checkProcessing(indexer, "PostCheckOptimizeIndex");
- }, 1000);
- });
- }
- }
- $scope.closeSearch = function(searcher) {
- searcher.isSearching = true;
- }
- //go get the data
- //combine two promises and execute when they are both done
- $q.all([
- //get the indexer details
- umbRequestHelper.resourcePromise(
- $http.get(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "GetIndexerDetails")),
- 'Failed to retrieve indexer details')
- .then(function(data) {
- $scope.indexerDetails = data;
- }),
- //get the searcher details
- umbRequestHelper.resourcePromise(
- $http.get(umbRequestHelper.getApiUrl("examineMgmtBaseUrl", "GetSearcherDetails")),
- 'Failed to retrieve searcher details')
- .then(function(data) {
- $scope.searcherDetails = data;
- for (var s in $scope.searcherDetails) {
- $scope.searcherDetails[s].searchType = "text";
- }
- })
- ]).then(function () {
- //all init loading is complete
- $scope.loading = false;
- });
- }
- angular.module("umbraco").controller("Umbraco.Dashboard.ExamineMgmtController", examineMgmtController);
- function xmlDataIntegrityReportController($scope, umbRequestHelper, $log, $http, $q, $timeout) {
- function check(item) {
- var action = item.check;
- umbRequestHelper.resourcePromise(
- $http.get(umbRequestHelper.getApiUrl("xmlDataIntegrityBaseUrl", action)),
- 'Failed to retrieve data integrity status')
- .then(function(result) {
- item.checking = false;
- item.invalid = result === "false";
- });
- }
- $scope.fix = function(item) {
- var action = item.fix;
- if (item.fix) {
- if (confirm("This will cause all xml structures for this type to be rebuilt. " +
- "Depending on how much content there is in your site this could take a while. " +
- "It is not recommended to rebuild xml structures if they are not out of sync, during times of high website traffic " +
- "or when editors are editing content.")) {
- item.fixing = true;
- umbRequestHelper.resourcePromise(
- $http.post(umbRequestHelper.getApiUrl("xmlDataIntegrityBaseUrl", action)),
- 'Failed to retrieve data integrity status')
- .then(function (result) {
- item.fixing = false;
- item.invalid = result === "false";
- });
- }
- }
- }
- $scope.items = {
- "contentXml": {
- label: "Content in the cmsContentXml table",
- checking: true,
- fixing: false,
- fix: "FixContentXmlTable",
- check: "CheckContentXmlTable"
- },
- "mediaXml": {
- label: "Media in the cmsContentXml table",
- checking: true,
- fixing: false,
- fix: "FixMediaXmlTable",
- check: "CheckMediaXmlTable"
- },
- "memberXml": {
- label: "Members in the cmsContentXml table",
- checking: true,
- fixing: false,
- fix: "FixMembersXmlTable",
- check: "CheckMembersXmlTable"
- }
- };
- for (var i in $scope.items) {
- check($scope.items[i]);
- }
- }
- angular.module("umbraco").controller("Umbraco.Dashboard.XmlDataIntegrityReportController", xmlDataIntegrityReportController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.ContentDeleteController
- * @function
- *
- * @description
- * The controller for deleting content
- */
- function DataTypeDeleteController($scope, dataTypeResource, treeService, navigationService) {
- $scope.performDelete = function() {
- //mark it for deletion (used in the UI)
- $scope.currentNode.loading = true;
- dataTypeResource.deleteById($scope.currentNode.id).then(function () {
- $scope.currentNode.loading = false;
- //get the root node before we remove it
- var rootNode = treeService.getTreeRoot($scope.currentNode);
- //TODO: Need to sync tree, etc...
- treeService.removeNode($scope.currentNode);
- navigationService.hideMenu();
- });
- };
- $scope.cancel = function() {
- navigationService.hideDialog();
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.DataType.DeleteController", DataTypeDeleteController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.DataType.EditController
- * @function
- *
- * @description
- * The controller for the content editor
- */
- function DataTypeEditController($scope, $routeParams, $location, appState, navigationService, treeService, dataTypeResource, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, formHelper, editorState) {
- //setup scope vars
- $scope.currentSection = appState.getSectionState("currentSection");
- $scope.currentNode = null; //the editors affiliated node
- //method used to configure the pre-values when we retrieve them from the server
- function createPreValueProps(preVals) {
- $scope.preValues = [];
- for (var i = 0; i < preVals.length; i++) {
- $scope.preValues.push({
- hideLabel: preVals[i].hideLabel,
- alias: preVals[i].key,
- description: preVals[i].description,
- label: preVals[i].label,
- view: preVals[i].view,
- value: preVals[i].value
- });
- }
- }
- //set up the standard data type props
- $scope.properties = {
- selectedEditor: {
- alias: "selectedEditor",
- description: "Select a property editor",
- label: "Property editor"
- },
- selectedEditorId: {
- alias: "selectedEditorId",
- label: "Property editor alias"
- }
- };
- //setup the pre-values as props
- $scope.preValues = [];
- if ($routeParams.create) {
- //we are creating so get an empty data type item
- dataTypeResource.getScaffold()
- .then(function(data) {
- $scope.loaded = true;
- $scope.preValuesLoaded = true;
- $scope.content = data;
- //set a shared state
- editorState.set($scope.content);
- });
- }
- else {
- //we are editing so get the content item from the server
- dataTypeResource.getById($routeParams.id)
- .then(function(data) {
- $scope.loaded = true;
- $scope.preValuesLoaded = true;
- $scope.content = data;
- createPreValueProps($scope.content.preValues);
- //share state
- editorState.set($scope.content);
- //in one particular special case, after we've created a new item we redirect back to the edit
- // route but there might be server validation errors in the collection which we need to display
- // after the redirect, so we will bind all subscriptions which will show the server validation errors
- // if there are any and then clear them so the collection no longer persists them.
- serverValidationManager.executeAndClearAllSubscriptions();
- navigationService.syncTree({ tree: "datatype", path: [String(data.id)] }).then(function (syncArgs) {
- $scope.currentNode = syncArgs.node;
- });
- });
- }
- $scope.$watch("content.selectedEditor", function (newVal, oldVal) {
- //when the value changes, we need to dynamically load in the new editor
- if (newVal && (newVal != oldVal && (oldVal || $routeParams.create))) {
- //we are editing so get the content item from the server
- var currDataTypeId = $routeParams.create ? undefined : $routeParams.id;
- dataTypeResource.getPreValues(newVal, currDataTypeId)
- .then(function (data) {
- $scope.preValuesLoaded = true;
- $scope.content.preValues = data;
- createPreValueProps($scope.content.preValues);
- //share state
- editorState.set($scope.content);
- });
- }
- });
- $scope.save = function() {
- if (formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
- dataTypeResource.save($scope.content, $scope.preValues, $routeParams.create)
- .then(function(data) {
- formHelper.resetForm({ scope: $scope, notifications: data.notifications });
- contentEditingHelper.handleSuccessfulSave({
- scope: $scope,
- savedContent: data,
- rebindCallback: function() {
- createPreValueProps(data.preValues);
- }
- });
- //share state
- editorState.set($scope.content);
- navigationService.syncTree({ tree: "datatype", path: [String(data.id)], forceReload: true }).then(function (syncArgs) {
- $scope.currentNode = syncArgs.node;
- });
- }, function(err) {
- //NOTE: in the case of data type values we are setting the orig/new props
- // to be the same thing since that only really matters for content/media.
- contentEditingHelper.handleSaveError({
- redirectOnFailure: false,
- err: err
- });
- //share state
- editorState.set($scope.content);
- });
- }
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.DataType.EditController", DataTypeEditController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Media.CreateController
- * @function
- *
- * @description
- * The controller for the media creation dialog
- */
- function mediaCreateController($scope, $routeParams, mediaTypeResource, iconHelper) {
- mediaTypeResource.getAllowedTypes($scope.currentNode.id).then(function(data) {
- $scope.allowedTypes = iconHelper.formatContentTypeIcons(data);
- });
- }
- angular.module('umbraco').controller("Umbraco.Editors.Media.CreateController", mediaCreateController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.ContentDeleteController
- * @function
- *
- * @description
- * The controller for deleting content
- */
- function MediaDeleteController($scope, mediaResource, treeService, navigationService, editorState, $location) {
- $scope.performDelete = function() {
- //mark it for deletion (used in the UI)
- $scope.currentNode.loading = true;
- mediaResource.deleteById($scope.currentNode.id).then(function () {
- $scope.currentNode.loading = false;
- //get the root node before we remove it
- var rootNode = treeService.getTreeRoot($scope.currentNode);
- treeService.removeNode($scope.currentNode);
- if (rootNode) {
- //ensure the recycle bin has child nodes now
- var recycleBin = treeService.getDescendantNode(rootNode, -21);
- if (recycleBin) {
- recycleBin.hasChildren = true;
- }
- }
- //if the current edited item is the same one as we're deleting, we need to navigate elsewhere
- if (editorState.current && editorState.current.id == $scope.currentNode.id) {
- $location.path("/media/media/edit/" + $scope.currentNode.parentId);
- }
- navigationService.hideMenu();
- },function() {
- $scope.currentNode.loading = false;
- });
- };
- $scope.cancel = function() {
- navigationService.hideDialog();
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.Media.DeleteController", MediaDeleteController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Media.EditController
- * @function
- *
- * @description
- * The controller for the media editor
- */
- function mediaEditController($scope, $routeParams, appState, mediaResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, treeService, formHelper, umbModelMapper, editorState, umbRequestHelper, $http) {
- //setup scope vars
- $scope.currentSection = appState.getSectionState("currentSection");
- $scope.currentNode = null; //the editors affiliated node
- /** Syncs the content item to it's tree node - this occurs on first load and after saving */
- function syncTreeNode(content, path, initialLoad) {
- if (!$scope.content.isChildOfListView) {
- navigationService.syncTree({ tree: "media", path: path.split(","), forceReload: initialLoad !== true }).then(function (syncArgs) {
- $scope.currentNode = syncArgs.node;
- });
- }
- else if (initialLoad === true) {
- //it's a child item, just sync the ui node to the parent
- navigationService.syncTree({ tree: "media", path: path.substring(0, path.lastIndexOf(",")).split(","), forceReload: initialLoad !== true });
- //if this is a child of a list view and it's the initial load of the editor, we need to get the tree node
- // from the server so that we can load in the actions menu.
- umbRequestHelper.resourcePromise(
- $http.get(content.treeNodeUrl),
- 'Failed to retrieve data for child node ' + content.id).then(function (node) {
- $scope.currentNode = node;
- });
- }
- }
- if ($routeParams.create) {
- mediaResource.getScaffold($routeParams.id, $routeParams.doctype)
- .then(function (data) {
- $scope.loaded = true;
- $scope.content = data;
- editorState.set($scope.content);
- });
- }
- else {
- mediaResource.getById($routeParams.id)
- .then(function (data) {
- $scope.loaded = true;
- $scope.content = data;
- if (data.isChildOfListView && data.trashed === false) {
- $scope.listViewPath = ($routeParams.page)
- ? "/media/media/edit/" + data.parentId + "?page=" + $routeParams.page
- : "/media/media/edit/" + data.parentId;
- }
- editorState.set($scope.content);
- //in one particular special case, after we've created a new item we redirect back to the edit
- // route but there might be server validation errors in the collection which we need to display
- // after the redirect, so we will bind all subscriptions which will show the server validation errors
- // if there are any and then clear them so the collection no longer persists them.
- serverValidationManager.executeAndClearAllSubscriptions();
- syncTreeNode($scope.content, data.path, true);
- if ($scope.content.parentId && $scope.content.parentId != -1) {
- //We fetch all ancestors of the node to generate the footer breadcrump navigation
- entityResource.getAncestors($routeParams.id, "media")
- .then(function (anc) {
- $scope.ancestors = anc;
- });
- }
- });
- }
- $scope.save = function () {
- if (!$scope.busy && formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
- $scope.busy = true;
- mediaResource.save($scope.content, $routeParams.create, fileManager.getFiles())
- .then(function(data) {
- formHelper.resetForm({ scope: $scope, notifications: data.notifications });
- contentEditingHelper.handleSuccessfulSave({
- scope: $scope,
- savedContent: data,
- rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
- });
- editorState.set($scope.content);
- $scope.busy = false;
- syncTreeNode($scope.content, data.path);
- }, function(err) {
- contentEditingHelper.handleSaveError({
- err: err,
- redirectOnFailure: true,
- rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
- });
- editorState.set($scope.content);
- $scope.busy = false;
- });
- }else{
- $scope.busy = false;
- }
- };
- }
- angular.module("umbraco")
- .controller("Umbraco.Editors.Media.EditController", mediaEditController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Media.EmptyRecycleBinController
- * @function
- *
- * @description
- * The controller for deleting media
- */
- function MediaEmptyRecycleBinController($scope, mediaResource, treeService, navigationService) {
- $scope.performDelete = function() {
- //(used in the UI)
- $scope.currentNode.loading = true;
- mediaResource.emptyRecycleBin($scope.currentNode.id).then(function () {
- $scope.currentNode.loading = false;
- //TODO: Need to sync tree, etc...
- treeService.removeChildNodes($scope.currentNode);
- navigationService.hideMenu();
- });
- };
- $scope.cancel = function() {
- navigationService.hideDialog();
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.Media.EmptyRecycleBinController", MediaEmptyRecycleBinController);
- //used for the media picker dialog
- angular.module("umbraco").controller("Umbraco.Editors.Media.MoveController",
- function ($scope, eventsService, mediaResource, appState, treeService, navigationService) {
- var dialogOptions = $scope.dialogOptions;
- $scope.dialogTreeEventHandler = $({});
- var node = dialogOptions.currentNode;
- function nodeSelectHandler(ev, args) {
- args.event.preventDefault();
- args.event.stopPropagation();
- eventsService.emit("editors.media.moveController.select", args);
- if ($scope.target) {
- //un-select if there's a current one selected
- $scope.target.selected = false;
- }
- $scope.target = args.node;
- $scope.target.selected = true;
- }
- $scope.dialogTreeEventHandler.bind("treeNodeSelect", nodeSelectHandler);
- $scope.move = function () {
- mediaResource.move({ parentId: $scope.target.id, id: node.id })
- .then(function (path) {
- $scope.error = false;
- $scope.success = true;
- //first we need to remove the node that launched the dialog
- treeService.removeNode($scope.currentNode);
- //get the currently edited node (if any)
- var activeNode = appState.getTreeState("selectedNode");
- //we need to do a double sync here: first sync to the moved content - but don't activate the node,
- //then sync to the currenlty edited content (note: this might not be the content that was moved!!)
- navigationService.syncTree({ tree: "media", path: path, forceReload: true, activate: false }).then(function (args) {
- if (activeNode) {
- var activeNodePath = treeService.getPath(activeNode).join();
- //sync to this node now - depending on what was copied this might already be synced but might not be
- navigationService.syncTree({ tree: "media", path: activeNodePath, forceReload: false, activate: true });
- }
- });
- }, function (err) {
- $scope.success = false;
- $scope.error = err;
- });
- };
- $scope.$on('$destroy', function () {
- $scope.dialogTreeEventHandler.unbind("treeNodeSelect", nodeSelectHandler);
- });
- });
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Content.MediaRecycleBinController
- * @function
- *
- * @description
- * Controls the recycle bin for media
- *
- */
- function MediaRecycleBinController($scope, $routeParams, dataTypeResource) {
- //ensures the list view doesn't actually load until we query for the list view config
- // for the section
- $scope.listViewPath = null;
- $routeParams.id = "-21";
- dataTypeResource.getById(-96).then(function (result) {
- _.each(result.preValues, function (i) {
- $scope.model.config[i.key] = i.value;
- });
- $scope.listViewPath = 'views/propertyeditors/listview/listview.html';
- });
- $scope.model = { config: { entityType: $routeParams.section } };
- }
- angular.module('umbraco').controller("Umbraco.Editors.Media.RecycleBinController", MediaRecycleBinController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Member.CreateController
- * @function
- *
- * @description
- * The controller for the member creation dialog
- */
- function memberCreateController($scope, $routeParams, memberTypeResource, iconHelper) {
- memberTypeResource.getTypes($scope.currentNode.id).then(function (data) {
- $scope.allowedTypes = iconHelper.formatContentTypeIcons(data);
- });
- }
- angular.module('umbraco').controller("Umbraco.Editors.Member.CreateController", memberCreateController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Member.DeleteController
- * @function
- *
- * @description
- * The controller for deleting content
- */
- function MemberDeleteController($scope, memberResource, treeService, navigationService, editorState, $location, $routeParams) {
- $scope.performDelete = function() {
- //mark it for deletion (used in the UI)
- $scope.currentNode.loading = true;
- memberResource.deleteByKey($scope.currentNode.id).then(function () {
- $scope.currentNode.loading = false;
- treeService.removeNode($scope.currentNode);
- //if the current edited item is the same one as we're deleting, we need to navigate elsewhere
- if (editorState.current && editorState.current.key == $scope.currentNode.id) {
- $location.path("/member/member/list/" + ($routeParams.listName ? $routeParams.listName : 'all-members'));
- }
- navigationService.hideMenu();
- });
- };
- $scope.cancel = function() {
- navigationService.hideDialog();
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.Member.DeleteController", MemberDeleteController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Member.EditController
- * @function
- *
- * @description
- * The controller for the member editor
- */
- function MemberEditController($scope, $routeParams, $location, $q, $window, appState, memberResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, umbModelMapper, editorState, umbRequestHelper, $http) {
- //setup scope vars
- $scope.currentSection = appState.getSectionState("currentSection");
- $scope.currentNode = null; //the editors affiliated node
- $scope.listViewPath = ($routeParams.page && $routeParams.listName)
- ? "/member/member/list/" + $routeParams.listName + "?page=" + $routeParams.page
- : null;
- //build a path to sync the tree with
- function buildTreePath(data) {
- return $routeParams.listName ? "-1," + $routeParams.listName : "-1";
- }
- if ($routeParams.create) {
- //if there is no doc type specified then we are going to assume that
- // we are not using the umbraco membership provider
- if ($routeParams.doctype) {
- //we are creating so get an empty member item
- memberResource.getScaffold($routeParams.doctype)
- .then(function(data) {
- $scope.loaded = true;
- $scope.content = data;
- editorState.set($scope.content);
- });
- }
- else {
- memberResource.getScaffold()
- .then(function (data) {
- $scope.loaded = true;
- $scope.content = data;
- editorState.set($scope.content);
- });
- }
- }
- else {
- //so, we usually refernce all editors with the Int ID, but with members we have
- //a different pattern, adding a route-redirect here to handle this:
- //isNumber doesnt work here since its seen as a string
- //TODO: Why is this here - I don't understand why this would ever be an integer? This will not work when we support non-umbraco membership providers.
- if ($routeParams.id && $routeParams.id.length < 9) {
- entityResource.getById($routeParams.id, "Member").then(function(entity) {
- $location.path("member/member/edit/" + entity.key);
- });
- }
- else {
- //we are editing so get the content item from the server
- memberResource.getByKey($routeParams.id)
- .then(function(data) {
- $scope.loaded = true;
- $scope.content = data;
- editorState.set($scope.content);
- var path = buildTreePath(data);
- //sync the tree (only for ui purposes)
- navigationService.syncTree({ tree: "member", path: path.split(",") });
- //it's the initial load of the editor, we need to get the tree node
- // from the server so that we can load in the actions menu.
- umbRequestHelper.resourcePromise(
- $http.get(data.treeNodeUrl),
- 'Failed to retrieve data for child node ' + data.key).then(function (node) {
- $scope.currentNode = node;
- });
- //in one particular special case, after we've created a new item we redirect back to the edit
- // route but there might be server validation errors in the collection which we need to display
- // after the redirect, so we will bind all subscriptions which will show the server validation errors
- // if there are any and then clear them so the collection no longer persists them.
- serverValidationManager.executeAndClearAllSubscriptions();
- });
- }
- }
- $scope.save = function() {
- if (!$scope.busy && formHelper.submitForm({ scope: $scope, statusMessage: "Saving..." })) {
- $scope.busy = true;
- memberResource.save($scope.content, $routeParams.create, fileManager.getFiles())
- .then(function(data) {
- formHelper.resetForm({ scope: $scope, notifications: data.notifications });
- contentEditingHelper.handleSuccessfulSave({
- scope: $scope,
- savedContent: data,
- //specify a custom id to redirect to since we want to use the GUID
- redirectId: data.key,
- rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, data)
- });
- editorState.set($scope.content);
- $scope.busy = false;
- var path = buildTreePath(data);
- //sync the tree (only for ui purposes)
- navigationService.syncTree({ tree: "member", path: path.split(","), forceReload: true });
- }, function (err) {
- contentEditingHelper.handleSaveError({
- redirectOnFailure: false,
- err: err,
- rebindCallback: contentEditingHelper.reBindChangedProperties($scope.content, err.data)
- });
- editorState.set($scope.content);
- $scope.busy = false;
- });
- }else{
- $scope.busy = false;
- }
- };
- }
- angular.module("umbraco").controller("Umbraco.Editors.Member.EditController", MemberEditController);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.Member.ListController
- * @function
- *
- * @description
- * The controller for the member list view
- */
- function MemberListController($scope, $routeParams, $location, $q, $window, appState, memberResource, entityResource, navigationService, notificationsService, angularHelper, serverValidationManager, contentEditingHelper, fileManager, formHelper, umbModelMapper, editorState) {
- //setup scope vars
- $scope.currentSection = appState.getSectionState("currentSection");
- $scope.currentNode = null; //the editors affiliated node
- //we are editing so get the content item from the server
- memberResource.getListNode($routeParams.id)
- .then(function (data) {
- $scope.loaded = true;
- $scope.content = data;
- editorState.set($scope.content);
- navigationService.syncTree({ tree: "member", path: data.path.split(",") }).then(function (syncArgs) {
- $scope.currentNode = syncArgs.node;
- });
- //in one particular special case, after we've created a new item we redirect back to the edit
- // route but there might be server validation errors in the collection which we need to display
- // after the redirect, so we will bind all subscriptions which will show the server validation errors
- // if there are any and then clear them so the collection no longer persists them.
- serverValidationManager.executeAndClearAllSubscriptions();
- });
- }
- angular.module("umbraco").controller("Umbraco.Editors.Member.ListController", MemberListController);
- function imageFilePickerController($scope, dialogService, mediaHelper) {
- $scope.pick = function() {
- dialogService.mediaPicker({
- multiPicker: false,
- callback: function(data) {
- $scope.model.value = mediaHelper.resolveFile(data, false);
- }
- });
- };
- }
- angular.module('umbraco').controller("Umbraco.PrevalueEditors.ImageFilePickerController",imageFilePickerController);
- //this controller simply tells the dialogs service to open a mediaPicker window
- //with a specified callback, this callback will receive an object with a selection on it
- function mediaPickerController($scope, dialogService, entityResource, $log, iconHelper) {
- function trim(str, chr) {
- var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
- return str.replace(rgxtrim, '');
- }
- $scope.renderModel = [];
- var dialogOptions = {
- multiPicker: false,
- entityType: "Media",
- section: "media",
- treeAlias: "media",
- callback: function(data) {
- if (angular.isArray(data)) {
- _.each(data, function (item, i) {
- $scope.add(item);
- });
- }
- else {
- $scope.clear();
- $scope.add(data);
- }
- }
- };
- $scope.openContentPicker = function(){
- var d = dialogService.treePicker(dialogOptions);
- };
- $scope.remove =function(index){
- $scope.renderModel.splice(index, 1);
- };
- $scope.clear = function() {
- $scope.renderModel = [];
- };
- $scope.add = function (item) {
- var currIds = _.map($scope.renderModel, function (i) {
- return i.id;
- });
- if (currIds.indexOf(item.id) < 0) {
- item.icon = iconHelper.convertFromLegacyIcon(item.icon);
- $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
- }
- };
- var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
- var currIds = _.map($scope.renderModel, function (i) {
- return i.id;
- });
- $scope.model.value = trim(currIds.join(), ",");
- });
- //when the scope is destroyed we need to unsubscribe
- $scope.$on('$destroy', function () {
- unsubscribe();
- });
- //load media data
- var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
- entityResource.getByIds(modelIds, dialogOptions.entityType).then(function (data) {
- _.each(data, function (item, i) {
- item.icon = iconHelper.convertFromLegacyIcon(item.icon);
- $scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
- });
- });
- }
- angular.module('umbraco').controller("Umbraco.PrevalueEditors.MediaPickerController",mediaPickerController);
- angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiValuesController",
- function ($scope, $timeout) {
- //NOTE: We need to make each item an object, not just a string because you cannot 2-way bind to a primitive.
- $scope.newItem = "";
- $scope.hasError = false;
- if (!angular.isArray($scope.model.value)) {
- //make an array from the dictionary
- var items = [];
- for (var i in $scope.model.value) {
- items.push({
- value: $scope.model.value[i].value,
- sortOrder: $scope.model.value[i].sortOrder,
- id: i
- });
- }
- //ensure the items are sorted by the provided sort order
- items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });
- //now make the editor model the array
- $scope.model.value = items;
- }
- $scope.remove = function(item, evt) {
- evt.preventDefault();
- $scope.model.value = _.reject($scope.model.value, function (x) {
- return x.value === item.value;
- });
- };
- $scope.add = function (evt) {
- evt.preventDefault();
- if ($scope.newItem) {
- if (!_.contains($scope.model.value, $scope.newItem)) {
- $scope.model.value.push({ value: $scope.newItem });
- $scope.newItem = "";
- $scope.hasError = false;
- return;
- }
- }
- //there was an error, do the highlight (will be set back by the directive)
- $scope.hasError = true;
- };
- $scope.sortableOptions = {
- axis: 'y',
- containment: 'parent',
- cursor: 'move',
- items: '> div.control-group',
- tolerance: 'pointer',
- update: function (e, ui) {
- // Get the new and old index for the moved element (using the text as the identifier, so
- // we'd have a problem if two prevalues were the same, but that would be unlikely)
- var newIndex = ui.item.index();
- var movedPrevalueText = $('input[type="text"]', ui.item).val();
- var originalIndex = getElementIndexByPrevalueText(movedPrevalueText);
- // Move the element in the model
- if (originalIndex > -1) {
- var movedElement = $scope.model.value[originalIndex];
- $scope.model.value.splice(originalIndex, 1);
- $scope.model.value.splice(newIndex, 0, movedElement);
- }
- }
- };
- function getElementIndexByPrevalueText(value) {
- for (var i = 0; i < $scope.model.value.length; i++) {
- if ($scope.model.value[i].value === value) {
- return i;
- }
- }
- return -1;
- }
- });
- //this controller simply tells the dialogs service to open a mediaPicker window
- //with a specified callback, this callback will receive an object with a selection on it
- angular.module('umbraco')
- .controller("Umbraco.PrevalueEditors.TreePickerController",
- function($scope, dialogService, entityResource, $log, iconHelper){
- $scope.renderModel = [];
- $scope.ids = [];
- var config = {
- multiPicker: false,
- entityType: "Document",
- type: "content",
- treeAlias: "content"
- };
- if($scope.model.value){
- $scope.ids = $scope.model.value.split(',');
- entityResource.getByIds($scope.ids, config.entityType).then(function (data) {
- _.each(data, function (item, i) {
- item.icon = iconHelper.convertFromLegacyIcon(item.icon);
- $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
- });
- });
- }
- $scope.openContentPicker =function() {
- var d = dialogService.treePicker({
- section: config.type,
- treeAlias: config.type,
- multiPicker: config.multiPicker,
- callback: populate
- });
- };
- $scope.remove =function(index){
- $scope.renderModel.splice(index, 1);
- $scope.ids.splice(index, 1);
- $scope.model.value = trim($scope.ids.join(), ",");
- };
- $scope.clear = function() {
- $scope.model.value = "";
- $scope.renderModel = [];
- $scope.ids = [];
- };
- $scope.add =function(item){
- if($scope.ids.indexOf(item.id) < 0){
- item.icon = iconHelper.convertFromLegacyIcon(item.icon);
- $scope.ids.push(item.id);
- $scope.renderModel.push({name: item.name, id: item.id, icon: item.icon});
- $scope.model.value = trim($scope.ids.join(), ",");
- }
- };
- var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
- $scope.model.value = trim($scope.ids.join(), ",");
- });
- //when the scope is destroyed we need to unsubscribe
- $scope.$on('$destroy', function () {
- unsubscribe();
- });
- function trim(str, chr) {
- var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^'+chr+'+|'+chr+'+$', 'g');
- return str.replace(rgxtrim, '');
- }
- function populate(data){
- if(angular.isArray(data)){
- _.each(data, function (item, i) {
- $scope.add(item);
- });
- }else{
- $scope.clear();
- $scope.add(data);
- }
- }
- });
- //this controller simply tells the dialogs service to open a mediaPicker window
- //with a specified callback, this callback will receive an object with a selection on it
- angular.module('umbraco')
- .controller("Umbraco.PrevalueEditors.TreeSourceController",
- function($scope, dialogService, entityResource, $log, iconHelper){
- if (!$scope.model) {
- $scope.model = {};
- }
- if (!$scope.model.value) {
- $scope.model.value = {
- type: "content"
- };
- }
- if($scope.model.value.id && $scope.model.value.type !== "member"){
- var ent = "Document";
- if($scope.model.value.type === "media"){
- ent = "Media";
- }
- entityResource.getById($scope.model.value.id, ent).then(function(item){
- item.icon = iconHelper.convertFromLegacyIcon(item.icon);
- $scope.node = item;
- });
- }
- $scope.openContentPicker =function(){
- var d = dialogService.treePicker({
- section: $scope.model.value.type,
- treeAlias: $scope.model.value.type,
- multiPicker: false,
- callback: populate});
- };
- $scope.clear = function() {
- $scope.model.value.id = undefined;
- $scope.node = undefined;
- $scope.model.value.query = undefined;
- };
- //we always need to ensure we dont submit anything broken
- var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
- if($scope.model.value.type === "member"){
- $scope.model.value.id = -1;
- $scope.model.value.query = "";
- }
- });
- //when the scope is destroyed we need to unsubscribe
- $scope.$on('$destroy', function () {
- unsubscribe();
- });
- function populate(item){
- $scope.clear();
- item.icon = iconHelper.convertFromLegacyIcon(item.icon);
- $scope.node = item;
- $scope.model.value.id = item.id;
- }
- });
- function booleanEditorController($scope, $rootScope, assetsService) {
- function setupViewModel() {
- $scope.renderModel = {
- value: false
- };
- if ($scope.model && $scope.model.value && ($scope.model.value.toString() === "1" || angular.lowercase($scope.model.value) === "true")) {
- $scope.renderModel.value = true;
- }
- }
- setupViewModel();
- $scope.$watch("renderModel.value", function (newVal) {
- $scope.model.value = newVal === true ? "1" : "0";
- });
- //here we declare a special method which will be called whenever the value has changed from the server
- //this is instead of doing a watch on the model.value = faster
- $scope.model.onValueChanged = function (newVal, oldVal) {
- //update the display val again if it has changed from the server
- setupViewModel();
- };
- }
- angular.module("umbraco").controller("Umbraco.PropertyEditors.BooleanController", booleanEditorController);
- angular.module("umbraco").controller("Umbraco.PropertyEditors.ChangePasswordController",
- function ($scope, $routeParams) {
- function resetModel(isNew) {
- //the model config will contain an object, if it does not we'll create defaults
- //NOTE: We will not support doing the password regex on the client side because the regex on the server side
- //based on the membership provider cannot always be ported to js from .net directly.
- /*
- {
- hasPassword: true/false,
- requiresQuestionAnswer: true/false,
- enableReset: true/false,
- enablePasswordRetrieval: true/false,
- minPasswordLength: 10
- }
- */
- //set defaults if they are not available
- if (!$scope.model.config || $scope.model.config.disableToggle === undefined) {
- $scope.model.config.disableToggle = false;
- }
- if (!$scope.model.config || $scope.model.config.hasPassword === undefined) {
- $scope.model.config.hasPassword = false;
- }
- if (!$scope.model.config || $scope.model.config.enablePasswordRetrieval === undefined) {
- $scope.model.config.enablePasswordRetrieval = true;
- }
- if (!$scope.model.config || $scope.model.config.requiresQuestionAnswer === undefined) {
- $scope.model.config.requiresQuestionAnswer = false;
- }
- if (!$scope.model.config || $scope.model.config.enableReset === undefined) {
- $scope.model.config.enableReset = true;
- }
- if (!$scope.model.config || $scope.model.config.minPasswordLength === undefined) {
- $scope.model.config.minPasswordLength = 0;
- }
- //set the model defaults
- if (!angular.isObject($scope.model.value)) {
- //if it's not an object then just create a new one
- $scope.model.value = {
- newPassword: null,
- oldPassword: null,
- reset: null,
- answer: null
- };
- }
- else {
- //just reset the values
- if (!isNew) {
- //if it is new, then leave the generated pass displayed
- $scope.model.value.newPassword = null;
- $scope.model.value.oldPassword = null;
- }
- $scope.model.value.reset = null;
- $scope.model.value.answer = null;
- }
- //the value to compare to match passwords
- if (!isNew) {
- $scope.model.confirm = "";
- }
- else if ($scope.model.value.newPassword.length > 0) {
- //if it is new and a new password has been set, then set the confirm password too
- $scope.model.confirm = $scope.model.value.newPassword;
- }
- }
- resetModel($routeParams.create);
- //if there is no password saved for this entity , it must be new so we do not allow toggling of the change password, it is always there
- //with validators turned on.
- $scope.changing = $scope.model.config.disableToggle === true || !$scope.model.config.hasPassword;
- //we're not currently changing so set the model to null
- if (!$scope.changing) {
- $scope.model.value = null;
- }
- $scope.doChange = function() {
- resetModel();
- $scope.changing = true;
- //if there was a previously generated password displaying, clear it
- $scope.model.value.generatedPassword = null;
- };
- $scope.cancelChange = function() {
- $scope.changing = false;
- //set model to null
- $scope.model.value = null;
- };
- var unsubscribe = [];
- //listen for the saved event, when that occurs we'll
- //change to changing = false;
- unsubscribe.push($scope.$on("formSubmitted", function() {
- if ($scope.model.config.disableToggle === false) {
- $scope.changing = false;
- }
- }));
- unsubscribe.push($scope.$on("formSubmitting", function() {
- //if there was a previously generated password displaying, clear it
- if ($scope.changing && $scope.model.value) {
- $scope.model.value.generatedPassword = null;
- }
- else if (!$scope.changing) {
- //we are not changing, so the model needs to be null
- $scope.model.value = null;
- }
- }));
- //when the scope is destroyed we need to unsubscribe
- $scope.$on('$destroy', function () {
- for (var u in unsubscribe) {
- unsubscribe[u]();
- }
- });
- $scope.showReset = function() {
- return $scope.model.config.hasPassword && $scope.model.config.enableReset;
- };
- $scope.showOldPass = function() {
- return $scope.model.config.hasPassword &&
- !$scope.model.config.allowManuallyChangingPassword &&
- !$scope.model.config.enablePasswordRetrieval && !$scope.model.value.reset;
- };
- $scope.showNewPass = function () {
- return !$scope.model.value.reset;
- };
- $scope.showConfirmPass = function() {
- return !$scope.model.value.reset;
- };
- $scope.showCancelBtn = function() {
- return $scope.model.config.disableToggle !== true && $scope.model.config.hasPassword;
- };
- });
- angular.module("umbraco").controller("Umbraco.PropertyEditors.CheckboxListController",
- function($scope) {
- if (angular.isObject($scope.model.config.items)) {
- //now we need to format the items in the dictionary because we always want to have an array
- var newItems = [];
- var vals = _.values($scope.model.config.items);
- var keys = _.keys($scope.model.config.items);
- for (var i = 0; i < vals.length; i++) {
- newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: vals[i].value });
- }
- //ensure the items are sorted by the provided sort order
- newItems.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });
- //re-assign
- $scope.model.config.items = newItems;
- }
- function setupViewModel() {
- $scope.selectedItems = [];
- //now we need to check if the value is null/undefined, if it is we need to set it to "" so that any value that is set
- // to "" gets selected by default
- if ($scope.model.value === null || $scope.model.value === undefined) {
- $scope.model.value = [];
- }
- for (var i = 0; i < $scope.model.config.items.length; i++) {
- var isChecked = _.contains($scope.model.value, $scope.model.config.items[i].id);
- $scope.selectedItems.push({
- checked: isChecked,
- key: $scope.model.config.items[i].id,
- val: $scope.model.config.items[i].value
- });
- }
- }
- setupViewModel();
- //update the model when the items checked changes
- $scope.$watch("selectedItems", function(newVal, oldVal) {
- $scope.model.value = [];
- for (var x = 0; x < $scope.selectedItems.length; x++) {
- if ($scope.selectedItems[x].checked) {
- $scope.model.value.push($scope.selectedItems[x].key);
- }
- }
- }, true);
- //here we declare a special method which will be called whenever the value has changed from the server
- //this is instead of doing a watch on the model.value = faster
- $scope.model.onValueChanged = function (newVal, oldVal) {
- //update the display val again if it has changed from the server
- setupViewModel();
- };
- });
- function ColorPickerController($scope) {
- $scope.toggleItem = function (color) {
- if ($scope.model.value == color) {
- $scope.model.value = "";
- //this is required to re-validate
- $scope.propertyForm.modelValue.$setViewValue($scope.model.value);
- }
- else {
- $scope.model.value = color;
- //this is required to re-validate
- $scope.propertyForm.modelValue.$setViewValue($scope.model.value);
- }
- };
- // Method required by the valPropertyValidator directive (returns true if the property editor has at least one color selected)
- $scope.validateMandatory = function () {
- return {
- isValid: !$scope.model.validation.mandatory || ($scope.model.value != null && $scope.model.value != ""),
- errorMsg: "Value cannot be empty",
- errorKey: "required"
- };
- }
- $scope.isConfigured = $scope.model.config && $scope.model.config.items && _.keys($scope.model.config.items).length > 0;
- }
- angular.module("umbraco").controller("Umbraco.PropertyEditors.ColorPickerController", ColorPickerController);
- angular.module("umbraco").controller("Umbraco.PrevalueEditors.MultiColorPickerController",
- function ($scope, $timeout, assetsService, angularHelper, $element) {
- //NOTE: We need to make each color an object, not just a string because you cannot 2-way bind to a primitive.
- var defaultColor = "000000";
- $scope.newColor = defaultColor;
- $scope.hasError = false;
- assetsService.load([
- //"lib/spectrum/tinycolor.js",
- "lib/spectrum/spectrum.js"
- ]).then(function () {
- var elem = $element.find("input");
- elem.spectrum({
- color: null,
- showInitial: false,
- chooseText: "choose", // TODO: These can be localised
- cancelText: "cancel", // TODO: These can be localised
- preferredFormat: "hex",
- showInput: true,
- clickoutFiresChange: true,
- hide: function (color) {
- //show the add butotn
- $element.find(".btn.add").show();
- },
- change: function (color) {
- angularHelper.safeApply($scope, function () {
- $scope.newColor = color.toHexString().trimStart("#"); // #ff0000
- });
- },
- show: function() {
- //hide the add butotn
- $element.find(".btn.add").hide();
- }
- });
- });
- if (!angular.isArray($scope.model.value)) {
- //make an array from the dictionary
- var items = [];
- for (var i in $scope.model.value) {
- items.push({
- value: $scope.model.value[i],
- id: i
- });
- }
- //now make the editor model the array
- $scope.model.value = items;
- }
- $scope.remove = function (item, evt) {
- evt.preventDefault();
- $scope.model.value = _.reject($scope.model.value, function (x) {
- return x.value === item.value;
- });
- };
- $scope.add = function (evt) {
- evt.preventDefault();
- if ($scope.newColor) {
- var exists = _.find($scope.model.value, function(item) {
- return item.value.toUpperCase() == $scope.newColor.toUpperCase();
- });
- if (!exists) {
- $scope.model.value.push({ value: $scope.newColor });
- //$scope.newColor = defaultColor;
- // set colorpicker to default color
- //var elem = $element.find("input");
- //elem.spectrum("set", $scope.newColor);
- $scope.hasError = false;
- return;
- }
- //there was an error, do the highlight (will be set back by the directive)
- $scope.hasError = true;
- }
- };
- //load the separate css for the editor to avoid it blocking our js loading
- assetsService.loadCss("lib/spectrum/spectrum.css");
- });
- //this controller simply tells the dialogs service to open a mediaPicker window
- //with a specified callback, this callback will receive an object with a selection on it
- function contentPickerController($scope, dialogService, entityResource, editorState, $log, iconHelper, $routeParams, fileManager, contentEditingHelper) {
- function trim(str, chr) {
- var rgxtrim = (!chr) ? new RegExp('^\\s+|\\s+$', 'g') : new RegExp('^' + chr + '+|' + chr + '+$', 'g');
- return str.replace(rgxtrim, '');
- }
- function startWatch() {
- //We need to watch our renderModel so that we can update the underlying $scope.model.value properly, this is required
- // because the ui-sortable doesn't dispatch an event after the digest of the sort operation. Any of the events for UI sortable
- // occur after the DOM has updated but BEFORE the digest has occured so the model has NOT changed yet - it even states so in the docs.
- // In their source code there is no event so we need to just subscribe to our model changes here.
- //This also makes it easier to manage models, we update one and the rest will just work.
- $scope.$watch(function () {
- //return the joined Ids as a string to watch
- return _.map($scope.renderModel, function (i) {
- return i.id;
- }).join();
- }, function (newVal) {
- var currIds = _.map($scope.renderModel, function (i) {
- return i.id;
- });
- $scope.model.value = trim(currIds.join(), ",");
- //Validate!
- if ($scope.model.config && $scope.model.config.minNumber && parseInt($scope.model.config.minNumber) > $scope.renderModel.length) {
- $scope.contentPickerForm.minCount.$setValidity("minCount", false);
- }
- else {
- $scope.contentPickerForm.minCount.$setValidity("minCount", true);
- }
- if ($scope.model.config && $scope.model.config.maxNumber && parseInt($scope.model.config.maxNumber) < $scope.renderModel.length) {
- $scope.contentPickerForm.maxCount.$setValidity("maxCount", false);
- }
- else {
- $scope.contentPickerForm.maxCount.$setValidity("maxCount", true);
- }
- });
- }
- $scope.renderModel = [];
- $scope.dialogEditor = editorState && editorState.current && editorState.current.isDialogEditor === true;
- //the default pre-values
- var defaultConfig = {
- multiPicker: false,
- showEditButton: false,
- startNode: {
- query: "",
- type: "content",
- id: $scope.model.config.startNodeId ? $scope.model.config.startNodeId : -1 // get start node for simple Content Picker
- }
- };
- if ($scope.model.config) {
- //merge the server config on top of the default config, then set the server config to use the result
- $scope.model.config = angular.extend(defaultConfig, $scope.model.config);
- }
- //Umbraco persists boolean for prevalues as "0" or "1" so we need to convert that!
- $scope.model.config.multiPicker = ($scope.model.config.multiPicker === "1" ? true : false);
- $scope.model.config.showEditButton = ($scope.model.config.showEditButton === "1" ? true : false);
- var entityType = $scope.model.config.startNode.type === "member"
- ? "Member"
- : $scope.model.config.startNode.type === "media"
- ? "Media"
- : "Document";
- //the dialog options for the picker
- var dialogOptions = {
- multiPicker: $scope.model.config.multiPicker,
- entityType: entityType,
- filterCssClass: "not-allowed not-published",
- startNodeId: null,
- callback: function (data) {
- if (angular.isArray(data)) {
- _.each(data, function (item, i) {
- $scope.add(item);
- });
- } else {
- $scope.clear();
- $scope.add(data);
- }
- },
- treeAlias: $scope.model.config.startNode.type,
- section: $scope.model.config.startNode.type
- };
- //since most of the pre-value config's are used in the dialog options (i.e. maxNumber, minNumber, etc...) we'll merge the
- // pre-value config on to the dialog options
- angular.extend(dialogOptions, $scope.model.config);
- //We need to manually handle the filter for members here since the tree displayed is different and only contains
- // searchable list views
- if (entityType === "Member") {
- //first change the not allowed filter css class
- dialogOptions.filterCssClass = "not-allowed";
- var currFilter = dialogOptions.filter;
- //now change the filter to be a method
- dialogOptions.filter = function(i) {
- //filter out the list view nodes
- if (i.metaData.isContainer) {
- return true;
- }
- if (!currFilter) {
- return false;
- }
- //now we need to filter based on what is stored in the pre-vals, this logic duplicates what is in the treepicker.controller,
- // but not much we can do about that since members require special filtering.
- var filterItem = currFilter.toLowerCase().split(',');
- var found = filterItem.indexOf(i.metaData.contentType.toLowerCase()) >= 0;
- if (!currFilter.startsWith("!") && !found || currFilter.startsWith("!") && found) {
- return true;
- }
- return false;
- }
- }
- //if we have a query for the startnode, we will use that.
- if ($scope.model.config.startNode.query) {
- var rootId = $routeParams.id;
- entityResource.getByQuery($scope.model.config.startNode.query, rootId, "Document").then(function (ent) {
- dialogOptions.startNodeId = ent.id;
- });
- } else {
- dialogOptions.startNodeId = $scope.model.config.startNode.id;
- }
- //dialog
- $scope.openContentPicker = function () {
- var d = dialogService.treePicker(dialogOptions);
- };
- $scope.remove = function (index) {
- $scope.renderModel.splice(index, 1);
- };
- $scope.add = function (item) {
- var currIds = _.map($scope.renderModel, function (i) {
- return i.id;
- });
- if (currIds.indexOf(item.id) < 0) {
- item.icon = iconHelper.convertFromLegacyIcon(item.icon);
- $scope.renderModel.push({ name: item.name, id: item.id, icon: item.icon });
- }
- };
- $scope.clear = function () {
- $scope.renderModel = [];
- };
- var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
- var currIds = _.map($scope.renderModel, function (i) {
- return i.id;
- });
- $scope.model.value = trim(currIds.join(), ",");
- });
- //when the scope is destroyed we need to unsubscribe
- $scope.$on('$destroy', function () {
- unsubscribe();
- });
- //load current data
- var modelIds = $scope.model.value ? $scope.model.value.split(',') : [];
- entityResource.getByIds(modelIds, entityType).then(function (data) {
- //Ensure we populate the render model in the same order that the ids were stored!
- _.each(modelIds, function (id, i) {
- var entity = _.find(data, function (d) {
- return d.id == id;
- });
- if(entity) {
- entity.icon = iconHelper.convertFromLegacyIcon(entity.icon);
- $scope.renderModel.push({ name: entity.name, id: entity.id, icon: entity.icon });
- }
- });
- //everything is loaded, start the watch on the model
- startWatch();
- });
- }
- angular.module('umbraco').controller("Umbraco.PropertyEditors.ContentPickerController", contentPickerController);
- function dateTimePickerController($scope, notificationsService, assetsService, angularHelper, userService, $element) {
- //setup the default config
- var config = {
- pickDate: true,
- pickTime: true,
- useSeconds: true,
- format: "YYYY-MM-DD HH:mm:ss",
- icons: {
- time: "icon-time",
- date: "icon-calendar",
- up: "icon-chevron-up",
- down: "icon-chevron-down"
- }
- };
- //map the user config
- $scope.model.config = angular.extend(config, $scope.model.config);
- $scope.hasDatetimePickerValue = $scope.model.value ? true : false;
- $scope.datetimePickerValue = null;
- //hide picker if clicking on the document
- $scope.hidePicker = function () {
- //$element.find("div:first").datetimepicker("hide");
- // Sometimes the statement above fails and generates errors in the browser console. The following statements fix that.
- var dtp = $element.find("div:first");
- if (dtp && dtp.datetimepicker) {
- dtp.datetimepicker("hide");
- }
- };
- $(document).bind("click", $scope.hidePicker);
- //handles the date changing via the api
- function applyDate(e) {
- angularHelper.safeApply($scope, function() {
- // when a date is changed, update the model
- if (e.date && e.date.isValid()) {
- $scope.datePickerForm.datepicker.$setValidity("pickerError", true);
- $scope.hasDatetimePickerValue = true;
- if (!$scope.model.config.format) {
- $scope.datetimePickerValue = e.date;
- }
- else {
- $scope.datetimePickerValue = e.date.format($scope.model.config.format);
- }
- }
- else {
- $scope.hasDatetimePickerValue = false;
- $scope.datetimePickerValue = null;
- }
- if (!$scope.model.config.pickTime) {
- $element.find("div:first").datetimepicker("hide", 0);
- }
- });
- }
- var picker = null;
- $scope.clearDate = function() {
- $scope.hasDatetimePickerValue = false;
- $scope.datetimePickerValue = null;
- $scope.model.value = null;
- $scope.datePickerForm.datepicker.$setValidity("pickerError", true);
- }
- //get the current user to see if we can localize this picker
- userService.getCurrentUser().then(function (user) {
- assetsService.loadCss('lib/datetimepicker/bootstrap-datetimepicker.min.css').then(function() {
- var filesToLoad = ["lib/moment/moment-with-locales.js",
- "lib/datetimepicker/bootstrap-datetimepicker.js"];
- $scope.model.config.language = user.locale;
- assetsService.load(filesToLoad).then(
- function () {
- //The Datepicker js and css files are available and all components are ready to use.
- // Get the id of the datepicker button that was clicked
- var pickerId = $scope.model.alias;
- var element = $element.find("div:first");
- // Open the datepicker and add a changeDate eventlistener
- element
- .datetimepicker(angular.extend({ useCurrent: true }, $scope.model.config))
- .on("dp.change", applyDate)
- .on("dp.error", function(a, b, c) {
- $scope.hasDatetimePickerValue = false;
- $scope.datePickerForm.datepicker.$setValidity("pickerError", false);
- });
- if ($scope.hasDatetimePickerValue) {
- // ----> MML FIX BEGIN http://issues.umbraco.org/issue/U4-6953
- //assign value to plugin/picker
- var dateVal = $scope.model.value ? moment($scope.model.value, $scope.model.config.format) : moment();
- element.datetimepicker("setValue", dateVal);
- $scope.datetimePickerValue = moment($scope.model.value).format($scope.model.config.format);
- // MML FIX END <-----
- }
- element.find("input").bind("blur", function() {
- //we need to force an apply here
- $scope.$apply();
- });
- //Ensure to remove the event handler when this instance is destroyted
- $scope.$on('$destroy', function () {
- element.find("input").unbind("blur");
- element.datetimepicker("destroy");
- });
- });
- });
- });
- var unsubscribe = $scope.$on("formSubmitting", function (ev, args) {
- if ($scope.hasDatetimePickerValue) {
- if ($scope.model.config.pickTime) {
- $scope.model.value = $element.find("div:first").data().DateTimePicker.getDate().format("YYYY-MM-DD HH:mm:ss");
- }
- else {
- $scope.model.value = $element.find("div:first").data().DateTimePicker.getDate().format("YYYY-MM-DD");
- }
- }
- else {
- $scope.model.value = null;
- }
- });
- //unbind doc click event!
- $scope.$on('$destroy', function () {
- $(document).unbind("click", $scope.hidePicker);
- unsubscribe();
- });
- }
- angular.module("umbraco").controller("Umbraco.PropertyEditors.DatepickerController", dateTimePickerController);
- angular.module("umbraco").controller("Umbraco.PropertyEditors.DropdownController",
- function($scope) {
- //setup the default config
- var config = {
- items: [],
- multiple: false
- };
- //map the user config
- angular.extend(config, $scope.model.config);
- //map back to the model
- $scope.model.config = config;
- function convertArrayToDictionaryArray(model){
- //now we need to format the items in the dictionary because we always want to have an array
- var newItems = [];
- for (var i = 0; i < model.length; i++) {
- newItems.push({ id: model[i], sortOrder: 0, value: model[i] });
- }
- return newItems;
- }
- function convertObjectToDictionaryArray(model){
- //now we need to format the items in the dictionary because we always want to have an array
- var newItems = [];
- var vals = _.values($scope.model.config.items);
- var keys = _.keys($scope.model.config.items);
- for (var i = 0; i < vals.length; i++) {
- var label = vals[i].value ? vals[i].value : vals[i];
- newItems.push({ id: keys[i], sortOrder: vals[i].sortOrder, value: label });
- }
- return newItems;
- }
- if (angular.isArray($scope.model.config.items)) {
- //PP: I dont think this will happen, but we have tests that expect it to happen..
- //if array is simple values, convert to array of objects
- if(!angular.isObject($scope.model.config.items[0])){
- $scope.model.config.items = convertArrayToDictionaryArray($scope.model.config.items);
- }
- }
- else if (angular.isObject($scope.model.config.items)) {
- $scope.model.config.items = convertObjectToDictionaryArray($scope.model.config.items);
- }
- else {
- throw "The items property must be either an array or a dictionary";
- }
- //sort the values
- $scope.model.config.items.sort(function (a, b) { return (a.sortOrder > b.sortOrder) ? 1 : ((b.sortOrder > a.sortOrder) ? -1 : 0); });
- //now we need to check if the value is null/undefined, if it is we need to set it to "" so that any value that is set
- // to "" gets selected by default
- if ($scope.model.value === null || $scope.model.value === undefined) {
- if ($scope.model.config.multiple) {
- $scope.model.value = [];
- }
- else {
- $scope.model.value = "";
- }
- }
- });
- /** A drop down list or multi value select list based on an entity type, this can be re-used for any entity types */
- function entityPicker($scope, entityResource) {
- //set the default to DocumentType
- if (!$scope.model.config.entityType) {
- $scope.model.config.entityType = "DocumentType";
- }
- //Determine the select list options and which value to publish
- if (!$scope.model.config.publishBy) {
- $scope.selectOptions = "entity.id as entity.name for entity in entities";
- }
- else {
- $scope.selectOptions = "entity." + $scope.model.config.publishBy + " as entity.name for entity in entities";
- }
- entityResource.getAll($scope.model.config.entityType).then(function (data) {
- //convert the ids to strings so the drop downs work properly when comparing
- _.each(data, function(d) {
- d.id = d.id.toString();
- });
- $scope.entities = data;
- });
- if ($scope.model.value === null || $scope.model.value === undefined) {
- if ($scope.model.config.multiple) {
- $scope.model.value = [];
- }
- else {
- $scope.model.value = "";
- }
- }
- else {
- //if it's multiple, change the value to an array
- if ($scope.model.config.multiple === "1") {
- if (_.isString($scope.model.value)) {
- $scope.model.value = $scope.model.value.split(',');
- }
- }
- }
- }
- angular.module('umbraco').controller("Umbraco.PropertyEditors.EntityPickerController", entityPicker);
- /**
- * @ngdoc controller
- * @name Umbraco.Editors.FileUploadController
- * @function
- *
- * @description
- * The controller for the file upload property editor. It is important to note that the $scope.model.value
- * doesn't necessarily depict what is saved for this property editor. $scope.model.value can be empty when we
- * are submitting files because in that case, we are adding files to the fileManager which is what gets peristed
- * on the server. However, when we are clearing files, we are setting $scope.model.value to "{clearFiles: true}"
- * to indicate on the server that we are removing files for this property. We will keep the $scope.model.value to
- * be the name of the file selected (if it is a newly selected file) or keep it to be it's original value, this allows
- * for the editors to check if the value has changed and to re-bind the property if that is true.
- *
- */
- function fileUploadController($scope, $element, $compile, imageHelper, fileManager, umbRequestHelper, mediaHelper) {
- /** Clears the file collections when content is saving (if we need to clear) or after saved */
- function clearFiles() {
- //clear the files collection (we don't want to upload any!)
- fileManager.setFiles($scope.model.alias, []);
- //clear the current files
- $scope.files = [];
- if ($scope.propertyForm.fileCount) {
- //this is required to re-validate
- $scope.propertyForm.fileCount.$setViewValue($scope.files.length);
- }
- }
- /** this method is used to initialize the data and to re-initialize it if the server value is changed */
- function initialize(index) {
- clearFiles();
- if (!index) {
- index = 1;
- }
- //this is used in order to tell the umb-single-file-upload directive to
- //rebuild the html input control (and thus clearing the selected file) since
- //that is the only way to manipulate the html for the file input control.
- $scope.rebuildInput = {
- index: index
- };
- //clear the current files
- $scope.files = [];
- //store the original value so we can restore it if the user clears and then cancels clearing.
- $scope.originalValue = $scope.model.value;
- //create the property to show the list of files currently saved
- if ($scope.model.value != "") {
- var images = $scope.model.value.split(",");
- $scope.persistedFiles = _.map(images, function (item) {
- return { file: item, isImage: imageHelper.detectIfImageByExtension(item) };
- });
- }
- else {
- $scope.persistedFiles = [];
- }
- _.each($scope.persistedFiles, function (file) {
- var thumbnailUrl = umbRequestHelper.getApiUrl(
- "imagesApiBaseUrl",
- "GetBigThumbnail",
- [{ originalImagePath: file.file }]);
- file.thumbnail = thumbnailUrl;
- });
- $scope.clearFiles = false;
- }
- initialize();
- // Method required by the valPropertyValidator directive (returns true if the property editor has at least one file selected)
- $scope.validateMandatory = function () {
- return {
- isValid: !$scope.model.validation.mandatory || ((($scope.persistedFiles != null && $scope.persistedFiles.length > 0) || ($scope.files != null && $scope.files.length > 0)) && !$scope.clearFiles),
- errorMsg: "Value cannot be empty",
- errorKey: "required"
- };
- }
- //listen for clear files changes to set our model to be sent up to the server
- $scope.$watch("clearFiles", function (isCleared) {
- if (isCleared == true) {
- $scope.model.value = { clearFiles: true };
- clearFiles();
- }
- else {
- //reset to original value
- $scope.model.value = $scope.originalValue;
- //this is required to re-validate
- $scope.propertyForm.fileCount.$setViewValue($scope.files.length);
- }
- });
- //listen for when a file is selected
- $scope.$on("filesSelected", function (event, args) {
- $scope.$apply(function () {
- //set the files collection
- fileManager.setFiles($scope.model.alias, args.files);
- //clear the current files
- $scope.files = [];
- var newVal = "";
- for (var i = 0; i < args.files.length; i++) {
- //save the file object to the scope's files collection
- $scope.files.push({ alias: $scope.model.alias, file: args.files[i] });
- newVal += args.files[i].name + ",";
- }
- //this is required to re-validate
- $scope.propertyForm.fileCount.$setViewValue($scope.files.length);
- //set clear files to false, this will reset the model too
- $scope.clearFiles = false;
- //set the model value to be the concatenation of files selected. Please see the notes
- // in the description of this controller, it states that this value isn't actually used for persistence,
- // but we need to set it so that the editor and the server can detect that it's been changed, and it is used for validation.
- $scope.model.value =