Built motion from commit 1020cd7.|0.0.107
[motion.git] / public / bower_components / angular-ckeditor / angular-ckeditor.js
1 (function (root, factory) {
2   // AMD
3   if (typeof define === 'function' && define.amd) define(['angular'], factory);
4   // Global
5   else factory(angular);
6 }(this, function (angular) {
7
8   angular
9   .module('ckeditor', [])
10   .directive('ckeditor', ['$parse', ckeditorDirective]);
11
12   // Polyfill setImmediate function.
13   var setImmediate = window && window.setImmediate ? window.setImmediate : function (fn) {
14     setTimeout(fn, 0);
15   };
16
17   /**
18    * CKEditor directive.
19    *
20    * @example
21    * <div ckeditor="options" ng-model="content" ready="onReady()"></div>
22    */
23
24   function ckeditorDirective($parse) {
25     return {
26       restrict: 'A',
27       require: ['ckeditor', 'ngModel'],
28       controller: [
29         '$scope',
30         '$element',
31         '$attrs',
32         '$parse',
33         '$q',
34         ckeditorController
35       ],
36       link: function (scope, element, attrs, ctrls) {
37         // get needed controllers
38         var controller = ctrls[0]; // our own, see below
39         var ngModelController = ctrls[1];
40
41         // Initialize the editor content when it is ready.
42         controller.ready().then(function initialize() {
43           // Sync view on specific events.
44           ['dataReady', 'change', 'blur', 'saveSnapshot'].forEach(function (event) {
45             controller.onCKEvent(event, function syncView() {
46               ngModelController.$setViewValue(controller.instance.getData() || '');
47             });
48           });
49
50           controller.instance.setReadOnly(!! attrs.readonly);
51           attrs.$observe('readonly', function (readonly) {
52             controller.instance.setReadOnly(!! readonly);
53           });
54
55           // Defer the ready handler calling to ensure that the editor is
56           // completely ready and populated with data.
57           setImmediate(function () {
58             $parse(attrs.ready)(scope);
59           });
60         });
61
62         // Set editor data when view data change.
63         ngModelController.$render = function syncEditor() {
64           controller.ready().then(function () {
65             // "noSnapshot" prevent recording an undo snapshot
66             controller.instance.setData(ngModelController.$viewValue || '', {
67               noSnapshot: true,
68               callback: function () {
69                 // Amends the top of the undo stack with the current DOM changes
70                 // ie: merge snapshot with the first empty one
71                 // http://docs.ckeditor.com/#!/api/CKEDITOR.editor-event-updateSnapshot
72                 controller.instance.fire('updateSnapshot');
73               }
74             });
75           });
76         };
77       }
78     };
79   }
80
81   /**
82    * CKEditor controller.
83    */
84
85   function ckeditorController($scope, $element, $attrs, $parse, $q) {
86     var config = $parse($attrs.ckeditor)($scope) || {};
87     var editorElement = $element[0];
88     var instance;
89     var readyDeferred = $q.defer(); // a deferred to be resolved when the editor is ready
90
91     // Create editor instance.
92     if (editorElement.hasAttribute('contenteditable') &&
93         editorElement.getAttribute('contenteditable').toLowerCase() == 'true') {
94       instance = this.instance = CKEDITOR.inline(editorElement, config);
95     }
96     else {
97       instance = this.instance = CKEDITOR.replace(editorElement, config);
98     }
99
100     /**
101      * Listen on events of a given type.
102      * This make all event asynchronous and wrapped in $scope.$apply.
103      *
104      * @param {String} event
105      * @param {Function} listener
106      * @returns {Function} Deregistration function for this listener.
107      */
108
109     this.onCKEvent = function (event, listener) {
110       instance.on(event, asyncListener);
111
112       function asyncListener() {
113         var args = arguments;
114         setImmediate(function () {
115           applyListener.apply(null, args);
116         });
117       }
118
119       function applyListener() {
120         var args = arguments;
121         $scope.$apply(function () {
122           listener.apply(null, args);
123         });
124       }
125
126       // Return the deregistration function
127       return function $off() {
128         instance.removeListener(event, applyListener);
129       };
130     };
131
132     this.onCKEvent('instanceReady', function() {
133       readyDeferred.resolve(true);
134     });
135
136     /**
137      * Check if the editor if ready.
138      *
139      * @returns {Promise}
140      */
141     this.ready = function ready() {
142       return readyDeferred.promise;
143     };
144
145     // Destroy editor when the scope is destroyed.
146     $scope.$on('$destroy', function onDestroy() {
147       // do not delete too fast or pending events will throw errors
148       readyDeferred.promise.then(function() {
149         instance.destroy(false);
150       });
151     });
152   }
153 }));