PageSourceSearch

https://platform.homeruniq.com/_content/TinyMCE.Blazor/tinymce-blazor.js

js homeruniq.com collected 2026-10-04 14:00:27 UTC 7,187 bytes, 242 lines download raw bytes

1const CreateScriptLoader = () => {
2  let unique = 0;
3
4  const uuid = (prefix) => {
5    const time = Date.now();
6    const random = Math.floor(Math.random() * 1000000000);
7    unique++;
8    return prefix + '_' + random + unique + String(time);
9  };
10  const state = {
11    scriptId: uuid('tiny-script'),
12    listeners: [],
13    scriptLoaded: false
14  };
15
16  const injectScript = (scriptId, doc, url, injectionCallback) => {
17    const scriptTag = doc.createElement('script');
18    scriptTag.referrerPolicy = 'origin';
19    scriptTag.type = 'application/javascript';
20    scriptTag.id = scriptId;
21    scriptTag.src = url;
22
23    const handler = () => {
24      scriptTag.removeEventListener('load', handler);
25      injectionCallback();
26    };
27    scriptTag.addEventListener('load', handler);
28    if (doc.head) {
29      doc.head.appendChild(scriptTag);
30    }
31  };
32
33  const load = (doc, url, cb) => {
34    if (state.scriptLoaded) {
35      cb();
36    } else {
37      state.listeners.push(cb);
38      if (!doc.getElementById(state.scriptId)) {
39        injectScript(state.scriptId, doc, url, () => {
40          state.listeners.forEach((fn) => fn());
41          state.scriptLoaded = true;
42        });
43      }
44    }
45  }
46
47  return {
48    load
49  }
50}
51
52if (!window.tinymceBlazorLoader) {
53  window.tinymceBlazorLoader = CreateScriptLoader();
54}
55
56const getGlobal = () => (typeof window !== 'undefined' ? window : global);
57
58const getTiny = () => {
59  const global = getGlobal();
60  return global && global.tinymce ? global.tinymce : null;
61};
62
63const updateTinyVal = (id, val) => {
64  if (getTiny() && getTiny().get(id).getContent() !== val) {
65    getTiny().get(id).setContent(val);
66  }
67};
68
69const tinyEventHandler = (() => {
70  const eventCache = {};
71  const bindEvent = (editor, event, fn) => {
72    if (!eventCache[editor.id]) eventCache[editor.id] = [];
73    eventCache[editor.id].push({ name: event, fn });
74    editor.on(event, fn);
75  };
76  const unbindEditor = (editorId) => {
77    if (!eventCache[editorId]) return;
78    const editor = getTiny() && getTiny().get(editorId);
79    if (editor) {
80      eventCache[editorId].forEach((event) => {
81        editor.off(event.name, event.fn);
82      });
83    }
84    delete eventCache[editorId];
85  };
86  return {
87    bindEvent,
88    unbindEditor
89  }
90})();
91
92const isElementReady = (el) => {
93  if (!el || !el.offsetParent && el.offsetWidth === 0 && el.offsetHeight === 0) return false;
94  const rect = el.getBoundingClientRect();
95  return rect.width > 0 && rect.height > 0;
96};
97
98const waitForElementReady = (el, timeoutMs = 2000) => {
99  return new Promise((resolve) => {
100    if (isElementReady(el)) {
101      resolve();
102      return;
103    }
104    const start = Date.now();
105    const poll = () => {
106      if (isElementReady(el)) {
107        resolve();
108      } else if (Date.now() - start > timeoutMs) {
109        resolve(); // proceed anyway after timeout
110      } else {
111        requestAnimationFrame(poll);
112      }
113    };
114    requestAnimationFrame(poll);
115  });
116};
117
118const chunkMap = (() => {
119  const map = new Map();
120  const next = (streamId, editorId, val, index, size) => {
121    const acc = (map.has(streamId) ? map.get(streamId) : "") + val;
122    if (index === size) {
123      updateTinyVal(editorId, acc);
124      map.delete(streamId);
125    } else {
126      map.set(streamId, acc);
127    }
128  };
129  return {
130    push: next
131  };
132})();
133
134window.tinymceBlazorWrapper = {
135  insertContent: (id, content, args) => {
136    const tiny = getTiny().get(id);
137    tiny?.insertContent(content, args);
138  },
139  updateMode: (id, disable) => {
140    const tiny = getTiny().get(id);
141    if (tiny.mode && typeof tiny.mode.set === 'function') {
142      tiny.mode.set(disable ? 'readonly' : 'design');
143    } else {
144      tiny.setMode(disable ? 'readonly' : 'design');
145    }
146  },
147  updateValue: (id, streamId, value, index, chunks) => {
148    chunkMap.push(streamId, id, value, index, chunks);
149  },
150  init: (el, blazorConf, dotNetRef) => {
151    const chunkSize = 16 * 1024;
152    const update = (format, content) => {
153      const updateFn = format === 'text' ? 'UpdateText' : 'UpdateModel';
154      const chunks = Math.floor(content.length / chunkSize) + 1;
155      const streamId = (Date.now() % 100000) + '';
156      for (let i = 0; i < chunks; i++) {
157        const chunk = content.substring(chunkSize * i, chunkSize * (i + 1));
158        dotNetRef.invokeMethodAsync(updateFn, streamId, i + 1, chunk, chunks);
159      }
160    };
161    const getJsObj = (objectPath) => {
162      const jsConf = (objectPath !== null && typeof objectPath === 'string') ? objectPath.split('.').reduce((acc, current) => {
163        return acc !== undefined ? acc[current] : undefined;
164      }, window) : undefined;
165      return (jsConf !== undefined && typeof jsConf === 'object') ? jsConf : {};
166    };
167    const tinyConf = { ...getJsObj(blazorConf.jsConf), ...blazorConf.conf };
168    tinyConf.inline = blazorConf.inline;
169    tinyConf.readonly = blazorConf.disabled;
170    tinyConf.target = el;
171    tinyConf._setup = tinyConf.setup;
172
173    tinyConf.setup = (editor) => {
174      // Bind init event - critical fix: call OnEditorReady in finally block
175      tinyEventHandler.bindEvent(editor, 'init', (e) => {
176        dotNetRef.invokeMethodAsync('GetValue')
177          .then(value => {
178            editor.setContent(value);
179          })
180          .catch(err => {
181            console.error('[TinyMCE] GetValue() or setContent() failed:', err);
182          })
183          .finally(() => {
184            // CRITICAL: Signal that editor is fully ready
185            // This prevents race conditions where user types before events are bound
186            dotNetRef.invokeMethodAsync('OnEditorReady')
187              .catch(err => {
188                console.error('[TinyMCE] OnEditorReady() callback failed:', err);
189              });
190          });
191      });
192
193      // Bind change and input events
194      tinyEventHandler.bindEvent(editor, 'change', (e) => {
195        dotNetRef.invokeMethodAsync('OnChange');
196      });
197      tinyEventHandler.bindEvent(editor, 'input', (e) => {
198        dotNetRef.invokeMethodAsync('OnInput');
199      });
200
201      tinyEventHandler.bindEvent(editor, 'setcontent', (e) => {
202        const textContent = editor.getContent({ format: 'text' });
203        update('text', textContent);
204      });
205      tinyEventHandler.bindEvent(editor, blazorConf.modelEvents, (e) => {
206        const htmlContent = editor.getContent();
207        const textContent = editor.getContent({ format: 'text' });
208        update('html', htmlContent);
209        update('text', textContent);
210      });
211
212      if (tinyConf._setup && typeof tinyConf._setup === 'function') {
213        tinyConf._setup(editor, tinyEventHandler);
214      }
215    };
216
217    const doInit = () => getTiny().init(tinyConf);
218    const initWhenReady = () => {
219      if (isElementReady(el)) {
220        doInit();
221      } else {
222        waitForElementReady(el).then(doInit);
223      }
224    };
225
226    if (getTiny()) {
227      initWhenReady();
228    } else {
229      if (el && el.ownerDocument) {
230        window.tinymceBlazorLoader.load(el.ownerDocument, blazorConf.src, () => {
231          initWhenReady();
232        });
233      }
234    }
235  },
236  destroy: (el, id) => {
237    if (getTiny() && getTiny().get(id)) {
238      tinyEventHandler.unbindEditor(id);
239      getTiny().get(id).remove();
240    }
241  }
242}

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.