1(function ($) 2{ 3 window.sdkInitEditor = function (selector) 4 { 5 $(selector).summernote({ 6 height: 420, 7 toolbar: [ 8 ['style', ['style']], 9 ['font', ['bold', 'italic', 'underline', 'clear']], 10 ['fontname', ['fontname']], 11 ['color', ['color']], 12 ['para', ['ul', 'ol', 'paragraph']], 13 ['insert', ['link', 'picture', 'video', 'audioPlayer', 'linkImage']], 14 ['view', ['fullscreen', 'codeview', 'help']] 15 ], 16 callbacks: { 17 onImageUpload: function (files) 18 { 19 var editor = $(this); 20 Array.from(files).forEach(function (file) 21 { 22 var upload = function (image) 23 { 24 var form = new FormData(); 25 form.append('image', image, image.name || 'image.jpg'); 26 $.ajax({ 27 url: 'upload-editor-image.php', 28 method: 'POST', 29 data: form, 30 processData: false, 31 contentType: false, 32 dataType: 'json' 33 }).done(function (response) 34 { 35 if(response.url) 36 { 37 editor.summernote('insertImage', response.url); 38 } 39 }).fail(function (request) 40 { 41 var message = request.responseJSON && request.responseJSON.error; 42 window.alert(message || 'Impossible dâajouter lâimage.'); 43 }); 44 }; 45 if(file.size <= 2 * 1024 * 1024) 46 { 47 upload(file); 48 return; 49 } 50 if(!/^image\/(jpeg|png|webp)$/.test(file.type)) 51 { 52 window.alert('Lâimage doit peser moins de 2 Mo.'); 53 return; 54 } 55 var picture = new Image(); 56 var objectUrl = URL.createObjectURL(file); 57 picture.onload = function () 58 { 59 URL.revokeObjectURL(objectUrl); 60 var ratio = Math.min(1, 1600 / Math.max(picture.width, picture.height)); 61 var canvas = document.createElement('canvas'); 62 canvas.width = Math.round(picture.width * ratio); 63 canvas.height = Math.round(picture.height * ratio); 64 var context2d = canvas.getContext('2d'); 65 context2d.fillStyle = '#ffffff'; 66 context2d.fillRect(0, 0, canvas.width, canvas.height); 67 context2d.drawImage(picture, 0, 0, canvas.width, canvas.height); 68 canvas.toBlob(function (blob) 69 { 70 if(!blob || blob.size > 2 * 1024 * 1024) 71 { 72 window.alert('Impossible de réduire lâimage sous 2 Mo.'); 73 return; 74 } 75 upload(new File([blob], 'image.jpg', {type: 'image/jpeg'})); 76 }, 'image/jpeg', 0.82); 77 }; 78 picture.onerror = function () 79 { 80 URL.revokeObjectURL(objectUrl); 81 window.alert('Impossible de lire lâimage.'); 82 }; 83 picture.src = objectUrl; 84 }); 85 } 86 }, 87 buttons: { 88 audioPlayer: function (context) 89 { 90 return $.summernote.ui.button({ 91 contents: '<i class="fa fa-volume-up"></i>', 92 tooltip: 'Insérer un lecteur audio (fichier ou adresse)', 93 click: function () 94 { 95 context.invoke('editor.saveRange'); 96 var dialog = document.createElement('dialog'); 97 dialog.className = 'sdk-link-dialog'; 98 dialog.innerHTML = '<form><h3>Insérer un lecteur audio</h3>' + 99 '<label>Fichier audio (MP3, OGG ou WAV, 20 Mo maximum)<input name="audioFile" type="file" accept=".mp3,.ogg,.wav,audio/mpeg,audio/ogg,audio/wav"></label>' + 100 '<label>Ou adresse HTTPS<input name="audioUrl" type="text" placeholder="https://exemple.ch/audio.mp3"></label>' + 101 '<p class="sdk-link-error" role="alert"></p>' + 102 '<div class="sdk-link-actions"><button type="button" class="sdk-link-cancel">Annuler</button><button type="submit">Insérer</button></div></form>'; 103 var form = dialog.querySelector('form'); 104 var error = form.querySelector('.sdk-link-error'); 105 var submit = form.querySelector('button[type="submit"]'); 106 var cancel = form.querySelector('.sdk-link-cancel'); 107 var uploading = false; 108 var insertAudio = function (url) 109 { 110 dialog.close(); 111 context.invoke('editor.restoreRange'); 112 var audio = document.createElement('audio'); 113 audio.controls = true; 114 audio.preload = 'none'; 115 audio.src = url;
116 context.invoke('editor.insertNode', audio); 117 }; 118 cancel.addEventListener('click', function () 119 { 120 dialog.close(); 121 }); 122 dialog.addEventListener('cancel', function (event) 123 { 124 if(uploading) 125 { 126 event.preventDefault(); 127 } 128 }); 129 dialog.addEventListener('close', function () 130 { 131 dialog.remove(); 132 }); 133 form.addEventListener('submit', function (event) 134 { 135 event.preventDefault(); 136 var file = form.elements.audioFile.files[0]; 137 if(file) 138 { 139 if(file.size < 1 || file.size > 20 * 1024 * 1024) 140 { 141 error.textContent = 'Le fichier audio doit peser moins de 20 Mo.'; 142 return; 143 } 144 var data = new FormData(); 145 data.append('audio', file); 146 uploading = true; 147 submit.disabled = true; 148 cancel.disabled = true; 149 error.textContent = 'Envoi du fichier audioâ¦'; 150 $.ajax({ 151 url: 'upload-editor-audio.php', 152 method: 'POST', 153 data: data, 154 processData: false, 155 contentType: false, 156 dataType: 'json' 157 }).done(function (response) 158 { 159 if(response.url) 160 { 161 insertAudio(response.url); 162 return; 163 } 164 error.textContent = 'Impossible dâajouter le fichier audio.'; 165 }).fail(function (request) 166 { 167 error.textContent = request.responseJSON && request.responseJSON.error || 'Impossible dâajouter le fichier audio.'; 168 }).always(function () 169 { 170 uploading = false; 171 submit.disabled = false; 172 cancel.disabled = false; 173 }); 174 return; 175 } 176 var url = form.elements.audioUrl.value.trim(); 177 if(!/^https:\/\/\S+$/i.test(url)) 178 { 179 error.textContent = 'Choisissez un fichier audio ou saisissez une adresse HTTPS.'; 180 return; 181 } 182 insertAudio(url); 183 }); 184 document.body.appendChild(dialog); 185 dialog.showModal(); 186 } 187 }).render(); 188 }, 189 linkImage: function (context) 190 { 191 var editable = context.layoutInfo.editable[0]; 192 var selectedNode = null; 193 var rememberTarget = function (event) 194 { 195 selectedNode = event.target.closest('img, button, .cmn--btn, .cmn--button'); 196 }; 197 editable.addEventListener('mousedown', rememberTarget, true); 198 editable.addEventListener('touchstart', rememberTarget, true); 199 editable.addEventListener('click', rememberTarget, true); 200 return $.summernote.ui.button({ 201 contents: '<i class="fa fa-link"></i><i class="fa fa-image"></i>', 202 tooltip: 'Lier lâimage ou le bouton sélectionné', 203 click: function () 204 { 205 var selection = window.getSelection(); 206 var node = selection && selection.anchorNode; 207 var element = node && (node.nodeType === 1 ? node : node.parentElement); 208 var target = selectedNode || context.invoke('editor.restoreTarget') || (element && element.closest('img, button, .cmn--btn, .cmn--button')); 209 if(target && !editable.contains(target)) 210 { 211 target = null; 212 } 213 if(!target) 214 { 215 window.alert('Sélectionnez dâabord une image ou un bouton dans le contenu.'); 216 return; 217 } 218 var existingAnchor = target.closest('a'); 219 var dialog = document.createElement('dialog'); 220 dialog.className = 'sdk-link-dialog'; 221 dialog.innerHTML = '<form><h3>Lier lâimage ou le bouton</h3>' + 222 '<label>Adresse du lien<input name="url" type="text" required></label>' + 223 '<label class="sdk-link-new-window"><input name="newWindow" type="checkbox"> Ouvrir dans une nouvelle fenêtre</label>' + 224 '<p class="sdk-link-error" role="alert"></p>' + 225 '<div class="sdk-link-actions"><button type="button" class="sdk-link-cancel">Annuler</button><button type="submit">Appliquer</button></div></form>'; 226 var form = dialog.querySelector('form'); 227 var urlInput = form.elements.url; 228 var newWindowInput = form.elements.newWindow; 229 urlInput.value = existingAnchor ? existingAnchor.getAttribute('href') : 'https://'; 230 newWindowInput.checked = !!(existingAnchor && existingAnchor.target === '_blank'); 231 form.querySelector('.sdk-link-cancel').addEventListener('click', function () 232 { 233 dialog.close(); 234 }); 235 dialog.addEventListener('close', function () 236 { 237 dialog.remove(); 238 }); 239 form.addEventListener('submit', function (event) 240 { 241 event.preventDefault(); 242 var url = urlInput.value.trim(); 243 if(/^[\w.-]+\.[a-z]{2,}(?:[/:?#].*)?$/i.test(url)) 244 { 245 url = 'https://' + url; 246 } 247 if(!/^(https?:\/\/\S+|\/\S*|#\S+)$/i.test(url)) 248 { 249 form.querySelector('.sdk-link-error').textContent = 'Saisissez une adresse web valide.'; 250 return; 251 } 252 if(!editable.contains(target)) 253 { 254 form.querySelector('.sdk-link-error').textContent = 'Lâélément sélectionné nâest plus disponible.'; 255 return; 256 } 257 var openInNewWindow = newWindowInput.checked; 258 dialog.close();
259 context.invoke('editor.beforeCommand'); 260 var anchor = target.closest('a'); 261 if(target.tagName === 'BUTTON') 262 { 263 anchor = document.createElement('a'); 264 anchor.className = target.className; 265 anchor.innerHTML = target.innerHTML; 266 target.replaceWith(anchor); 267 } 268 else if(!anchor) 269 { 270 anchor = document.createElement('a'); 271 target.parentNode.insertBefore(anchor, target); 272 anchor.appendChild(target); 273 } 274 anchor.href = url; 275 if(openInNewWindow) 276 { 277 anchor.target = '_blank'; 278 anchor.relList.add('noopener', 'noreferrer'); 279 } 280 else 281 { 282 anchor.removeAttribute('target'); 283 anchor.relList.remove('noopener', 'noreferrer'); 284 if(!anchor.rel) 285 { 286 anchor.removeAttribute('rel'); 287 } 288 } 289 if(target.tagName === 'IMG') 290 { 291 anchor.classList.add('sdk-linked-image'); 292 anchor.title = url; 293 } 294 selectedNode = null; 295 context.invoke('editor.afterCommand'); 296 }); 297 document.body.appendChild(dialog); 298 dialog.showModal(); 299 urlInput.focus(); 300 urlInput.select(); 301 } 302 }).render(); 303 } 304 } 305 }); 306 }; 307})(jQuery);
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.