PluginProbe ʕ •ᴥ•ʔ
Code Manager / 1.0.0
Code Manager v1.0.0
1.0.48 1.0.47 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.19 1.0.2 1.0.20 1.0.21 1.0.22 1.0.23 1.0.24 1.0.25 1.0.26 1.0.27 1.0.28 1.0.3 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 1.0.39 1.0.4 1.0.40 1.0.41 1.0.42 1.0.43 1.0.44 1.0.45 1.0.46 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9
code-manager / assets / js / code_manager_tabmode.js
code-manager / assets / js Last commit date
clipboard.min.js 5 years ago code_manager.js 5 years ago code_manager_listmode.js 5 years ago code_manager_tabmode.js 5 years ago notify.min.js 5 years ago
code_manager_tabmode.js
677 lines
1 /**
2 * JavaScript code to build Code Manager IDE in tab mode
3 *
4 * @author Peter Schulz
5 * @since 1.0.0
6 */
7
8 const PHP_DEFAULT = '<?php\n\n?>';
9
10 var user_has_edited = {};
11
12 var current_url = window.location.href.split('?');
13 var default_url = current_url[0] + '?page=code_manager';
14
15 var href = window.location.href;
16 var pathname = href.substring(0, href.lastIndexOf('/')) + '/admin-ajax.php';
17
18 var tabs = 0;
19 var cm_editors = {};
20 var new_label_index = 0;
21 var preview_activated = false;
22
23 function option_in_code_list(option_value) {
24 found = false;
25 jQuery('#code_manager_code_list option').each(function() {
26 if (this.value === option_value) {
27 found = true;
28 return true;
29 }
30 });
31 return found;
32 }
33
34 function get_code_list(callback) {
35 jQuery.ajax({
36 method: 'POST',
37 url: pathname + '?action=code_manager_get_code_list',
38 data: {
39 wpnonce: wpnonce_get_code_list,
40 page: 'code_manager_post'
41 }
42 }).success(
43 function(msg) {
44 try {
45 obj = JSON.parse(msg);
46
47 if (Array.isArray(obj)) {
48 jQuery('#code_manager_code_list').empty();
49 for (var key in obj) {
50 if (!is_code_edited(obj[key].code_id)) {
51 jQuery('#code_manager_code_list')
52 .append(
53 jQuery('<option>', {value: obj[key].code_id})
54 .text(obj[key].code_name)
55 .attr('data-type', obj[key].code_type)
56 );
57 }
58 }
59 callback();
60 }
61 }
62 catch (e) {
63 jQuery.notify(e, 'error');
64 }
65 }
66 );
67 }
68
69 function is_code_edited(code_id) {
70 for (var editor in cm_editors) {
71 if (cm_editors[editor].tab_code_index==code_id) {
72 return true;
73 }
74 }
75 return false;
76 }
77
78 function get_code(code_id, code_name, code_type) {
79 jQuery.ajax({
80 method: 'POST',
81 url: pathname + '?action=code_manager_get_code',
82 data: {
83 wpnonce: wpnonce_get_code,
84 code_id: code_id,
85 page: 'code_manager_post'
86 }
87 }).success(
88 function(msg) {
89 if (msg==='ERR-Not authorized') {
90 jQuery.notify('Not authorized', 'error');
91 } else if (msg==='ERR-Wrong arguments') {
92 jQuery.notify('Wrong arguments', 'error');
93 } else {
94 tab_load(code_id, code_name, code_type, msg);
95 }
96 }
97 );
98 }
99
100 function tab_unselect() {
101 jQuery('.nav-tab-active').removeClass('nav-tab-active');
102 jQuery('.nav-tab-content').hide();
103 }
104
105 function tab_new(tab_label, code_id = -1, code_type = 'PHP Shortcode', code = '') {
106 tab_unselect();
107
108 code_types = '';
109 for (var code_group in code_manager_code_groups) {
110 code_types += '<optgroup label="' + code_group + '">';
111 code_manager_code_group = code_manager_code_groups[code_group];
112 for (var label in code_manager_code_group ) {
113 if (code_type===label) {
114 selected = ' selected';
115 } else {
116 selected = '';
117 }
118 code_types +=
119 '<option value="' + label + '"' + selected + '>' +
120 code_manager_code_group[label] +
121 '</option>';
122 }
123 code_types += '</optgroup>';
124 }
125
126 jQuery('#code_manager_taskbar_tabmode')
127 .append(
128 '<a id="tab-' + tabs + '" href="javascript:void(0)" class="nav-tab nav-tab-active" onclick="tab_clicked(' + tabs + ')" data-code-manager-tab="' + tabs + '">' +
129 '<span id="tab-' + tabs + '-label" contenteditable="true" class="code_manager_tab_label" data-code-manager-tab="' + tabs + '" title="Double click to change code name">' + tab_label + '</span>' +
130 '<span id="tab-' + tabs + '-icon" class="dashicons dashicons-dismiss icon_close" onclick="tab_close(this,event,' + tabs + ')"></span>' +
131 '</a>'
132 );
133
134 var editorSettings = cm_settings;
135 if (code_type.includes('html')) {
136 // Load HTML settings
137 editorSettings = wp.codeEditor.defaultSettings ? _.clone( wp.codeEditor.defaultSettings ) : {};
138 editorSettings.codemirror = _.extend(
139 {},
140 editorSettings.codemirror,
141 {
142 mode: 'html',
143 }
144 );
145 } else if (code_type.includes('css')) {
146 // Load CSS settings
147 editorSettings = wp.codeEditor.defaultSettings ? _.clone( wp.codeEditor.defaultSettings ) : {};
148 editorSettings.codemirror = _.extend(
149 {},
150 editorSettings.codemirror,
151 {
152 mode: 'css',
153 }
154 );
155 } if (code_type.includes('javascript')) {
156 // Load JavaScript settings
157 editorSettings = wp.codeEditor.defaultSettings ? _.clone( wp.codeEditor.defaultSettings ) : {};
158 editorSettings.codemirror = _.extend(
159 {},
160 editorSettings.codemirror,
161 {
162 mode: 'javascript',
163 }
164 );
165 } else {
166 // Load PHP settings (default = cm_settings)
167 if (code==='') {
168 code = PHP_DEFAULT;
169 }
170 }
171
172 code_id_displayed = code_id==-1 ? 'new' : code_id;
173 jQuery('#code_manager_workspace_tabmode')
174 .append(
175 '<div id="tab-' + tabs + '-div" class="nav-tab-content">' +
176 '<div id="tab-' + tabs + '-taskbar" class="tab_task_bar">' +
177 '<a href="javascript:void(0)" class="button non-active" id="tab-' + tabs + '-icon-save" disabled="true" onclick="tab_icon_save(' + tabs + ')" title="Save code">' +
178 '<span class="dashicons dashicons-yes-alt" style="padding-top: 4px;"></span>' +
179 '</a>' +
180 '&nbsp;' +
181 '<select id="tab-' + tabs + '-code_type" title="Select code type">' +
182 code_types +
183 '</select>' +
184 '&nbsp;' +
185 '<span>ID: ' +
186 '<span id="tab-' + tabs + '-code_id" style="font-weight: bold">' + code_id_displayed + '</span>' +
187 '</span>' +
188 '<span style="float: right;">' +
189 '<a href="javascript:void(0)" class="button" id="tab-' + tabs + '-icon-preview" onclick="tab_icon_preview(' + tabs + ')" title="Activate preview mode for this code">' +
190 '<span id="tab-' + tabs + '-icon-preview-dashicon" class="dashicons dashicons-visibility" style="padding-top: 4px; padding-right: 4px;"></span>' +
191 '</a>' +
192 '</span>' +
193 '</div>' +
194 '<div id="tab-' + tabs + '-code" class="tab_code" data-code-manager-tab="' + tabs + '">' +
195 '<textarea id="tab-' + tabs + '-content">' +
196 code +
197 '</textarea>' +
198 '</div>' +
199 '</div>'
200 );
201
202 var tab_editor = wp.codeEditor.initialize(jQuery('#tab-' + tabs + '-content'), editorSettings);
203
204 tab_editor.codemirror.focus();
205 tab_editor.codemirror.setCursor(1);
206 tab_editor.codemirror.setOption('tabindex', tabs);
207
208 var editor = {
209 tab_index: tabs,
210 tab_code_index: code_id,
211 tab_label: tab_label,
212 tab_editor: tab_editor
213 };
214 cm_editors[tabs] = editor;
215 user_has_edited[tabs] = false;
216
217 tab_editor.codemirror.on('change', function(cm_editor){
218 tab_changed(cm_editor.getOption('tabindex'));
219 });
220
221 jQuery('#tab-' + tabs + '-label').tooltip();
222 jQuery('#tab-' + tabs + '-icon').tooltip();
223 jQuery('#tab-' + tabs + '-icon-code').tooltip();
224 jQuery('#tab-' + tabs + '-icon-save').tooltip();
225 jQuery('#tab-' + tabs + '-code_type').tooltip();
226 jQuery('#tab-' + tabs + '-icon-preview').tooltip();
227 jQuery('#tab-' + tabs + '-icon-deactivate').tooltip();
228 jQuery('#tab-' + tabs + '-icon-default').tooltip();
229 jQuery('#tab-' + tabs + '-icon-current').tooltip();
230
231 jQuery('#tab-' + tabs + '-code_type').on('focus', function(event) {
232 jQuery(this).data({current_value:jQuery(this).val()});
233 });
234
235 jQuery('#tab-' + tabs + '-code_type').on('change', {tab:tabs,cid:code_id}, function(event) {
236 if (event.data.cid===-1) {
237 if (jQuery('#tab-' + event.data.tab + '-code_type option:selected').text().toLowerCase().includes('php')) {
238 // Add php tags
239 if (cm_editors[event.data.tab].tab_editor.codemirror.getValue()==='') {
240 cm_editors[event.data.tab].tab_editor.codemirror.setValue(PHP_DEFAULT);
241 }
242 } else {
243 // Remove php tags (clear field)
244 if (cm_editors[event.data.tab].tab_editor.codemirror.getValue()===PHP_DEFAULT) {
245 cm_editors[event.data.tab].tab_editor.codemirror.setValue('');
246 }
247 }
248
249 tab_changed(event.data.tab);
250 return;
251 }
252
253 html = '<div>Are you sure you want to change the code type? Due to possible errors, this code will be disabled!</div>';
254 var dialog =
255 jQuery(html)
256 .data('current_element',jQuery(this))
257 .data('current_value',jQuery.data(this, 'current_value'))
258 .data('current_tab',event.data.tab)
259 .dialog({
260 dialogClass: 'no-close',
261 title: 'Change code type?',
262 buttons: {
263 'Yes': function() {
264 tab_changed(jQuery.data(this, 'current_tab'));
265 dialog.dialog('destroy');
266 },
267 'No': function() {
268 jQuery(jQuery.data(this, 'current_element')).val(jQuery.data(this, 'current_value'));
269 dialog.dialog('destroy');
270 },
271 'Cancel': function() {
272 jQuery(jQuery.data(this, 'current_element')).val(jQuery.data(this, 'current_value'));
273 dialog.dialog('destroy');
274 }
275 }
276 });
277 });
278
279 jQuery('#tab-' + tabs + '-label').on('input', {tab:tabs}, function(event) {
280 tab_changed(event.data.tab);
281 });
282
283 jQuery('#tab-' + tabs + '-label').on('dblclick', function() {
284 var cell = this;
285 var range, selection;
286 if (document.body.createTextRange) {
287 range = document.body.createTextRange();
288 range.moveToElementText(cell);
289 range.select();
290 } else if (window.getSelection) {
291 selection = window.getSelection();
292 range = document.createRange();
293 range.selectNodeContents(cell);
294 selection.removeAllRanges();
295 selection.addRange(range);
296 }
297 });
298
299 tabs++;
300 }
301
302 function tab_changed(tabindex) {
303 user_has_edited[tabindex] = true;
304 jQuery('#tab-' + tabindex + '-icon').addClass('tab_unsaved_changes');
305 jQuery('#tab-' + tabindex + '-icon-save').removeClass('non-active').attr('disabled', false);
306 }
307
308 function activate_code_on_server(tab) {
309 if (preview_activated===tab) {
310 return;
311 }
312
313 jQuery.ajax({
314 method: 'POST',
315 url: pathname + '?action=code_manager_activate_code_preview',
316 data: {
317 wpnonce: wpnone_activate_code_preview,
318 code_id: cm_editors[tab].tab_code_index,
319 page: 'code_manager_post'
320 }
321 }).success(
322 function(msg) {
323 if (msg==='OK') {
324 jQuery.notify('Preview activated', 'success');
325 preview_activated = tab;
326 } else {
327 jQuery.notify(msg, 'error');
328 }
329 }
330 );
331 }
332
333 function tab_open() {
334 get_code_list(tab_open_callback);
335 }
336
337 function tab_open_callback() {
338 var dialog = jQuery(jQuery('#code_manager_open_frame')).dialog({
339 dialogClass: 'no-close',
340 width: "inherit",
341 title: 'Select code from list',
342 buttons: {
343 'Yes': function() {
344 if (jQuery('#code_manager_code_list').val()!=='Loading data...') {
345 get_code(
346 jQuery('#code_manager_code_list').val(),
347 jQuery('#code_manager_code_list :checked').text(),
348 jQuery('#code_manager_code_list :checked').attr('data-type')
349 );
350 }
351 dialog.dialog('close');
352 },
353 'No': function() {
354 dialog.dialog('close');
355 },
356 'Cancel': function() {
357 dialog.dialog('close');
358 }
359 }
360 });
361 }
362
363 function tab_close(elem, event, tab) {
364 if (user_has_edited[tab]===true) {
365 html = '<div>Your changes will not be saved!</div>';
366 var dialog = jQuery(html).dialog({
367 dialogClass: 'no-close',
368 title: 'Close tab?',
369 buttons: {
370 'Yes': function() {
371 close_tab(elem, tab);
372 dialog.dialog('destroy');
373 },
374 'No': function() {
375 dialog.dialog('destroy');
376 },
377 'Cancel': function() {
378 dialog.dialog('destroy');
379 }
380 }
381 });
382 } else {
383 close_tab(elem, tab);
384 }
385 event.stopPropagation();
386 }
387 function close_tab(elem, tab) {
388 jQuery(elem).parent().remove();
389 jQuery('#tab-' + tab + '-div').remove();
390
391 cm = cm_editors[tab].tab_editor.codemirror;
392 cm.setOption('mode', 'text/x-csrc');
393 cm.getWrapperElement().parentNode.removeChild(cm.getWrapperElement());
394 cm=null;
395 delete cm_editors[tab];
396 delete user_has_edited[tab];
397
398 if (!jQuery('.nav-tab-active').length) {
399 index_selected = -1;
400
401 for (editor in cm_editors) {
402 tab_index = cm_editors[editor].tab_editor.codemirror.getOption('tabindex');
403 if (index_selected>tab) {
404 break;
405 }
406 index_selected = tab_index;
407 }
408
409 if (index_selected>-1) {
410 tab_activate(index_selected);
411 }
412 }
413 }
414
415 function tab_activate(tab) {
416 jQuery('#tab-' + tab).addClass('nav-tab-active');
417 jQuery('#tab-' + tab + '-div').show();
418 }
419
420 function tab_load(code_id, tab_label, code_type, code) {
421 tab_new(tab_label, code_id, code_type, code);
422 }
423
424 function tab_clicked(tab) {
425 source_id = jQuery('.nav-tab-active').attr('data-code-manager-tab');
426 if (source_id===tab) {
427 return;
428 }
429
430 if (preview_activated==source_id) {
431 tab_icon_deactivate(tab);
432 }
433
434 jQuery('.nav-tab-active').removeClass('nav-tab-active');
435 jQuery('.nav-tab-content').hide();
436 jQuery('#tab-' + tab).addClass('nav-tab-active');
437 jQuery('#tab-' + tab + '-div').show();
438
439 if (jQuery('#tab-' + tab + '-preview').is(':visible')) {
440 tab_icon_preview(tab);
441 }
442 }
443
444 function tab_icon_save(tab) {
445 tab_label = jQuery('#tab-' + tab + '-label').text();
446 old_label = cm_editors[tab].tab_label;
447 if (old_label!==tab_label) {
448 code_name_exists(tab_label, old_label, tab)
449 } else {
450 save_code(tab);
451 }
452 }
453
454 function code_name_exists(code_name, old_label, tab) {
455 jQuery.ajax({
456 method: 'POST',
457 url: pathname + '?action=code_manager_code_name_exists',
458 data: {
459 wpnonce: wpnonce_get_code,
460 code_name: code_name,
461 page: 'code_manager_post'
462 }
463 }).success(
464 function(msg) {
465 if (msg!=='OK') {
466 jQuery.notify('Name already exists', 'error');
467 jQuery('#tab-' + tab + '-label').text(old_label);
468 } else {
469 save_code(tab);
470 }
471 }
472 );
473 }
474
475 function save_code(tab, successmsg = 'Code saved') {
476 if (user_has_edited[tab]===false) {
477 return;
478 }
479
480 cm = cm_editors[tab].tab_editor.codemirror;
481 cm.save();
482
483 jQuery.ajax({
484 method: 'POST',
485 url: pathname + '?action=code_manager_update_code',
486 data: {
487 wpnonce: wpnonce_update_code,
488 code_id: cm_editors[tab].tab_code_index,
489 code_name: jQuery('#tab-' + tab + '-label').text(),
490 code_type: jQuery('#tab-' + tab + '-code_type').val(),
491 code: jQuery('#tab-' + tab + '-content').val(),
492 page: 'code_manager_post'
493 }
494 }).success(
495 function(msg) {
496 if ( msg.substr(0, 3) === 'UPD' ) {
497 jQuery.notify(successmsg, 'success');
498 mark_tab_as_unchanged(cm);
499 } else if ( msg.substr(0, 3) === 'INS' ) {
500 code_id = msg.substr(4);
501 cm_editors[tab].tab_code_index = code_id;
502 jQuery('#tab-' + tab + '-code_id').html(code_id);
503 jQuery.notify(successmsg, 'success');
504 mark_tab_as_unchanged(cm);
505 } else {
506 if (msg.length>50) {
507 errormsg = 'ERROR : ' + msg.substr(0,50) + '...';
508 } else {
509 errormsg = msg;
510 }
511 jQuery.notify(errormsg, 'error');
512 }
513 }
514 );
515 }
516
517 function mark_tab_as_unchanged(cm_editor) {
518 tabindex = cm_editor.getOption('tabindex');
519 user_has_edited[tabindex] = false;
520 jQuery('#tab-' + tabindex + '-icon').removeClass('tab_unsaved_changes');
521 jQuery('#tab-' + tabindex + '-icon-save').addClass('non-active').attr('disabled', true);
522 }
523
524 function tab_icon_preview(tab) {
525 if (cm_editors[tab].tab_code_index===-1) {
526 jQuery.notify('Your code must be saved before it can be previewed', 'info');
527 return;
528 }
529
530 if (jQuery('#tab-' + tab + '-icon-preview-dashicon').hasClass('dashicons-visibility')) {
531 // Activate preview
532 activate_code_on_server(tab);
533
534 jQuery('#tab-' + tab + '-icon-preview').attr('title', 'Deactivate preview mode for this code');
535 jQuery('#tab-' + tab + '-icon-preview-dashicon').addClass('dashicons-hidden').removeClass('dashicons-visibility');
536 } else {
537 // Deactivate preview
538 tab_icon_deactivate(tab);
539
540 jQuery('#tab-' + tab + '-icon-preview').attr('title', 'Activate preview mode for this code');
541 jQuery('#tab-' + tab + '-icon-preview-dashicon').removeClass('dashicons-hidden').addClass('dashicons-visibility');
542 }
543 }
544
545 function tab_icon_deactivate(tab) {
546 if (preview_activated===false) {
547 return;
548 }
549
550 jQuery.ajax({
551 method: 'POST',
552 url: pathname + '?action=code_manager_deactivate_code_preview',
553 data: {
554 wpnonce: wpnone_activate_code_preview,
555 code_id: cm_editors[tab].tab_code_index,
556 page: 'code_manager_post'
557 }
558 }).success(
559 function(msg) {
560 if ( msg === 'OK' ) {
561 jQuery.notify('Preview deactivated', 'success');
562 preview_activated = false;
563 } else {
564 jQuery.notify(msg, 'error');
565 }
566 }
567 );
568 }
569
570 function unsaved_changes() {
571 has_edited = false;
572
573 for (var tabindex in user_has_edited) {
574 if (user_has_edited[tabindex]===true) {
575 has_edited = true;
576 }
577 }
578
579 return has_edited;
580 }
581
582 function reset_preview() {
583 jQuery.ajax({
584 type: 'POST',
585 url: pathname + '?action=code_manager_reset_preview',
586 data: {
587 wpnonce: wpnonce_code_manager_activate_preview,
588 page: 'code_manager_post'
589 }
590 }).success(
591 function (msg) {
592 if ( msg === 'OK' ) {
593 jQuery.notify(msg, 'success');
594 } else {
595 jQuery.notify(msg, 'info');
596 }
597 }
598 ).error(
599 function () {
600 jQuery.notify(msg, 'error');
601 }
602 );
603 }
604
605 jQuery(document).ready(function() {
606 tab_new('New');
607 new_label_index++;
608
609 jQuery('#code_manager_new').on('click', function(e) {
610 tab_new('New_' + (new_label_index++), -1);
611 });
612
613 jQuery('#code_manager_open').on('click', function(e) {
614 tab_open();
615 });
616
617 jQuery('#code_manager_cancel_file').on('click', function() {
618 jQuery('#code_manager_open_frame').hide();
619 });
620
621 jQuery('#code_manager_taskbar_tabmode').sortable();
622
623 jQuery(window).bind('keydown', function(event) {
624 if ((event.ctrlKey || event.metaKey) && String.fromCharCode(event.which).toLowerCase()==='s') {
625 if (
626 jQuery(event.target).hasClass('CodeMirror-code') ||
627 jQuery(event.target).hasClass('code_manager_tab_label')
628 ) {
629 if (jQuery(event.target).hasClass('CodeMirror-code')) {
630 tab_code = jQuery(event.target).closest('.tab_code');
631 tab = tab_code.attr('data-code-manager-tab');
632 } else {
633 tab = jQuery(event.target).attr('data-code-manager-tab');
634 }
635 if (typeof tab !== typeof undefined && tab !== false) {
636 save_code(tab);
637 event.preventDefault();
638 }
639 }
640 } else if (
641 (event.ctrlKey || event.metaKey) &&
642 String.fromCharCode(event.which).toLowerCase()==='v' &&
643 jQuery(event.target).hasClass('code_manager_tab_label')
644 ) {
645 event.preventDefault(); // Prevent ctrl-v on tab label
646 }
647 });
648
649 jQuery('.cm_menu_title').tooltip();
650 jQuery('#disable_preview').tooltip();
651 jQuery('#disable_preview').on('click', function() {
652 html = "<div>This turns of preview mode for all code IDs for all users. After a reset you might need to refresh this page to update preview icons. Do you want to continue?</div>";
653 var dialog = jQuery(html).dialog({
654 dialogClass: 'no-close',
655 title: 'Reset preview',
656 buttons: {
657 'Yes': function() {
658 dialog.dialog('destroy');
659 reset_preview();
660 },
661 'No': function() {
662 dialog.dialog('destroy');
663 },
664 'Cancel': function() {
665 dialog.dialog('destroy');
666 }
667 }
668 });
669 });
670
671 jQuery(window).on('beforeunload', function() {
672 if ( unsaved_changes() ) {
673 return 'Your changes will not be saved! Are you sure you want to leave this page?';
674 }
675 });
676 });
677