| 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> |