<!DOCTYPE html>
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js"> <!--<![endif]-->
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>AngularUI - TinyMCE Demo</title>
<script data-require="angular.js@1.4.7" data-semver="1.4.7" src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.7/angular.min.js"></script>
<script data-require="angular.js@1.4.7" data-semver="1.4.7" src="https://code.angularjs.org/1.4.7/angular-messages.js"></script>
<script src="https://cdn.tinymce.com/4/tinymce.min.js"></script>
<script src="tinymce.js"></script>
<script src="demo.js">
</script>
</head>
<body ng-app="ui.tinymce" ng-controller="DemoCtrl as demo">
<form method="post">
<textarea ui-tinymce="tinyMceOptions"
ng-model="demo.tinymce"
ng-change="demo.updateHtml()"></textarea>
</form>
<pre ng-bind="demo.tinymceHtml"></pre>
</body>
</html>
// Code goes here
angular.module('ui.tinymce')
.controller('DemoCtrl',['$scope', '$sce', '$timeout', function($scope,$sce,$timeout) {
var ctrl = this;
$scope.tinyMceOptions = {
setup: function(editor) {
console.log('test1');
$timeout(function () {
console.log('test2');
editor.focus();
}, 200)
},
plugins: ["image", "imagetools"],
statusbar: false,
menubar: false,
resize: false,
toolbar: 'formatselect | bold italic underline | bullist numlist | undo redo | image'
};
this.updateHtml = function() {
ctrl.tinymceHtml = $sce.trustAsHtml(ctrl.tinymce);
};
}]);
/**
* Binds a TinyMCE widget to <textarea> elements.
*/
angular.module('ui.tinymce', [])
.value('uiTinymceConfig', {})
.directive('uiTinymce', ['$rootScope', '$compile', '$timeout', '$window', '$sce', 'uiTinymceConfig', function($rootScope, $compile, $timeout, $window, $sce, uiTinymceConfig) {
uiTinymceConfig = uiTinymceConfig || {};
var generatedIds = 0;
var ID_ATTR = 'ui-tinymce';
if (uiTinymceConfig.baseUrl) {
tinymce.baseURL = uiTinymceConfig.baseUrl;
}
return {
require: ['ngModel', '^?form'],
priority: 999,
link: function(scope, element, attrs, ctrls) {
if (!$window.tinymce) {
return;
}
var ngModel = ctrls[0],
form = ctrls[1] || null;
var expression, options = {}, tinyInstance,
updateView = function(editor) {
var content = editor.getContent({format: options.format}).trim();
content = $sce.trustAsHtml(content);
ngModel.$setViewValue(content);
if (!$rootScope.$$phase) {
scope.$digest();
}
};
function toggleDisable(disabled) {
if (disabled) {
ensureInstance();
if (tinyInstance) {
tinyInstance.getBody().setAttribute('contenteditable', false);
}
} else {
ensureInstance();
if (tinyInstance && !tinyInstance.settings.readonly) {
tinyInstance.getBody().setAttribute('contenteditable', true);
}
}
}
// generate an ID
attrs.$set('id', ID_ATTR + '-' + generatedIds++);
expression = {};
angular.extend(expression, scope.$eval(attrs.uiTinymce));
// Combines the editor save and view update
// into a a single function. Additionally, this
// helps debounce the save & update process so that
// the entire process doesn't have to happen for every
// action (i.e. key press, mouse event, etc).
var doSaveUpdate = (function(doSaveUpdateDelay) {
var doSaveUpdateTimer;
return function(ed) {
$timeout.cancel(doSaveUpdateTimer);
doSaveUpdateTimer = $timeout(function() {
return (function(ed) {
ed.save();
updateView(ed);
})(ed);
}, doSaveUpdateDelay);
};
})(400); // This could be setup to be an option or attribute.
var setupOptions = {
// Update model when calling setContent
// (such as from the source editor popup)
setup: function(ed) {
ed.on('init', function() {
ngModel.$render();
ngModel.$setPristine();
ngModel.$setUntouched();
if (form) {
form.$setPristine();
}
});
// Update model when:
// - a button has been clicked [ExecCommand]
// - the editor content has been modified [change]
// - the node has changed [NodeChange]
// - an object has been resized (table, image) [ObjectResized]
ed.on('ExecCommand change NodeChange ObjectResized', function() {
doSaveUpdate(ed);
});
ed.on('blur', function() {
element[0].blur();
ngModel.$setTouched();
scope.$digest();
});
ed.on('remove', function() {
element.remove();
});
if (expression.setup) {
expression.setup(ed, {
updateView: updateView
});
}
},
format: expression.format || 'html',
selector: '#' + attrs.id
};
// extend options with initial uiTinymceConfig and
// options from directive attribute value
angular.extend(options, uiTinymceConfig, expression, setupOptions);
// Wrapped in $timeout due to $tinymce:refresh implementation, requires
// element to be present in DOM before instantiating editor when
// re-rendering directive
$timeout(function() {
if (options.baseURL){
tinymce.baseURL = options.baseURL;
}
tinymce.init(options);
toggleDisable(scope.$eval(attrs.ngDisabled));
});
ngModel.$formatters.unshift(function(modelValue) {
return modelValue ? $sce.trustAsHtml(modelValue) : '';
});
ngModel.$parsers.unshift(function(viewValue) {
return viewValue ? $sce.getTrustedHtml(viewValue) : '';
});
ngModel.$render = function() {
ensureInstance();
var viewValue = ngModel.$viewValue ?
$sce.getTrustedHtml(ngModel.$viewValue) : '';
// instance.getDoc() check is a guard against null value
// when destruction & recreation of instances happen
if (tinyInstance &&
tinyInstance.getDoc()
) {
tinyInstance.setContent(viewValue);
// Triggering change event due to TinyMCE not firing event &
// becoming out of sync for change callbacks
tinyInstance.fire('change');
}
};
attrs.$observe('disabled', toggleDisable);
// This block is because of TinyMCE not playing well with removal and
// recreation of instances, requiring instances to have different
// selectors in order to render new instances properly
scope.$on('$tinymce:refresh', function(e, id) {
var eid = attrs.id;
if (angular.isUndefined(id) || id === eid) {
var parentElement = element.parent();
var clonedElement = element.clone();
clonedElement.removeAttr('id');
clonedElement.removeAttr('style');
clonedElement.removeAttr('aria-hidden');
tinymce.execCommand('mceRemoveEditor', false, eid);
parentElement.append($compile(clonedElement)(scope));
}
});
scope.$on('$destroy', function() {
ensureInstance();
if (tinyInstance) {
tinyInstance.remove();
tinyInstance = null;
}
});
function ensureInstance() {
if (!tinyInstance) {
tinyInstance = tinymce.get(attrs.id);
}
}
}
};
}]);