angular-ckeditor.js 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  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. angular
  8. .module('ckeditor', [])
  9. .directive('ckeditor', ['$parse', ckeditorDirective]);
  10. // Create setImmediate function.
  11. var setImmediate = window && window.setImmediate ? window.setImmediate : function (fn) {
  12. setTimeout(fn, 0);
  13. };
  14. /**
  15. * CKEditor directive.
  16. *
  17. * @example
  18. * <div ckeditor="options" ng-model="content" ready="onReady()"></div>
  19. */
  20. function ckeditorDirective($parse) {
  21. return {
  22. restrict: 'A',
  23. require: ['ckeditor', 'ngModel'],
  24. controller: [
  25. '$scope',
  26. '$element',
  27. '$attrs',
  28. '$parse',
  29. '$q',
  30. ckeditorController
  31. ],
  32. link: function (scope, element, attrs, ctrls) {
  33. var ckeditor = ctrls[0];
  34. var ngModel = ctrls[1];
  35. // Initialize the editor when it is ready.
  36. ckeditor.ready().then(function initialize() {
  37. // Sync view on specific events.
  38. ['dataReady', 'change', 'saveSnapshot'].forEach(function (event) {
  39. ckeditor.$on(event, function syncView() {
  40. ngModel.$setViewValue(ckeditor.instance.getData() || '');
  41. });
  42. });
  43. // Put editor out of readonly.
  44. ckeditor.instance.setReadOnly(false);
  45. // Defer the ready handler calling to ensure that the editor is
  46. // completely ready and populated with data.
  47. setImmediate(function () {
  48. $parse(attrs.ready)(scope);
  49. });
  50. });
  51. // Set editor data when view data change.
  52. ngModel.$render = function syncEditor() {
  53. ckeditor.ready().then(function () {
  54. ckeditor.instance.setData(ngModel.$viewValue || '');
  55. });
  56. };
  57. }
  58. };
  59. }
  60. /**
  61. * CKEditor controller.
  62. */
  63. function ckeditorController($scope, $element, $attrs, $parse, $q) {
  64. // Create editor instance.
  65. var config = $parse($attrs.ckeditor)($scope) || {};
  66. var editorElement = $element[0];
  67. var instance;
  68. if (editorElement.hasAttribute('contenteditable') &&
  69. editorElement.getAttribute('contenteditable').toLowerCase() == 'true') {
  70. instance = this.instance = CKEDITOR.inline(editorElement, config);
  71. }
  72. else {
  73. instance = this.instance = CKEDITOR.replace(editorElement, config);
  74. }
  75. /**
  76. * Listen on events of a given type.
  77. * This make all event asynchrone and wrapped in $scope.$apply.
  78. *
  79. * @param {String} event
  80. * @param {Function} listener
  81. * @returns {Function} Deregistration function for this listener.
  82. */
  83. this.$on = function $on(event, listener) {
  84. // Wrap primus event with $rootScope.$apply.
  85. instance.on(event, asyncListener);
  86. function asyncListener() {
  87. var args = arguments;
  88. setImmediate(function () {
  89. applyListener.apply(null, args);
  90. });
  91. }
  92. function applyListener() {
  93. var args = arguments;
  94. $scope.$apply(function () {
  95. listener.apply(null, args);
  96. });
  97. }
  98. // Return the deregistration function
  99. return function $off() {
  100. instance.removeListener(event, applyListener);
  101. };
  102. };
  103. /**
  104. * Check if the editor if ready.
  105. *
  106. * @returns {Promise}
  107. */
  108. this.ready = function ready() {
  109. if (this.readyDefer) return this.readyDefer.promise;
  110. var readyDefer = this.readyDefer = $q.defer();
  111. if (this.instance.status === 'ready') readyDefer.resolve();
  112. else this.$on('instanceReady', readyDefer.resolve);
  113. return readyDefer.promise;
  114. };
  115. // Destroy editor when the scope is destroyed.
  116. $scope.$on('$destroy', function onDestroy() {
  117. //instance.destroy(false);
  118. });
  119. }
  120. }));