Merge branch '7.0.0' of https://github.com/umbraco/Umbraco-CMS into 7.0.0

This commit is contained in:
perploug
2013-10-01 10:11:08 +02:00
80 changed files with 873 additions and 4171 deletions

View File

@@ -34,16 +34,28 @@ function authResource($q, $http, umbRequestHelper, angularHelper) {
"PostLogout")));
},
/** Sends a request to the server to check if the current cookie value is valid for the user */
isAuthenticated: function () {
/** Sends a request to the server to get the current user details, will return a 401 if the user is not logged in */
getCurrentUser: function () {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"authenticationApiBaseUrl",
"GetCurrentUser")),
'Server call failed for checking authorization');
}
'Server call failed for getting current user');
},
/** Checks if the user is logged in or not - does not return 401 or 403 */
isAuthenticated: function () {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"authenticationApiBaseUrl",
"IsAuthenticated")),
'Server call failed for checking authentication');
},
};
}

View File

@@ -26,7 +26,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
/**
* @ngdoc method
* @name umbraco.resources.memberResource#getByLogin
* @name umbraco.resources.memberResource#getByKey
* @methodOf umbraco.resources.memberResource
*
* @description
@@ -34,7 +34,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
* ##usage
* <pre>
* memberResource.getByLogin("tom")
* memberResource.getByKey("0000-0000-000-00000-000")
* .then(function(member) {
* var mymember = member;
* alert('its here!');
@@ -45,20 +45,20 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @returns {Promise} resourcePromise object containing the member item.
*
*/
getByLogin: function (loginName) {
getByKey: function (key) {
return umbRequestHelper.resourcePromise(
$http.get(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"GetByLogin",
[{ loginName: loginName }])),
'Failed to retreive data for member id ' + loginName);
"GetByKey",
[{ key: key }])),
'Failed to retreive data for member id ' + key);
},
/**
* @ngdoc method
* @name umbraco.resources.memberResource#deleteByLogin
* @name umbraco.resources.memberResource#deleteByKey
* @methodOf umbraco.resources.memberResource
*
* @description
@@ -66,7 +66,7 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
*
* ##usage
* <pre>
* memberResource.deleteByLogin(1234)
* memberResource.deleteByKey("0000-0000-000-00000-000")
* .then(function() {
* alert('its gone!');
* });
@@ -76,14 +76,14 @@ function memberResource($q, $http, umbDataFormatter, umbRequestHelper) {
* @returns {Promise} resourcePromise object.
*
*/
deleteByLogin: function (id) {
deleteByKey: function (key) {
return umbRequestHelper.resourcePromise(
$http.delete(
umbRequestHelper.getApiUrl(
"memberApiBaseUrl",
"DeleteById",
[{ id: id }])),
'Failed to delete item ' + id);
"DeleteByKey",
[{ key: key }])),
'Failed to delete item ' + key);
},
/**

View File

@@ -53,30 +53,20 @@ angular.module('umbraco.services')
return {
/** Internal method to display the login dialog */
_showLoginDialog: function () {
openLoginDialog();
},
/** Returns a promise, sends a request to the server to check if the current cookie is authorized */
isAuthenticated: function (args) {
return authResource.isAuthenticated()
.then(function(data) {
//note, this can return null if they are not authenticated
if (!data) {
throw "Not authenticated";
}
else {
var result = { user: data, authenticated: true, lastUserId: lastUserId };
if (args.broadcastEvent) {
//broadcast a global event, will inform listening controllers to load in the user specific data
$rootScope.$broadcast("authenticated", result);
}
currentUser = data;
currentUser.avatar = 'http://www.gravatar.com/avatar/' + data.emailHash + '?s=40&d=404';
return result;
}
});
isAuthenticated: function () {
//if we've got a current user then just return true
if (currentUser) {
var deferred = $q.defer();
deferred.resolve(true);
return deferred.promise;
}
return authResource.isAuthenticated();
},
/** Returns a promise, sends a request to the server to validate the credentials */
@@ -97,6 +87,7 @@ angular.module('umbraco.services')
});
},
/** Logs the user out and redirects to the login page */
logout: function () {
return authResource.performLogout()
.then(function (data) {
@@ -107,14 +98,38 @@ angular.module('umbraco.services')
//broadcast a global event
$rootScope.$broadcast("notAuthenticated");
openLoginDialog();
$location.path("/login").search({check: false});
return null;
});
},
/** Returns the current user object, if null then calls to authenticated or authenticate must be called */
getCurrentUser: function () {
return currentUser;
/** Returns the current user object in a promise */
getCurrentUser: function (args) {
var deferred = $q.defer();
if (!currentUser) {
authResource.getCurrentUser()
.then(function(data) {
var result = { user: data, authenticated: true, lastUserId: lastUserId };
if (args.broadcastEvent) {
//broadcast a global event, will inform listening controllers to load in the user specific data
$rootScope.$broadcast("authenticated", result);
}
currentUser = data;
currentUser.avatar = 'http://www.gravatar.com/avatar/' + data.emailHash + '?s=40&d=404';
deferred.resolve(currentUser);
});
}
else {
deferred.resolve(currentUser);
}
return deferred.promise;
}
};

View File

@@ -1,15 +1,62 @@
app.config(function ($routeProvider) {
/** This checks if the user is authenticated for a route and what the isRequired is set to.
Depending on whether isRequired = true, it first check if the user is authenticated and will resolve successfully
otherwise the route will fail and the $routeChangeError event will execute, in that handler we will redirect to the rejected
path that is resolved from this method and prevent default (prevent the route from executing) */
var checkAuth = function(isRequired) {
return {
isAuthenticated: function ($q, userService, $route) {
var deferred = $q.defer();
//don't need to check if we've redirected to login and we've already checked auth
if (!$route.current.params.section && $route.current.params.check === false) {
deferred.resolve(true);
return deferred.promise;
}
userService.isAuthenticated()
.then(function () {
if (isRequired) {
//this will resolve successfully so the route will continue
deferred.resolve(true);
}
else {
deferred.reject({ path: "/" });
}
}, function () {
if (isRequired) {
//the check=false is checked above so that we don't have to make another http call to check
//if they are logged in since we already know they are not.
deferred.reject({ path: "/login", search: { check: false } });
}
else {
//this will resolve successfully so the route will continue
deferred.resolve(true);
}
});
return deferred.promise;
}
};
};
$routeProvider
.when('/login', {
templateUrl: 'views/common/login.html',
//ensure auth is *not* required so it will redirect to /content otherwise
resolve: checkAuth(false)
})
.when('/:section', {
templateUrl: function (rp) {
if (rp.section === "default" || rp.section === "")
if (rp.section.toLowerCase() === "default" || rp.section.toLowerCase() === "umbraco" || rp.section === "")
{
rp.section = "content";
}
rp.url = "dashboard.aspx?app=" + rp.section;
return 'views/common/dashboard.html';
}
},
resolve: checkAuth(true)
})
.when('/framed/:url', {
//This occurs when we need to launch some content in an iframe
@@ -18,7 +65,8 @@ app.config(function ($routeProvider) {
throw "A framed resource must have a url route parameter";
return 'views/common/legacy.html';
}
},
resolve: checkAuth(true)
})
.when('/:section/:method', {
templateUrl: function(rp) {
@@ -32,7 +80,8 @@ app.config(function ($routeProvider) {
// dashboards (as tabs if we wanted) and each tab could actually be a route link to one of these views?
return 'views/' + rp.section + '/' + rp.method + '.html';
}
},
resolve: checkAuth(true)
})
.when('/:section/:tree/:method/:id', {
templateUrl: function (rp) {
@@ -43,9 +92,10 @@ app.config(function ($routeProvider) {
//we don't need to put views into section folders since theoretically trees
// could be moved among sections, we only need folders for specific trees.
return 'views/' + rp.tree + '/' + rp.method + '.html';
}
},
resolve: checkAuth(true)
})
.otherwise({ redirectTo: '/content' });
.otherwise({ redirectTo: '/login' });
}).config(function ($locationProvider) {
//$locationProvider.html5Mode(false).hashPrefix('!'); //turn html5 mode off
@@ -53,10 +103,28 @@ app.config(function ($routeProvider) {
});
app.run(['userService', '$log', '$rootScope', function (userService, $log, $rootScope) {
app.run(['userService', '$log', '$rootScope', '$location', function (userService, $log, $rootScope, $location) {
// Get the current user when the application starts
// (in case they are still logged in from a previous session)
var firstRun = true;
/** when we have a successful first route that is not the login page - meaning the user is authenticated
we'll get the current user from the user service and ensure it broadcasts it's events. If the route
is successful from after a login then this will not actually do anything since the authenticated event would
have alraedy fired, but if the user is loading the angularjs app for the first time and they are already authenticated
then this is when the authenticated event will be fired.
*/
$rootScope.$on('$routeChangeSuccess', function (event, current, previous) {
if (firstRun && !$location.url().toLowerCase().startsWith("/login")) {
firstRun = false;
userService.getCurrentUser({ broadcastEvent: true });
}
});
/** When the route change is rejected - based on checkAuth - we'll prevent the rejected route from executing including
wiring up it's controller, etc... and then redirect to the rejected URL. */
$rootScope.$on('$routeChangeError', function (event, current, previous, rejection) {
event.preventDefault();
$location.path(rejection.path).search(rejection.search);
});
userService.isAuthenticated({broadcastEvent: true});
}]);

View File

@@ -5,9 +5,9 @@ angular.module("umbraco")
$scope.history = historyService.current;
$scope.logout = function () {
userService.logout();
$scope.hide();
$location.path("/");
userService.logout().then(function() {
$scope.hide();
});
};
$scope.gotoHistory = function (link) {

View File

@@ -0,0 +1,11 @@
/** 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 ($scope, userService, $location) {
userService._showLoginDialog();
//when a user is authorized redirect - this will only be handled here when we are actually on the /login route
$scope.$on("authenticated", function(evt, data) {
$location.path("/").search("");
});
});

View File

@@ -0,0 +1,3 @@
<div ng-controller="Umbraco.LoginController">
</div>

View File

@@ -8,7 +8,7 @@
* The main application controller
*
*/
function MainController($scope, $routeParams, $rootScope, $timeout, $http, $log, notificationsService, userService, navigationService, legacyJsLoader) {
function MainController($scope, $location, $routeParams, $rootScope, $timeout, $http, $log, notificationsService, userService, navigationService, legacyJsLoader) {
var legacyTreeJsLoaded = false;
@@ -78,6 +78,12 @@ function MainController($scope, $routeParams, $rootScope, $timeout, $http, $log,
$scope.authenticated = data.authenticated;
$scope.user = data.user;
//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
if (data.lastUserId && data.lastUserId !== data.user.id) {
$location.path("/").search("");
}
//var url = "http://www.gravatar.com/avatar/" + $scope.user.emailHash + ".json?404=404";
//$http.jsonp(url).then(function(response){
// $log.log("found: " + response);

View File

@@ -13,7 +13,7 @@ function MemberDeleteController($scope, memberResource, treeService, navigationS
//mark it for deletion (used in the UI)
$scope.currentNode.loading = true;
memberResource.deleteByLogin($scope.currentNode.id).then(function () {
memberResource.deleteByKey($scope.currentNode.id).then(function () {
$scope.currentNode.loading = false;
//TODO: Need to sync tree, etc...

View File

@@ -22,7 +22,7 @@ function MemberEditController($scope, $routeParams, $q, $timeout, $window, membe
}
else {
//we are editing so get the content item from the server
memberResource.getByLogin($routeParams.id)
memberResource.getByKey($routeParams.id)
.then(function(data) {
$scope.loaded = true;
$scope.content = data;

View File

@@ -1,14 +1,26 @@
function booleanEditorController($scope, $rootScope, assetsService) {
$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;
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.Editors.BooleanController", booleanEditorController);

View File

@@ -1,22 +1,27 @@
angular.module("umbraco").controller("Umbraco.Editors.CheckboxListController",
function($scope) {
$scope.selectedItems = [];
if (!angular.isObject($scope.model.config.items)) {
throw "The model.config.items property must be either a dictionary";
}
//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 = [];
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 in $scope.model.config.items) {
var isChecked = _.contains($scope.model.value, i);
$scope.selectedItems.push({ checked: isChecked, key: i, val: $scope.model.config.items[i] });
}
}
for (var i in $scope.model.config.items) {
var isChecked = _.contains($scope.model.value, i);
$scope.selectedItems.push({ checked: isChecked, key: i, val: $scope.model.config.items[i] });
}
setupViewModel();
//update the model when the items checked changes
$scope.$watch("selectedItems", function(newVal, oldVal) {
@@ -29,5 +34,12 @@ angular.module("umbraco").controller("Umbraco.Editors.CheckboxListController",
}
}, 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();
};
});

View File

@@ -1,75 +1,84 @@
angular.module("umbraco")
.controller("Umbraco.Editors.GoogleMapsController",
function ($rootScope, $scope, notificationsService, dialogService, assetsService, $log, $timeout) {
assetsService.loadJs('http://www.google.com/jsapi')
.then(function(){
google.load("maps", "3",
{
callback: initMap,
other_params: "sensor=false"
assetsService.loadJs('http://www.google.com/jsapi')
.then(function () {
google.load("maps", "3",
{
callback: initMap,
other_params: "sensor=false"
});
});
function initMap() {
//Google maps is available and all components are ready to use.
var valueArray = $scope.model.value.split(',');
var latLng = new google.maps.LatLng(valueArray[0], valueArray[1]);
var mapDiv = document.getElementById($scope.model.alias + '_map');
var mapOptions = {
zoom: $scope.model.config.zoom,
center: latLng,
mapTypeId: google.maps.MapTypeId[$scope.model.config.mapType]
};
var geocoder = new google.maps.Geocoder();
var map = new google.maps.Map(mapDiv, mapOptions);
var marker = new google.maps.Marker({
map: map,
position: latLng,
draggable: true
});
google.maps.event.addListener(map, 'click', function (event) {
dialogService.mediaPicker({
scope: $scope, callback: function (data) {
var image = data.selection[0].src;
var latLng = event.latLng;
var marker = new google.maps.Marker({
map: map,
icon: image,
position: latLng,
draggable: true
});
});
function initMap(){
//Google maps is available and all components are ready to use.
var valueArray = $scope.model.value.split(',');
var latLng = new google.maps.LatLng(valueArray[0], valueArray[1]);
var mapDiv = document.getElementById($scope.model.alias + '_map');
var mapOptions = {
zoom: $scope.model.config.zoom,
center: latLng,
mapTypeId: google.maps.MapTypeId[$scope.model.config.mapType]
};
var geocoder = new google.maps.Geocoder();
var map = new google.maps.Map(mapDiv, mapOptions);
google.maps.event.addListener(marker, "dragend", function (e) {
var newLat = marker.getPosition().lat();
var newLng = marker.getPosition().lng();
var marker = new google.maps.Marker({
map: map,
position: latLng,
draggable: true
});
codeLatLng(marker.getPosition(), geocoder);
google.maps.event.addListener(map, 'click', function(event) {
//set the model value
$scope.model.vvalue = newLat + "," + newLng;
});
dialogService.mediaPicker({scope: $scope, callback: function(data){
var image = data.selection[0].src;
var latLng = event.latLng;
var marker = new google.maps.Marker({
map: map,
icon: image,
position: latLng,
draggable: true
}
});
});
google.maps.event.addListener(marker, "dragend", function(e){
var newLat = marker.getPosition().lat();
var newLng = marker.getPosition().lng();
$('a[data-toggle="tab"]').on('shown', function (e) {
google.maps.event.trigger(map, 'resize');
});
}
codeLatLng(marker.getPosition(), geocoder);
//set the model value
$scope.model.vvalue = newLat + "," + newLng;
});
}});
});
$('a[data-toggle="tab"]').on('shown', function (e) {
google.maps.event.trigger(map, 'resize');
});
}
function codeLatLng(latLng, geocoder) {
geocoder.geocode({'latLng': latLng},
function(results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var location = results[0].formatted_address;
function codeLatLng(latLng, geocoder) {
geocoder.geocode({ 'latLng': latLng },
function (results, status) {
if (status == google.maps.GeocoderStatus.OK) {
var location = results[0].formatted_address;
$rootScope.$apply(function () {
notificationsService.success("Peter just went to: ", location);
});
}
});
}
});
}
});
}
//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
initMap();
};
});

View File

@@ -1,54 +1,68 @@
//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.Editors.MediaPickerController",
function($rootScope, $scope, dialogService, mediaResource, imageHelper, $log){
$scope.images = [];
$scope.ids = [];
angular.module('umbraco').controller("Umbraco.Editors.MediaPickerController",
function($rootScope, $scope, dialogService, mediaResource, imageHelper, $log) {
if($scope.model.value){
$scope.ids = $scope.model.value.split(',');
mediaResource.getByIds($scope.ids).then(function(medias){
//img.media = media;
$(medias).each(function(i, media){
//shortcuts
//TODO, do something better then this for searching
var img = {};
img.src = imageHelper.getImagePropertyValue({imageModel: media});
img.thumbnail = imageHelper.getThumbnailFromPath(img.src);
$scope.images.push(img);
});
});
}
function setupViewModel() {
$scope.images = [];
$scope.ids = [];
$scope.remove = function(index){
$scope.images.splice(index, 1);
$scope.ids.splice(index, 1);
$scope.sync();
};
if ($scope.model.value) {
$scope.ids = $scope.model.value.split(',');
$scope.add = function(){
dialogService.mediaPicker({multipicker:true, callback: function(data){
$(data.selection).each(function(i, media){
//shortcuts
//TODO, do something better then this for searching
mediaResource.getByIds($scope.ids).then(function (medias) {
//img.media = media;
_.each(medias, function (media, i) {
//shortcuts
//TODO, do something better then this for searching
var img = {};
img.src = imageHelper.getImagePropertyValue({ imageModel: media });
img.thumbnail = imageHelper.getThumbnailFromPath(img.src);
$scope.images.push(img);
});
});
}
}
var img = {};
img.id = media.id;
img.src = imageHelper.getImagePropertyValue({imageModel: media});
img.thumbnail = imageHelper.getThumbnailFromPath(img.src);
$scope.images.push(img);
$scope.ids.push(img.id);
});
setupViewModel();
$scope.sync();
}});
};
$scope.remove = function(index) {
$scope.images.splice(index, 1);
$scope.ids.splice(index, 1);
$scope.sync();
};
$scope.sync = function(){
$scope.model.value = $scope.ids.join();
};
$scope.add = function() {
dialogService.mediaPicker({
multipicker: true,
callback: function(data) {
_.each(data.selection, function(media, i) {
//shortcuts
//TODO, do something better then this for searching
});
var img = {};
img.id = media.id;
img.src = imageHelper.getImagePropertyValue({ imageModel: media });
img.thumbnail = imageHelper.getThumbnailFromPath(img.src);
$scope.images.push(img);
$scope.ids.push(img.id);
});
$scope.sync();
}
});
};
$scope.sync = function() {
$scope.model.value = $scope.ids.join();
};
//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();
};
});

View File

@@ -32,65 +32,79 @@ angular.module("umbraco")
var plugins = "code";
assetsService.loadJs("lib/tinymce/tinymce.min.js", $scope).then(function () {
//we need to add a timeout here, to force a redraw so TinyMCE can find
//the elements needed
$timeout(function () {
tinymce.DOM.events.domLoaded = true;
tinymce.init({
mode: "exact",
elements: $scope.model.alias + "_rte",
skin: "umbraco",
plugins: plugins,
valid_elements: validElements,
menubar: false,
statusbar: false,
height: 340,
toolbar: toolbar,
setup: function (editor) {
//We need to listen on multiple things here because of the nature of tinymce, it doesn't
//fire events when you think!
//The change event doesn't fire when content changes, only when cursor points are changed and undo points
//are created. the blur event doesn't fire if you insert content into the editor with a button and then
//press save.
//We have a couple of options, one is to do a set timeout and check for isDirty on the editor, or we can
//listen to both change and blur and also on our own 'saving' event. I think this will be best because a
//timer might end up using unwanted cpu and we'd still have to listen to our saving event in case they clicked
//save before the timeout elapsed.
editor.on('change', function (e) {
angularHelper.safeApply($scope, function() {
$scope.model.value = editor.getContent();
});
});
editor.on('blur', function (e) {
angularHelper.safeApply($scope, function () {
/** Loads in the editor */
function loadTinyMce() {
//we need to add a timeout here, to force a redraw so TinyMCE can find
//the elements needed
$timeout(function () {
tinymce.DOM.events.domLoaded = true;
tinymce.init({
mode: "exact",
elements: $scope.model.alias + "_rte",
skin: "umbraco",
plugins: plugins,
valid_elements: validElements,
menubar: false,
statusbar: false,
height: 340,
toolbar: toolbar,
setup: function (editor) {
//We need to listen on multiple things here because of the nature of tinymce, it doesn't
//fire events when you think!
//The change event doesn't fire when content changes, only when cursor points are changed and undo points
//are created. the blur event doesn't fire if you insert content into the editor with a button and then
//press save.
//We have a couple of options, one is to do a set timeout and check for isDirty on the editor, or we can
//listen to both change and blur and also on our own 'saving' event. I think this will be best because a
//timer might end up using unwanted cpu and we'd still have to listen to our saving event in case they clicked
//save before the timeout elapsed.
editor.on('change', function (e) {
angularHelper.safeApply($scope, function () {
$scope.model.value = editor.getContent();
});
});
editor.on('blur', function (e) {
angularHelper.safeApply($scope, function () {
$scope.model.value = editor.getContent();
});
});
var unsubscribe = $scope.$on("saving", function () {
$scope.model.value = editor.getContent();
});
});
var unsubscribe = $scope.$on("saving", function() {
$scope.model.value = editor.getContent();
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise if this is part of a modal, the listener still exists because the dom
// element might still be there even after the modal has been hidden.
$element.bind('$destroy', function () {
unsubscribe();
});
//when the element is disposed we need to unsubscribe!
// NOTE: this is very important otherwise if this is part of a modal, the listener still exists because the dom
// element might still be there even after the modal has been hidden.
$element.bind('$destroy', function () {
unsubscribe();
});
//Create the insert media plugin
tinyMceService.createMediaPicker(editor, $scope);
//Create the insert media plugin
tinyMceService.createMediaPicker(editor, $scope);
//Create the insert icon plugin
tinyMceService.createInsertEmbeddedMedia(editor, $scope);
//Create the insert icon plugin
tinyMceService.createInsertEmbeddedMedia(editor, $scope);
//Create the insert macro plugin
tinyMceService.createInsertMacro(editor, $scope);
//Create the insert macro plugin
tinyMceService.createInsertMacro(editor, $scope);
}
});
}, 1);
}
});
}, 1);
}
loadTinyMce();
//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
loadTinyMce();
};
});
});