PageSourceSearch

https://followyournola.com/bower_components/angular-ui-tinymce/src/tinymce.js

js followyournola.com collected 2026-10-04 05:12:46 UTC 6,621 bytes, 205 lines download raw bytes

1/**
2 * Binds a TinyMCE widget to <textarea> elements.
3 */
4angular.module('ui.tinymce', [])
5  .value('uiTinymceConfig', {})
6  .directive('uiTinymce', ['$rootScope', '$compile', '$timeout', '$window', '$sce', 'uiTinymceConfig', function($rootScope, $compile, $timeout, $window, $sce, uiTinymceConfig) {
7    uiTinymceConfig = uiTinymceConfig || {};
8    var generatedIds = 0;
9    var ID_ATTR = 'ui-tinymce';
10    if (uiTinymceConfig.baseUrl) {
11      tinymce.baseURL = uiTinymceConfig.baseUrl;
12    }
13
14    return {
15      require: ['ngModel', '^?form'],
16      priority: 599,
17      link: function(scope, element, attrs, ctrls) {
18        if (!$window.tinymce) {
19          return;
20        }
21
22        var ngModel = ctrls[0],
23          form = ctrls[1] || null;
24
25        var expression, options = {
26          debounce: true
27        }, tinyInstance,
28          updateView = function(editor) {
29            var content = editor.getContent({format: options.format}).trim();
30            content = $sce.trustAsHtml(content);
31
32            ngModel.$setViewValue(content);
33            if (!$rootScope.$$phase) {
34              scope.$digest();
35            }
36          };
37
38        function toggleDisable(disabled) {
39          if (disabled) {
40            ensureInstance();
41
42            if (tinyInstance) {
43              tinyInstance.getBody().setAttribute('contenteditable', false);
44            }
45          } else {
46            ensureInstance();
47
48            if (tinyInstance && !tinyInstance.settings.readonly) {
49              tinyInstance.getBody().setAttribute('contenteditable', true);
50            }
51          }
52        }
53
54        // generate an ID
55        attrs.$set('id', ID_ATTR + '-' + generatedIds++);
56
57        expression = {};
58
59        angular.extend(expression, scope.$eval(attrs.uiTinymce));
60
61        //Debounce update and save action
62        var debouncedUpdate = (function(debouncedUpdateDelay) {
63          var debouncedUpdateTimer;
64          return function(ed) {
65	        $timeout.cancel(debouncedUpdateTimer);
66	         debouncedUpdateTimer = $timeout(function() {
67              return (function(ed) {
68                if (ed.isDirty()) {
69                  ed.save();
70                  updateView(ed);
71                }
72              })(ed);
73            }, debouncedUpdateDelay);
74          };
75        })(400);
76
77        var setupOptions = {
78          // Update model when calling setContent
79          // (such as from the source editor popup)
80          setup: function(ed) {
81            ed.on('init', function() {
82              ngModel.$render();
83              ngModel.$setPristine();
84                ngModel.$setUntouched();
85              if (form) {
86                form.$setPristine();
87              }
88            });
89
90            // Update model when:
91            // - a button has been clicked [ExecCommand]
92            // - the editor content has been modified [change]
93            // - the node has changed [NodeChange]
94            // - an object has been resized (table, image) [ObjectResized]
95            ed.on('ExecCommand change NodeChange ObjectResized', function() {
96              if (!options.debounce) {
97                ed.save();
98                updateView(ed);
99              	return;
100              }
101              debouncedUpdate(ed);
102            });
103
104            ed.on('blur', function() {
105              element[0].blur();
106              ngModel.$setTouched();
107              if (!$rootScope.$$phase) {
108                scope.$digest();
109              }
110            });
111
112            ed.on('remove', function() {
113              element.remove();
114            });
115
116            if (uiTinymceConfig.setup) {
117              uiTinymceConfig.setup(ed, {
118                updateView: updateView
119              });
120            }
121
122            if (expression.setup) {
123              expression.setup(ed, {
124                updateView: updateView
125              });
126            }
127          },
128          format: expression.format || 'html',
129          selector: '#' + attrs.id
130        };
131        // extend options with initial uiTinymceConfig and
132        // options from directive attribute value
133        angular.extend(options, uiTinymceConfig, expression, setupOptions);
134        // Wrapped in $timeout due to $tinymce:refresh implementation, requires
135        // element to be present in DOM before instantiating editor when
136        // re-rendering directive
137        $timeout(function() {
138          if (options.baseURL){
139            tinymce.baseURL = options.baseURL;
140          }
141          tinymce.init(options);
142          toggleDisable(scope.$eval(attrs.ngDisabled));
143        });
144
145        ngModel.$formatters.unshift(function(modelValue) {
146          return modelValue ? $sce.trustAsHtml(modelValue) : '';
147        });
148
149        ngModel.$parsers.unshift(function(viewValue) {
150          return viewValue ? $sce.getTrustedHtml(viewValue) : '';
151        });
152
153        ngModel.$render = function() {
154          ensureInstance();
155
156          var viewValue = ngModel.$viewValue ?
157            $sce.getTrustedHtml(ngModel.$viewValue) : '';
158
159          // instance.getDoc() check is a guard against null value
160          // when destruction & recreation of instances happen
161          if (tinyInstance &&
162            tinyInstance.getDoc()
163          ) {
164            tinyInstance.setContent(viewValue);
165            // Triggering change event due to TinyMCE not firing event &
166            // becoming out of sync for change callbacks
167            tinyInstance.fire('change');
168          }
169        };
170
171        attrs.$observe('disabled', toggleDisable);
172
173        // This block is because of TinyMCE not playing well with removal and
174        // recreation of instances, requiring instances to have different
175        // selectors in order to render new instances properly
176        scope.$on('$tinymce:refresh', function(e, id) {
177          var eid = attrs.id;
178          if (angular.isUndefined(id) || id === eid) {
179            var parentElement = element.parent();
180            var clonedElement = element.clone();
181            clonedElement.removeAttr('id');
182            clonedElement.removeAttr('style');
183            clonedElement.removeAttr('aria-hidden');
184            tinymce.execCommand('mceRemoveEditor', false, eid);
185            parentElement.append($compile(clonedElement)(scope));
186          }
187        });
188
189        scope.$on('$destroy', function() {
190          ensureInstance();
191
192          if (tinyInstance) {
193            tinyInstance.remove();
194            tinyInstance = null;
195          }
196        });
197
198        function ensureInstance() {
199          if (!tinyInstance) {
200            tinyInstance = tinymce.get(attrs.id);
201          }
202        }
203      }
204    };
205  }]);

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.