141 lines
3.8 KiB
JavaScript
Executable File
141 lines
3.8 KiB
JavaScript
Executable File
(function (root, factory) {
|
|
// AMD
|
|
if (typeof define === 'function' && define.amd) define(['angular'], factory);
|
|
// Global
|
|
else factory(angular);
|
|
}(this, function (angular) {
|
|
|
|
angular
|
|
.module('ckeditor', [])
|
|
.directive('ckeditor', ['$parse', ckeditorDirective]);
|
|
|
|
// Create setImmediate function.
|
|
var setImmediate = window && window.setImmediate ? window.setImmediate : function (fn) {
|
|
setTimeout(fn, 0);
|
|
};
|
|
|
|
/**
|
|
* CKEditor directive.
|
|
*
|
|
* @example
|
|
* <div ckeditor="options" ng-model="content" ready="onReady()"></div>
|
|
*/
|
|
|
|
function ckeditorDirective($parse) {
|
|
return {
|
|
restrict: 'A',
|
|
require: ['ckeditor', 'ngModel'],
|
|
controller: [
|
|
'$scope',
|
|
'$element',
|
|
'$attrs',
|
|
'$parse',
|
|
'$q',
|
|
ckeditorController
|
|
],
|
|
link: function (scope, element, attrs, ctrls) {
|
|
var ckeditor = ctrls[0];
|
|
var ngModel = ctrls[1];
|
|
|
|
// Initialize the editor when it is ready.
|
|
ckeditor.ready().then(function initialize() {
|
|
// Sync view on specific events.
|
|
['dataReady', 'change', 'saveSnapshot'].forEach(function (event) {
|
|
ckeditor.$on(event, function syncView() {
|
|
ngModel.$setViewValue(ckeditor.instance.getData() || '');
|
|
});
|
|
});
|
|
|
|
// Put editor out of readonly.
|
|
ckeditor.instance.setReadOnly(false);
|
|
|
|
// Defer the ready handler calling to ensure that the editor is
|
|
// completely ready and populated with data.
|
|
setImmediate(function () {
|
|
$parse(attrs.ready)(scope);
|
|
});
|
|
});
|
|
|
|
// Set editor data when view data change.
|
|
ngModel.$render = function syncEditor() {
|
|
ckeditor.ready().then(function () {
|
|
ckeditor.instance.setData(ngModel.$viewValue || '');
|
|
});
|
|
};
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* CKEditor controller.
|
|
*/
|
|
|
|
function ckeditorController($scope, $element, $attrs, $parse, $q) {
|
|
// Create editor instance.
|
|
var config = $parse($attrs.ckeditor)($scope) || {};
|
|
var editorElement = $element[0];
|
|
var instance;
|
|
if (editorElement.hasAttribute('contenteditable') &&
|
|
editorElement.getAttribute('contenteditable').toLowerCase() == 'true') {
|
|
instance = this.instance = CKEDITOR.inline(editorElement, config);
|
|
}
|
|
else {
|
|
instance = this.instance = CKEDITOR.replace(editorElement, config);
|
|
}
|
|
|
|
/**
|
|
* Listen on events of a given type.
|
|
* This make all event asynchrone and wrapped in $scope.$apply.
|
|
*
|
|
* @param {String} event
|
|
* @param {Function} listener
|
|
* @returns {Function} Deregistration function for this listener.
|
|
*/
|
|
|
|
this.$on = function $on(event, listener) {
|
|
// Wrap primus event with $rootScope.$apply.
|
|
instance.on(event, asyncListener);
|
|
|
|
function asyncListener() {
|
|
var args = arguments;
|
|
setImmediate(function () {
|
|
applyListener.apply(null, args);
|
|
});
|
|
}
|
|
|
|
function applyListener() {
|
|
var args = arguments;
|
|
$scope.$apply(function () {
|
|
listener.apply(null, args);
|
|
});
|
|
}
|
|
|
|
// Return the deregistration function
|
|
return function $off() {
|
|
instance.removeListener(event, applyListener);
|
|
};
|
|
};
|
|
|
|
/**
|
|
* Check if the editor if ready.
|
|
*
|
|
* @returns {Promise}
|
|
*/
|
|
|
|
this.ready = function ready() {
|
|
if (this.readyDefer) return this.readyDefer.promise;
|
|
|
|
var readyDefer = this.readyDefer = $q.defer();
|
|
if (this.instance.status === 'ready') readyDefer.resolve();
|
|
else this.$on('instanceReady', readyDefer.resolve);
|
|
|
|
return readyDefer.promise;
|
|
};
|
|
|
|
// Destroy editor when the scope is destroyed.
|
|
$scope.$on('$destroy', function onDestroy() {
|
|
instance.destroy(false);
|
|
});
|
|
}
|
|
}));
|