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