PluginProbe
Photonic Gallery & Lightbox for Flickr, SmugMug & Others / 3.37
Photonic Gallery & Lightbox for Flickr, SmugMug & Others v3.37
3.37 3.36 3.35 3.34 3.33 2.19 2.20 2.21 2.22 2.23 2.24 2.25 2.26 2.27 2.28 2.29 2.30 2.31 2.32 2.33 2.34 2.40 2.41 2.42 2.43 All 142 releases
photonic / include / js / admin / mce.js

mce.js in Photonic Gallery & Lightbox for Flickr, SmugMug & Others 3.37, at include/js/admin/mce.js

359 lines 12.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 let photonicClickedNode;
2 (function($) {
3 tinymce.PluginManager.add('photonic', function(editor, url) {
4 const wizardButton = document.querySelector('#photonic-add-gallery');
5 const nativeMediaLibrary = new PhotonicWPNativeUI(sendDataToWizard, getDataFromWizard);
6 const mceTab = document.getElementById('content-tmce'), htmlTab = document.getElementById('content-html');
7 let lastClickedTab = mceTab; // We are in the MCE Editor, so this must be the clicked tab.
8
9 nativeMediaLibrary.waitForIFrame();
10
11 function html(cls, data, type) {
12 data = window.encodeURIComponent(data);
13 return '<img src="' + tinymce.Env.transparentSrc + '" class="wp-media mceItem ' + cls + '" ' + 'data-wp-media="' + data + '" data-mce-resize="false" data-mce-placeholder="1" alt="" title="Photonic ' + type + ' gallery" />';
14 }
15
16 function restoreMediaShortcodes(content) {
17 function getAttr(str, name) {
18 name = new RegExp(name + '=\"([^\"]+)\"').exec(str);
19 return name ? window.decodeURIComponent(name[1]) : '';
20 }
21
22 let newContent;
23 newContent = content.replace(/(?:<p(?: [^>]+)?>)*(<img [^>]+>)(?:<\/p>)*/g, function(match, image) {
24 const data = getAttr(image, 'data-wp-media');
25 if (data) {
26 return '<p>' + data + '</p>';
27 }
28
29 return match;
30 });
31 return newContent;
32 }
33
34 editor.on('mouseup', function(event) {
35 const dom = editor.dom,
36 node = event.target;
37
38 function unselect() {
39 dom.removeClass(dom.select('img.wp-media-selected'), 'wp-media-selected');
40 }
41
42 if (node.nodeName === 'IMG' && dom.getAttrib(node, 'data-wp-media')) {
43 // Don't trigger on right-click
44 unselect();
45 }
46 });
47
48 // Display gallery, audio or video instead of img in the element path
49 editor.on('GetContent', function(event) {
50 if (event.get) {
51 event.content = restoreMediaShortcodes(event.content);
52 }
53 });
54
55 // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('...');
56 editor.addCommand('Photonic_Gallery', function(ui, v) {
57 const node = editor.selection.getNode();
58 const type = v.type;
59
60 const shortcode = wp.mce.views.getText(node);
61 const shortcodeObj = wp.shortcode.next(Photonic_Admin_JS.shortcode, shortcode);
62 const shortcodeAttr = shortcodeObj.shortcode.attrs.named;
63
64 const template = (new DOMParser().parseFromString(document.getElementById('tmpl-photonic-editor-' + type).innerHTML.replace('<script type="text/html" id="tmpl-photonic-editor-' + type + '">', '').replace('</script>', ''), 'text/html')).body
65
66 // First, set all the inputs and selects in the template to the shortcode values
67 template.querySelectorAll('input').forEach(input => {
68 if (shortcodeAttr[input.name] !== undefined) {
69 template.querySelector('input[name="' + input.name + '"]').value = shortcodeAttr[input.name];
70 }
71 else if (input.getAttribute('alt_id') && shortcodeAttr[input.getAttribute('alt_id')] !== undefined) {
72 template.querySelector('input[alt_id="' + input.getAttribute('alt_id') + '"]').value = shortcodeAttr[input.getAttribute('alt_id')];
73 }
74 });
75
76 template.querySelectorAll('select').forEach(select => {
77 if (shortcodeAttr[select.name] !== undefined) {
78 template.querySelector('select[name="' + select.name + '"]').value = shortcodeAttr[select.name];
79 }
80 else if (select.getAttribute('alt_id') && shortcodeAttr[select.getAttribute('alt_id')] !== undefined) {
81 template.querySelector('select[alt_id="' + select.getAttribute('alt_id') + '"]').value = shortcodeAttr[select.getAttribute('alt_id')];
82 }
83 });
84
85 // Passing the template to the WindowManager has issues retrieving values, so we now dynamically get the fields
86 // The previous step is necessary, otherwise the shortcode values are not passed.
87 const fields = [];
88 template.querySelectorAll('label').forEach(row => {
89 const label = row.querySelector('span.label').innerText;
90 const field = row.querySelector('input, select');
91 const tooltip = row.querySelector('span.hint') ? row.querySelector('span.hint') : undefined;
92
93 if (field) {
94 const fieldObj = {
95 type: field.nodeName === 'INPUT' ? 'textbox' : (field.nodeName === 'SELECT' ? 'listbox' : ''),
96 name: field.name,
97 label: label,
98 value: field.value,
99 tooltip: tooltip.innerText
100 };
101 if (field.nodeName === 'SELECT') {
102 fieldObj.values = [];
103 Array.from(field.children).forEach(option => {
104 fieldObj.values.push({
105 text: option.innerText,
106 value: option.value
107 });
108 });
109 }
110 fields.push(fieldObj);
111 }
112 });
113
114 editor.windowManager.open({
115 title: 'Photonic Shortcode Editor - ' + (type === 'wp' ? 'WP' : type.substr(0,1).toUpperCase() + type.substr(1)),
116 id: 'photonic-gallery-editor',
117 width: 800,
118 height: 400,
119 body: fields,
120 onsubmit: function(e) {
121 let insertCode = '[' + Photonic_Admin_JS.shortcode + ' type="' + (type === 'wp' ? 'default' : type) + '"';
122 const newCode = e.data;
123 Object.entries(newCode).forEach(([idx, obj]) => {
124 if (obj !== '') {
125 insertCode += ' ' + idx + "='" + decodeURIComponent(obj).replace(/<[^>]+>/g, '') + "'";
126 }
127 });
128 insertCode += ']';
129
130 node.setAttribute('data-wpview-text', encodeURIComponent(insertCode));
131 }
132 });
133 });
134
135 // Register the command so that it can be invoked by using tinyMCE.activeEditor.execCommand('...');
136 editor.addCommand('Photonic_Gallery_Wizard', function(ui, v) {
137 photonicClickedNode = editor.selection.getNode();
138
139 // No s**t, but the TB code ignores everything after the TB_iframe=true parameter, hence appending TB_iframe=true to the end
140 // tb_show('Edit Gallery', (Photonic_Admin_JS.flow_url + '&shortcode=' + scParameter).replace('&TB_iframe=true', '') + '&TB_iframe=true');
141 tb_show('Edit Gallery', Photonic_Admin_JS.flow_url);
142 });
143
144 function verifyHTML(string) {
145 const settings = {};
146
147 if (!window.tinymce) {
148 return string.replace(/<[^>]+>/g, '');
149 }
150
151 if (!string || (string.indexOf('<') === -1 && string.indexOf('>') === -1)) {
152 return string;
153 }
154
155 const schema = new window.tinymce.html.Schema(settings);
156 const parser = new window.tinymce.html.DomParser(settings, schema);
157 const serializer = new window.tinymce.html.Serializer(settings, schema);
158
159 return serializer.serialize(parser.parse(string, { forced_root_block: false }));
160 }
161
162 function getPhotonicType(img) {
163 let type = 'default';
164 if (img.classList.contains('photonic-gallery-flickr')) {
165 type = 'flickr';
166 }
167 else if (img.classList.contains('photonic-gallery-google')) {
168 type = 'google';
169 }
170 else if (img.classList.contains('photonic-gallery-smugmug')) {
171 type = 'smugmug';
172 }
173 else if (img.classList.contains('photonic-gallery-zenfolio')) {
174 type = 'zenfolio';
175 }
176 else if (img.classList.contains('photonic-gallery-instagram')) {
177 type = 'instagram';
178 }
179 return type;
180 }
181
182 wp.mce.photonic_view_renderer = _.extend({}, wp.media.gallery, {
183 shortcode_string: Photonic_Admin_JS.shortcode,
184 state: [ 'gallery-edit' ],
185 template: wp.media.template('editor-gallery'),
186
187 // Lifted verbatim from mce-view.js, "base" code
188 edit: function(text, update) {
189 const media = wp.media;
190 const type = this.type;
191 if (type === Photonic_Admin_JS.shortcode && type !== 'gallery') {
192 if (Photonic_Admin_JS.disable_flow) {
193 editor.execCommand('Photonic_Gallery', '', {type: 'default'});
194 }
195 else {
196 editor.execCommand('Photonic_Gallery_Wizard', '', {type: 'default'});
197 }
198 return;
199 }
200
201 let frame = media[ type ].edit(text);
202
203 this.pausePlayers && this.pausePlayers();
204
205 _.each(this.state, function(state) {
206 frame.state(state).on('update', function(selection) {
207 update(media[ type ].shortcode(selection).string(), type === 'gallery');
208 });
209 });
210
211 frame.on('close', function() {
212 frame.detach();
213 });
214
215 frame.open();
216 },
217
218 initialize: function() {
219 const shortcodeAttr = this.shortcode.attrs.named;
220 let type;
221 if (shortcodeAttr['type'] === undefined) {
222 type = Photonic_Admin_JS.default_gallery_type;
223 }
224 else {
225 type = shortcodeAttr['type'];
226 }
227 if (type === 'default') {
228 // Lifted, almost verbatim, from wp-includes/js/mce-view.js. This is the default gallery processing code.
229 // If Photonic_Admin_JS.shortcode != 'gallery', the code from WP will be called anyway. Otherwise this code will be triggered
230 // if type == 'default'.
231 const media = wp.media;
232 let attachments = media.gallery.attachments(this.shortcode, media.view.settings.post.id),
233 attrs = this.shortcode.attrs.named,
234 self = this;
235
236 attachments.more()
237 .done(function () {
238 attachments = attachments.toJSON();
239
240 _.each(attachments, function (attachment) {
241 if (attachment.sizes) {
242 if (attrs.size && attachment.sizes[attrs.size]) {
243 attachment.thumbnail = attachment.sizes[attrs.size];
244 }
245 else if (attachment.sizes.thumbnail) {
246 attachment.thumbnail = attachment.sizes.thumbnail;
247 }
248 else if (attachment.sizes.full) {
249 attachment.thumbnail = attachment.sizes.full;
250 }
251 }
252 });
253
254 self.render(self.template({
255 verifyHTML: verifyHTML,
256 attachments: attachments,
257 columns: attrs.columns ? parseInt(attrs.columns, 10) : media.galleryDefaults.columns
258 }), attrs);
259 })
260 .fail(function (jqXHR, textStatus) {
261 self.setError(textStatus);
262 }
263 );
264 }
265 else {
266 this.content = html('wp-gallery photonic-gallery photonic-gallery-' + type, this.shortcode.string(), type === 'wp' ? 'WP' : type.substr(0, 1).toUpperCase() + type.substr(1));
267 }
268 }
269 });
270
271 editor.addButton('wp_view_edit', {
272 tooltip: 'Edit ', // trailing space is needed, used for context
273 icon: 'dashicon dashicons-edit',
274 onclick: function() {
275 const node = editor.selection.getNode();
276 if (editor.dom.hasClass(node, 'wpview')) {
277 const img = node.querySelector('img.photonic-gallery'); // Placeholder
278 const div = node.querySelector('div.gallery');
279
280 if ((img === null || !img.classList.contains('photonic-gallery')) && editor.dom.hasClass( node, 'wpview' )) { // Open Native Gallery editor if that is what is in "wpview".
281 wp.mce.views.edit(editor, node);
282 }
283 else if ((div && Photonic_Admin_JS.shortcode !== 'gallery') || img.classList.contains('photonic-gallery')) {
284 const type = getPhotonicType(img);
285 if (Photonic_Admin_JS.disable_flow) {
286 editor.execCommand('Photonic_Gallery', '', {type: type});
287 }
288 else {
289 editor.execCommand('Photonic_Gallery_Wizard', '', {type: type});
290 }
291 }
292 }
293 }
294 });
295
296 editor.on('click keyup', function(e) {
297 if (e.target.nodeName === 'IMG' && e.target.className.indexOf('photonic-gallery') > -1) {
298 e.preventDefault();
299
300 const type = getPhotonicType(e.target);
301 if (Photonic_Admin_JS.disable_flow) {
302 editor.execCommand('Photonic_Gallery', '', {type: type});
303 }
304 else {
305 editor.execCommand('Photonic_Gallery_Wizard', '', {type: type});
306 }
307 return false;
308 }
309 else {
310 return false;
311 }
312 });
313
314 function sendDataToWizard(messageChannel) {
315 const shortcode = wp.mce.views.getText(photonicClickedNode);
316 const shortcodeObj = wp.shortcode.next(Photonic_Admin_JS.shortcode, shortcode);
317
318 // Second, send the actual shortcode
319 messageChannel.port1.postMessage({
320 type: 'photonicMCENode',
321 object: {
322 shortcode: shortcodeObj
323 }
324 });
325 }
326
327 function getDataFromWizard(data) {
328 if (photonicClickedNode) {
329 photonicClickedNode.setAttribute('data-wpview-text', encodeURIComponent(data.html));
330 }
331 else {
332 editor.execCommand('mceInsertContent', false, data.html);
333 }
334 }
335
336 if (wizardButton) {
337 wizardButton.addEventListener('click', e => {
338 // Need to null this out, since a user can click on the button to add a new gallery, but the `photonicClickedNode` might be carrying the previously clicked node's data
339 photonicClickedNode = null;
340 });
341 }
342
343 if (mceTab && htmlTab) {
344 [mceTab, htmlTab].forEach(button => {
345 button.addEventListener('click', e => {
346 if (lastClickedTab.id !== button.id) {
347 lastClickedTab = button;
348 if (button.id === mceTab.id) {
349 nativeMediaLibrary.waitForIFrame();
350 }
351 }
352 });
353 });
354 }
355
356 wp.mce.views.register(Photonic_Admin_JS.shortcode, wp.mce.photonic_view_renderer);
357 });
358 })(jQuery);
359