22
|
1 <!doctype html>
|
|
2 <html>
|
|
3 <head>
|
|
4 <meta name="viewport" content="width=device-width, initial-scale=1">
|
35
|
5 <script src="/site.js"></script>
|
24
|
6 <script src="http://tinymce.luan.software/tinymce.min.js" xreferrerpolicy="origin"></script>
|
22
|
7 <style>
|
35
|
8 input[type="file"] {
|
|
9 display: none;
|
|
10 }
|
22
|
11 </style>
|
|
12 <script>
|
28
|
13 function videoIframe(url) {
|
|
14 return '<iframe data-video="'+url+'" width="560" height="315" frameborder="0" allowfullscreen src="'+url+'"></iframe>';
|
|
15 }
|
|
16
|
30
|
17 // fucking moronic javascript doesn't have \Q \E in regex
|
28
|
18 var videoHandlers = {};
|
|
19 {
|
30
|
20 let ptn1 = /^https:\/\/youtu\.be\/([a-zA-Z0-9_-]+)(?:\?t=([0-9]+))?/;
|
|
21 let ptn2 = /^https:\/\/www\.youtube\.com\/watch\?v=([a-zA-Z0-9_-]+)(?:&t=([0-9]+)s)?/;
|
28
|
22 videoHandlers.youtube = function(url) {
|
|
23 let result = url.match(ptn1) || url.match(ptn2);
|
|
24 if( result ) {
|
|
25 url = 'https://www.youtube.com/embed/' + result[1];
|
|
26 if( result[2] )
|
|
27 url += '?start=' + result[2];
|
|
28 return videoIframe(url);
|
|
29 }
|
|
30 }
|
|
31 }
|
|
32 {
|
30
|
33 let ptn = /^https:\/\/rumble\.com\/embed\/[a-z0-9]+\/\?pub=[a-z0-9]+/;
|
28
|
34 videoHandlers.rumble = function(url) {
|
|
35 if( url.match(ptn) ) {
|
|
36 return videoIframe(url);
|
|
37 }
|
|
38 }
|
|
39 }
|
|
40 {
|
30
|
41 let ptn = /^https:\/\/www\.bitchute\.com\/video\/([a-zA-Z0-9]+)\//;
|
28
|
42 videoHandlers.bitchute = function(url) {
|
|
43 let result = url.match(ptn);
|
|
44 if( result ) {
|
|
45 url = 'https://www.bitchute.com/embed/' + result[1];
|
|
46 return videoIframe(url);
|
|
47 }
|
|
48 }
|
|
49 }
|
|
50 {
|
30
|
51 let ptn = /^https:\/\/vimeo\.com\/([0-9]+)/;
|
28
|
52 videoHandlers.vimeo = function(url) {
|
|
53 let result = url.match(ptn);
|
|
54 if( result ) {
|
|
55 url = 'https://player.vimeo.com/video/' + result[1];
|
|
56 return videoIframe(url);
|
|
57 }
|
|
58 }
|
|
59 }
|
|
60 {
|
30
|
61 let ptn = /^https:\/\/dai\.ly\/([a-z0-9]+)/;
|
28
|
62 videoHandlers.dailymotion = function(url) {
|
|
63 let result = url.match(ptn);
|
|
64 if( result ) {
|
|
65 url = 'https://www.dailymotion.com/embed/video/' + result[1];
|
|
66 return videoIframe(url);
|
|
67 }
|
|
68 }
|
|
69 }
|
|
70 {
|
30
|
71 let ptn = /^https:\/\/www\.tiktok\.com\/[^/]+\/video\/([0-9]+)/;
|
28
|
72 videoHandlers.tiktok = function(url) {
|
|
73 let result = url.match(ptn);
|
|
74 if( result ) {
|
31
|
75 //let html = '<blockquote class="tiktok-embed" data-video="'+result[1]+'" style="max-width: 560px; margin-left: 0;"><section></section></blockquote>';
|
28
|
76 //html += '<script async src="https://www.tiktok.com/embed.js"></'+'script>';
|
31
|
77 let html = '<img data-video="'+result[1]+'" src="whataever">';
|
28
|
78 return html;
|
|
79 }
|
|
80 }
|
|
81 }
|
|
82 {
|
30
|
83 let ptn = /\.[a-zA-Z0-9]+$/;
|
28
|
84 videoHandlers.file = function(url) {
|
|
85 if( url.match(ptn) ) {
|
|
86 return '<video controls width="560" height><source src="'+url+'"></video>';
|
|
87 }
|
|
88 }
|
|
89 }
|
|
90
|
|
91 function videoUrlToHtml(url) {
|
|
92 for (let key in videoHandlers) {
|
|
93 let handle = videoHandlers[key];
|
|
94 let html = handle(url);
|
|
95 if(html) return html;
|
|
96 }
|
|
97 return '<a data-video="'+url+'" href="'+url+'">'+url+'</a>';
|
|
98 }
|
22
|
99
|
35
|
100 function uploaded(input,url,filename) {
|
|
101 input.parentNode.parentNode.querySelector('input[type="url"]').value = url;
|
|
102 }
|
|
103
|
|
104 let imageFileHtml = '<input type=file accept="image/*" onchange="upload(this,uploaded)">';
|
|
105 imageFileHtml += '<button class="tox-button tox-button--secondary" onclick="fileButtonClick(this)">Upload Image</button>';
|
|
106
|
|
107 let videoFileHtml = '<input type=file accept="video/*" onchange="upload(this,uploaded)">';
|
|
108 videoFileHtml += '<button class="tox-button tox-button--secondary" onclick="fileButtonClick(this)">Upload Video</button>';
|
24
|
109
|
23
|
110 function tinymceSetup(editor) {
|
24
|
111
|
35
|
112 editor.ui.registry.addButton('insertLink', {
|
|
113 icon: 'link',
|
|
114 tooltip: 'Insert link',
|
|
115 onAction: function(api) {
|
|
116 editor.windowManager.open({
|
|
117 title: 'Insert Link',
|
|
118 body: {
|
|
119 type: 'panel',
|
|
120 items: [
|
|
121 {
|
|
122 type: 'urlinput',
|
|
123 name: 'src',
|
|
124 label: 'URL'
|
|
125 },
|
|
126 {
|
|
127 type: 'input',
|
|
128 name: 'text',
|
|
129 label: 'Text to display'
|
|
130 },
|
|
131 ]
|
|
132 },
|
|
133 buttons: [
|
|
134 {
|
|
135 type: 'cancel',
|
|
136 text: 'Cancel'
|
|
137 },
|
|
138 {
|
|
139 type: 'submit',
|
|
140 text: 'Save',
|
|
141 buttonType: 'primary'
|
|
142 }
|
|
143 ],
|
|
144 onSubmit: function(dialogApi) {
|
|
145 let data = dialogApi.getData();
|
|
146 let src = data.src.value;
|
|
147 if(!src) return;
|
|
148 src = tinymce.DOM.encode(src);
|
|
149 let text = data.text;
|
|
150 let html = '<a href="' + src + '">' + text + '</a>';
|
|
151 dialogApi.close();
|
|
152 editor.insertContent(html);
|
|
153 }
|
|
154 });
|
|
155 },
|
|
156 });
|
|
157
|
31
|
158 editor.ui.registry.addButton('insertImage', {
|
|
159 icon: 'image',
|
|
160 tooltip: 'Insert image',
|
|
161 onAction: function(api) {
|
|
162 editor.windowManager.open({
|
|
163 title: 'Insert Image',
|
|
164 body: {
|
|
165 type: 'panel',
|
|
166 items: [
|
|
167 {
|
|
168 type: 'urlinput',
|
|
169 name: 'src',
|
|
170 filetype: 'image',
|
|
171 label: 'Source URL'
|
|
172 },
|
35
|
173 {
|
|
174 type: 'htmlpanel',
|
|
175 html: imageFileHtml
|
|
176 },
|
31
|
177 ]
|
|
178 },
|
|
179 buttons: [
|
|
180 {
|
|
181 type: 'cancel',
|
|
182 text: 'Cancel'
|
|
183 },
|
|
184 {
|
|
185 type: 'submit',
|
|
186 text: 'Save',
|
|
187 buttonType: 'primary'
|
|
188 }
|
|
189 ],
|
|
190 onSubmit: function(dialogApi) {
|
35
|
191 let src = dialogApi.getData().src.value;
|
31
|
192 if(!src) return;
|
|
193 src = tinymce.DOM.encode(src);
|
|
194 let html = '<img src="' + src + '">';
|
|
195 dialogApi.close();
|
|
196 editor.insertContent(html);
|
|
197 }
|
|
198 });
|
|
199 },
|
|
200 });
|
|
201
|
|
202 editor.ui.registry.addButton('insertVideo', {
|
|
203 icon: 'embed',
|
|
204 tooltip: 'Insert video',
|
|
205 onAction: function(api) {
|
|
206 editor.windowManager.open({
|
|
207 title: 'Insert Video',
|
|
208 body: {
|
|
209 type: 'panel',
|
|
210 items: [
|
|
211 {
|
|
212 type: 'urlinput',
|
|
213 name: 'src',
|
35
|
214 filetype: 'media',
|
31
|
215 label: 'Source URL'
|
|
216 },
|
35
|
217 {
|
|
218 type: 'htmlpanel',
|
|
219 html: videoFileHtml
|
|
220 },
|
31
|
221 ]
|
|
222 },
|
|
223 buttons: [
|
|
224 {
|
|
225 type: 'cancel',
|
|
226 text: 'Cancel'
|
|
227 },
|
|
228 {
|
|
229 type: 'submit',
|
|
230 text: 'Save',
|
|
231 buttonType: 'primary'
|
|
232 }
|
|
233 ],
|
|
234 onSubmit: function(dialogApi) {
|
35
|
235 let src = dialogApi.getData().src.value;
|
31
|
236 if(!src) return;
|
|
237 let html = videoUrlToHtml(src);
|
|
238 //alert(html);
|
|
239 dialogApi.close();
|
|
240 editor.insertContent(html);
|
|
241 }
|
|
242 });
|
|
243 },
|
|
244 });
|
|
245
|
24
|
246 editor.ui.registry.addToggleButton('styleCode', {
|
32
|
247 icon: 'code-sample',
|
24
|
248 tooltip: 'Code',
|
|
249 onAction: function(api) {
|
31
|
250 editor.execCommand('mceToggleFormat', false, 'code');
|
24
|
251 },
|
|
252 onSetup: function(api) {
|
|
253 api.setActive(editor.formatter.match('code'));
|
|
254 let changed = editor.formatter.formatChanged('code', api.setActive);
|
|
255 return function() { changed.unbind(); };
|
|
256 }
|
|
257 });
|
|
258
|
|
259 editor.ui.registry.addMenuButton('styleText', {
|
|
260 icon: 'format',
|
|
261 tooltip: 'Text',
|
|
262 fetch: function(callback) {
|
|
263 callback([
|
|
264 'fontsize',
|
|
265 'forecolor',
|
|
266 ])
|
|
267 }
|
23
|
268 });
|
26
|
269
|
31
|
270 editor.on( 'init', function(e) {
|
|
271 editor.focus();
|
|
272 } );
|
23
|
273 }
|
|
274
|
22
|
275 tinymce.init({
|
|
276 selector: 'textarea',
|
23
|
277 setup: tinymceSetup,
|
27
|
278 //menubar: false,
|
26
|
279 statusbar: false,
|
32
|
280 plugins: ['link', 'image', 'media', 'lists', 'code', 'autoresize'],
|
35
|
281 toolbar: 'link insertLink insertImage insertVideo | styleCode bold italic underline strikethrough superscript styleText | blockquote numlist bullist',
|
26
|
282 autoresize_bottom_margin: 0,
|
22
|
283 link_target_list: false,
|
|
284 link_title: false,
|
|
285 object_resizing: false,
|
|
286 contextmenu: false,
|
|
287 text_patterns: false,
|
26
|
288 content_style: 'img {max-width: 500px;} p {margin: 0}',
|
22
|
289 extended_valid_elements: 'b,i',
|
|
290 formats: {
|
|
291 bold: { inline: 'b' },
|
|
292 italic: {inline: 'i'},
|
|
293 underline: {inline: 'u'},
|
|
294 },
|
|
295 });
|
|
296
|
|
297 function log() {
|
|
298 console.log(tinymce.activeEditor.getContent());
|
|
299 }
|
|
300 </script>
|
|
301 </head>
|
|
302 <body>
|
35
|
303 <p>
|
|
304 <a href="https://www.tiny.cloud/">TinyMCE</a>
|
|
305 <a href="https://github.com/tinymce/tinymce">source</a>
|
|
306 </p>
|
22
|
307 <textarea></textarea>
|
|
308 <p><button onclick="log()">log</button></p>
|
|
309 </body>
|
|
310 </html>
|