PageSourceSearch

https://www2.unesp.br/lib/custom-tinymce-plugins/portal-unesp-gallery/plugin.min.js

js unesp.br collected 2026-09-24 08:31:45 UTC 18,441 bytes, 419 lines download raw bytes

1tinymce.PluginManager.add('portal-unesp-gallery', function (editor, url) {
2    // Configuration constants
3    const GALLERY_PREVIEW_IMAGE_LIMIT = 1000;
4
5    // Helper function to create gallery shortcode
6    function createGalleryShortcode(data) {
7        return `[portal-unesp-gallery title="${data.title}" description="${data.description}" images="${data.images}"]`;
8    }
9
10    // Helper function to read placeholder data
11    function getPlaceholderData(placeholder, getAttrib) {
12        return {
13            title: getAttrib(placeholder, 'data-mce-gallery-title') || '',
14            description: getAttrib(placeholder, 'data-mce-gallery-description') || '',
15            images: getAttrib(placeholder, 'data-mce-gallery-images') || ''
16        };
17    }
18
19    // Helper function to update placeholder data
20    function setPlaceholderData(placeholder, data) {
21        editor.dom.setAttribs(placeholder, {
22            'data-mce-gallery-title': data.title,
23            'data-mce-gallery-description': data.description,
24            'data-mce-gallery-images': data.images
25        });
26    }
27
28    // Helper function to parse shortcode attributes
29    function getShortcodeAttribute(attributes, name) {
30        const match = attributes.match(new RegExp(`${name}=("([^"]*)"|'([^']*)')`));
31        return match ? (match[2] || match[3] || '') : '';
32    }
33
34    // Helper function to update gallery placeholder content
35    function updateGalleryPlaceholder(placeholder, data) {
36        // Update the placeholder attributes
37        setPlaceholderData(placeholder, data);
38
39        // Update the visible content
40        const contentDiv = editor.dom.select('div', placeholder)[0];
41        if (contentDiv) {
42            contentDiv.innerHTML = createPlaceholderContentHtml(data);
43        }
44    }
45
46    // Helper function to get fileManagerUrl from textarea
47    function getFileManagerUrl() {
48        const textarea = editor.getElement();
49        return textarea ? textarea.getAttribute('data-tinymce-file-manager-portal-unesp-gallery-url') || '' : '';
50    }
51
52    // Helper function to open gallery edit dialog
53    function openGalleryEditDialog(galleryData, updateCallback) {
54        // Save window scroll position
55        document.body.style.overflow = 'hidden';
56        const fileManagerUrl = getFileManagerUrl();
57        const dialogUrl = fileManagerUrl
58            ? url + `/gallery-dialog.php?operation=update&file_manager_url=${encodeURIComponent(fileManagerUrl)}`
59            : url + '/gallery-dialog.php?operation=update';
60        $.colorbox({
61            href: dialogUrl,
62            iframe: true,
63            width: '100%',
64            height: '100%',
65            onComplete: function () {
66                const iframe = $('.cboxIframe')[0];
67                const iframeWindow = iframe.contentWindow;
68                iframeWindow.galleryData = galleryData;
69                // Restore scroll position
70            },
71            onClosed: function () {
72                document.body.style.overflow = '';
73                // Cleanup if needed
74                if (window[updateCallback]) {
75                    delete window[updateCallback];
76                }
77            }
78        });
79    }
80
81    // Helper function to open gallery creation dialog
82    function openGalleryCreateDialog() {
83        const fileManagerUrl = getFileManagerUrl();
84        const dialogUrl = fileManagerUrl
85            ? url + `/gallery-dialog.php?operation=insert&file_manager_url=${encodeURIComponent(fileManagerUrl)}`
86            : url + '/gallery-dialog.php?operation=insert';
87        $.colorbox({
88            href: dialogUrl,
89            iframe: true,
90            width: '1200px',
91            height: '95%',
92            onClosed: function () {
93                if (window.insertGallery) {
94                    delete window.insertGallery;
95                }
96            }
97        });
98    }
99
100    // Function to handle editing a gallery
101    function handleGalleryEdit(placeholder) {
102        const galleryData = getPlaceholderData(placeholder, editor.dom.getAttrib);
103
104        window.updateGallery = function (data) {
105            updateGalleryPlaceholder(placeholder, data);
106            $.colorbox.close();
107            delete window.updateGallery;
108        };
109
110        openGalleryEditDialog(galleryData, 'updateGallery');
111    }
112
113    // Helper function to set button state based on TinyMCE version
114    function setButtonState(api, isActive) {
115        if (api.setActive) {
116            api.setActive(isActive);
117        } else if (api.setState) {
118            api.setState(isActive ? 2 : 0); // 2 is active, 0 is inactive
119        } else {
120            const buttonElement = api.getEl ? api.getEl() : null;
121            if (buttonElement) {
122                if (isActive) {
123                    editor.dom.addClass(buttonElement, 'mce-active');
124                } else {
125                    editor.dom.removeClass(buttonElement, 'mce-active');
126                }
127            }
128        }
129    }
130
131    // Register a custom icon for the toolbar button
132    editor.ui.registry.addIcon(
133        'portal-unesp-gallery',
134        '<svg xmlns="http://www.w3.org/2000/svg" viewBox="38.292 38.354 23 23" width="23px" height="23px">' +
135        '<path d="M 40.292 56.054 L 43.592 52.854 C 43.892 52.554 44.292 52.554 44.592 52.854 L 47.292 55.354 L 51.392 51.354 C 51.692 50.954 52.192 50.954 52.392 51.354 L 54.392 53.254 L 54.392 45.354 L 40.292 45.354 Z M 40.292 59.354 L 43.292 59.354 L 46.092 56.454 L 44.092 54.454 L 40.292 58.254 Z M 54.292 55.354 L 51.792 52.954 L 45.392 59.454 L 54.292 59.454 Z M 39.292 43.354 L 43.292 43.354 L 43.292 39.354 C 43.292 38.754 43.692 38.354 44.292 38.354 L 60.292 38.354 C 60.892 38.354 61.292 38.754 61.292 39.354 L 61.292 55.354 C 61.292 55.954 60.892 56.354 60.292 56.354 L 56.292 56.354 L 56.292 60.354 C 56.292 60.954 55.892 61.354 55.292 61.354 L 39.292 61.354 C 38.74 61.354 38.292 60.906 38.292 60.354 L 38.292 44.354 C 38.292 43.754 38.692 43.354 39.292 43.354 Z M 55.292 43.354 C 55.892 43.354 56.292 43.754 56.292 44.354 L 56.292 46.452 L 56.392 46.354 
135C 56.692 45.954 57.192 45.954 57.392 46.354 L 59.392 48.254 L 59.392 40.354 L 45.292 40.354 L 45.292 43.354 L 48.56 43.354 C 48.897 42.77 49.522 42.354 50.292 42.354 C 51.006 42.354 51.667 42.735 52.024 43.354 Z M 43.56 50.354 C 42.79 49.02 43.752 47.354 45.292 47.354 C 46.006 47.354 46.667 47.735 47.024 48.354 C 47.794 49.687 46.831 51.354 45.292 51.354 C 44.577 51.354 43.917 50.972 43.56 50.354 Z M 59.292 54.454 L 59.292 50.354 L 56.792 47.954 L 56.292 48.462 L 56.292 54.454 Z" fill-rule="nonzero" style="stroke-width: 1;"/>' +
136        '</svg>'
137    );
138
139    // Add a button to the editor
140    editor.ui.registry.addToggleButton('portal-unesp-gallery', {
141        // text: 'Galeria',
142        icon: 'portal-unesp-gallery',
143        tooltip: 'Inserir/editar galeria',
144        onAction: function () {
145            // Check if a gallery placeholder is selected
146            const selectedNode = editor.selection.getNode();
147            const galleryPlaceholder = editor.dom.getParent(selectedNode, '.pu-portal-unesp-gallery-placeholder');
148
149            if (galleryPlaceholder) {
150                // Edit existing gallery
151                handleGalleryEdit(galleryPlaceholder);
152            } else {
153                // Insert new gallery
154                window.insertGallery = function (data) {
155                    // Create the shortcode with the provided data
156                    const shortcode = createGalleryShortcode(data);
157                    editor.insertContent(shortcode);
158                    $.colorbox.close();
159                    delete window.insertGallery;
160                };
161
162                // Open a Colorbox modal with an iframe
163                openGalleryCreateDialog();
164            }
165        },
166        onSetup: function (api) {
167            // Function to check if a gallery is selected
168            const checkGallerySelected = function () {
169                const selectedNode = editor.selection.getNode();
170                const galleryPlaceholder = editor.dom.getParent(selectedNode, '.pu-portal-unesp-gallery-placeholder');
171                setButtonState(api, !!galleryPlaceholder);
172            };
173
174            // Initial state
175            checkGallerySelected();
176
177            // Use the selectorChangedWithUnbind method for more efficient updates
178            const selectionChangeUnbind = editor.selection.selectorChangedWithUnbind(
179                '.pu-portal-unesp-gallery-placeholder',
180                function (state) {
181                    setButtonState(api, state);
182                }
183            ).unbind;
184
185            // Also listen for NodeChange for broader selection changes
186            editor.on('NodeChange', checkGallerySelected);
187
188            // Return a function to be called when the button is removed
189            return function () {
190                selectionChangeUnbind();
191                editor.off('NodeChange', checkGallerySelected);
192            };
193        }
194    });
195
196    // Load external CSS for the gallery placeholder
197    editor.on('init', function () {
198        const linkElem = editor.dom.create('link', {
199            rel: 'stylesheet',
200            href: url + '/plugin.css'
201        });
202        editor.getDoc().getElementsByTagName('head')[0].appendChild(linkElem);
203    });
204
205    // Helper function to create image previews
206    function createImagePreview(imagesString) {
207        let imagePreview = '';
208        try {
209            if (imagesString) {
210                const imageItems = imagesString.split('||');
211                imagePreview = '<div class="pu-portal-unesp-gallery-preview">';
212                // Limit to first N images for preview
213                const previewImages = imageItems.slice(0, GALLERY_PREVIEW_IMAGE_LIMIT);
214                previewImages.forEach(item => {
215                    // Split by pipe to get URL and legend
216                    const parts = item.trim().split('~');
217                    const url = parts[0] ? parts[0].trim() : '';
218                    const legend = parts.length > 1 ? parts[1].trim() : '';
219
220                    if (!url) {
221                        return;
222                    }
223
224                    // Add image with legend as title attribute for tooltip
225                    imagePreview += `<img src="${url}" alt="Preview" title="${legend}">`;
226                });
227                if (imageItems.length > GALLERY_PREVIEW_IMAGE_LIMIT) {
228                    imagePreview += `<span class="pu-portal-unesp-gallery-more">+${imageItems.length - GALLERY_PREVIEW_IMAGE_LIMIT} mais</span>`;
229                }
230                imagePreview += '</div>';
231            }
232        } catch (e) {
233            console.error('Error creating image preview:', e);
234            imagePreview = '<div class="pu-portal-unesp-gallery-preview">Error loading preview</div>';
235        }
236        return imagePreview;
237    }
238
239    // Helper function to create placeholder inner HTML
240    function createPlaceholderContentHtml(data) {
241        const imagePreview = createImagePreview(data.images);
242        const hasTitle = Boolean(data.title && data.title.trim());
243        const hasDescription = Boolean(data.description && data.description.trim());
244        const headerHtml = (hasTitle || hasDescription)
245            ? `
246            <header class="pu-portal-unesp-gallery-header">
247                ${hasTitle ? `<h4 class="pu-portal-unesp-gallery-title">${data.title}</h4>` : ''}
248                ${hasDescription ? `<p class="pu-portal-unesp-gallery-description">${data.description}</p>` : ''}
249            </header>
250        `
251            : '';
252        return `
253            ${headerHtml}
254            ${imagePreview}
255        `;
256    }
257
258    // Helper function to create full placeholder HTML
259    function createPlaceholderHtml(data) {
260        return `<div class="pu-portal-unesp-gallery pu-portal-unesp-gallery-placeholder" 
261                    data-mce-gallery-title="${data.title}" 
262                    data-mce-gallery-description="${data.description}" 
263                    data-mce-gallery-images="${data.images}" 
264                    contenteditable="false">
265                    <div>
266                        ${createPlaceholderContentHtml(data)}
267                    </div>
268                    <div class="pu-portal-unesp-gallery-actions">
269                        <span class="bg-white"><span class="pu-portal-unesp-gallery-edit btn btn-outline-primary btn-sm"><i class="fa fa-pencil"></i> Editar</span></span>
270                        <span class="bg-white"><span class="pu-portal-unesp-gallery-delete btn btn-outline-danger btn-sm"><i class="fa fa-times"></i> Excluir</span></span>
271                    </div>
272                </div>`;
273    }
274
275    // Convert shortcodes to placeholders when content is set or loaded
276    editor.on('BeforeSetContent', function (e) {
277        e.content = e.content.replace(/\[portal-unesp-gallery([^\]]*)\]/g, function (match, attributes) {
278            // Parse attributes
279            const title = getShortcodeAttribute(attributes, 'title');
280            const description = getShortcodeAttribute(attributes, 'description');
281            const images = getShortcodeAttribute(attributes, 'images');
282
283            // Create a placeholder HTML
284            return createPlaceholderHtml({ title, description, images });
285        });
286    });
287
288    // Helper function to convert placeholders to shortcodes
289    function convertPlaceholdersToShortcodes(content) {
290        // Create a temporary DOM element to parse the HTML
291        const tempDiv = document.createElement('div');
292        tempDiv.innerHTML = content;
293
294        // Find all gallery placeholders
295        const placeholders = tempDiv.querySelectorAll('.pu-portal-unesp-gallery-placeholder');
296
297        // Replace each placeholder with its shortcode
298        placeholders.forEach(placeholder => {
299            const { title, description, images } = getPlaceholderData(
300                placeholder,
301                (el, attr) => el.getAttribute(attr)
302            );
303
304            // Create the shortcode
305            const shortcode = document.createTextNode(
306                createGalleryShortcode({ title, description, images })
307            );
308
309            // Replace the placeholder with the shortcode
310            placeholder.parentNode.replaceChild(shortcode, placeholder);
311        });
312
313        // Return the modified HTML
314        return tempDiv.innerHTML;
315    }
316
317    // Convert placeholders back to shortcodes when content is retrieved
318    editor.on('GetContent', function (e) {
319        e.content = convertPlaceholdersToShortcodes(e.content);
320    });
321
322    // Hook into the code plugin's dialog
323    editor.on('PreInit', function () {
324        // Check if the code plugin is available
325        if (editor.plugins.code) {
326            // Store the original openCodeEditor function
327            const originalOpenCodeEditor = editor.plugins.code.openCodeEditor;
328
329            // Override the openCodeEditor function
330            editor.plugins.code.openCodeEditor = function () {
331                // Convert placeholders to shortcodes in the editor content
332                const content = editor.getContent();
333                const convertedContent = convertPlaceholdersToShortcodes(content);
334
335                // Temporarily set the editor content to the converted version
336                editor.setContent(convertedContent);
337
338                // Call the original function
339                const result = originalOpenCodeEditor.apply(this, arguments);
340
341                // After the code dialog is closed, we'll need to convert shortcodes back to placeholders
342                // This happens automatically via BeforeSetContent when the code dialog applies changes
343
344                return result;
345            };
346        }
347    });
348
349    // Handle clicks on the placeholder to edit or delete
350    editor.on('click', function (e) {
351
352        // Check if clicked on gallery placeholder
353        if (e.target.closest('.pu-portal-unesp-gallery-placeholder')) {
354            // Check if edit button was clicked
355            if (e.target.closest('.pu-portal-unesp-gallery-edit')) {
356                const placeholder = editor.dom.getParent(e.target, '.pu-portal-unesp-gallery-placeholder');
357                if (placeholder) {
358                    handleGalleryEdit(placeholder);
359                }
360            }
361            // Check if delete button was clicked
362            else if (e.target.closest('.pu-portal-unesp-gallery-delete')) {
363                const placeholder = editor.dom.getParent(e.target, '.pu-portal-unesp-gallery-placeholder');
364                if (placeholder) {
365                    // Confirm deletion
366                    editor.windowManager.open({
367                        title: 'Excluir Galeria',
368                        body: {
369                            type: 'panel',
370                            items: [
371                                {
372                                    type: 'htmlpanel',
373                                    html: '<p>Tem certeza que deseja excluir esta galeria?</p>'
374                                }
375                            ]
376                        },
377                        buttons: [
378                            {
379                                type: 'cancel',
380                                text: 'Cancelar'
381                            },
382                            {
383                                type: 'submit',
384                                text: 'Excluir',
385                                primary: true
386                            }
387                        ],
388                        onSubmit: function (api) {
389                            // Remove the placeholder from the editor
390                            editor.dom.remove(placeholder);
391
392                            // Force selection update by setting cursor to current position
393                            editor.selection.collapse(true);
394
395                            // Force a node change event to update UI states
396                            editor.nodeChanged();
397
398                            // Set focus back to the editor
399                            editor.focus();
400
401                            api.close();
402                        }
403                    });
404                }
405            }
406            return false;
407        }
408    });
409
410    // Return metadata about the plugin
411    return {
412        getMetadata: function () {
413            return {
414                name: 'Portal Unesp Gallery',
415                url: 'https://www.unesp.br/manuais/portal'
416            };
417        }
418    };
419});

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.