PageSourceSearch

https://sdkbudo.ch/assets/js/editor-content.js?v=20260920-8

js sdkbudo.ch collected 2026-10-02 19:26:09 UTC 10,661 bytes, 307 lines download raw bytes

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.