PluginProbe
WPIDE – File Manager & Code Editor / 2.0.7
WPIDE – File Manager & Code Editor v2.0.7
3.5.8 3.5.7 2.0.14 2.0.15 2.0.16 2.0.2 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.0.9 2.1 2.2 2.3 2.3.1 2.3.2 2.4.0 2.5 2.6 3.0 3.1 3.2 3.3 3.4 All 54 releases
wpide / js / load-editor.js

load-editor.js in WPIDE – File Manager & Code Editor 2.0.7, at js/load-editor.js

741 lines 21.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 var autocompleting = false;
2 var autocompletelength = 2;
3 var editor = '';
4
5 var saved_editor_sessions = [];
6 var saved_undo_manager = [];
7 var last_added_editor_session = 0;
8 var current_editor_session = 0;
9
10 var EditSession = require('ace/edit_session').EditSession;
11 var UndoManager = require('ace/undomanager').UndoManager;
12 var Search = require("ace/search").Search;
13 var TokenIterator = require("ace/token_iterator").TokenIterator;
14
15 var oHandler;
16
17 function onSessionChange(e) {
18
19 if( editor.getSession().enable_autocomplete === false){
20 return;
21 }
22
23 //don't continue with autocomplete if /n entered
24 try {
25 if ( e.data.text.charCodeAt(0) === 10 ){
26 return;
27 }
28 }catch(error){}
29
30 try {
31 if ( e.data.action == 'removeText' ){
32
33 if (autocompleting) {
34 autocompletelength = (autocompletelength - 1) ;
35 }else{
36 return;
37 }
38 }
39 }catch(error){}
40
41
42 //get current cursor position
43 range = editor.getSelectionRange();
44 //take note of selection row to compare with search
45 cursor_row = range.start.row;
46
47 try{
48 //quit autocomplete if we are writing a "string"
49 var iterator = new TokenIterator(editor.getSession(), range.start.row, range.start.column);
50 var current_token_type = iterator.getCurrentToken().type;
51 if(current_token_type == "string" || current_token_type == "comment"){
52 return;
53 }
54 }catch(error){}
55
56 if (range.start.column > 0){
57
58 //search for command text user has entered that we need to try match functions against
59 var search = new Search().set({
60 needle: "[\\n \.\)\(]",
61 backwards: true,
62 wrap: false,
63 caseSensitive: false,
64 wholeWord: false,
65 regExp: true
66 });
67 //console.log(search.find(editor.getSession()));
68
69 range = search.find(editor.getSession());
70
71 if (range) range.start.column++;
72
73 }else{ //change this to look char position, if it's starting at 0 then do this
74
75 range.start.column = 0;
76 }
77
78 if (! range || range.start.row < cursor_row ){
79 //forse the autocomplete check on this row starting at column 0
80 range = editor.getSelectionRange();
81 range.start.column = 0;
82 }
83
84
85 //console.log("search result - start row " + range.start.row + "-" + range.end.row + ", column " + range.start.column+ "-" + range.end.column);
86 //console.log(editor.getSelection().getRange());
87
88 range.end.column = editor.getSession().getSelection().getCursor().column +1;//set end column as cursor pos
89
90 //console.log("[ \.] based: " + editor.getSession().doc.getTextRange(range));
91
92 //no column lower than 1 thanks
93 if (range.start.column < 1) {
94 range.start.column = 0;
95 }
96
97 //console.log("after row " + range.start.row + "-" + range.end.row + ", column " + range.start.column+ "-" + range.end.column);
98 //get the editor text based on that range
99 var text = editor.getSession().doc.getTextRange(range);
100 $quit_onchange = false;
101
102 //console.log(text);
103
104 //console.log("Searching for text \""+text+"\" length: "+ text.length);
105 if (text.length < 3){
106
107 wpide_close_autocomplete();
108 return;
109 }
110
111 autocompletelength = text.length;
112
113 //create the dropdown for autocomplete
114 var sel = editor.getSelection();
115 var session = editor.getSession();
116 var lead = sel.getSelectionLead();
117
118 var pos = editor.renderer.textToScreenCoordinates(lead.row, lead.column);
119 var ac; // #ac is auto complete html select element
120
121
122
123 if( document.getElementById('ac') ){
124 ac=document.getElementById('ac');
125
126 //add editor click listener
127 //editor clicks should hide the autocomplete dropdown
128 editor.container.addEventListener('click', function(e){
129
130 wpide_close_autocomplete();
131
132 autocompleting=false;
133 autocompletelength = 2;
134
135 }, false);
136
137 } //end - create initial autocomplete dropdown and related actions
138
139
140 //calulate the editor container offset
141 var obj=editor.container;
142
143 var curleft = 0;
144 var curtop = 0;
145
146 if (obj.offsetParent) {
147
148 do {
149 curleft += obj.offsetLeft;
150 curtop += obj.offsetTop;
151 } while (obj = obj.offsetParent);
152
153 }
154
155
156 //position autocomplete
157 ac.style.top= ((pos.pageY - curtop)+20) + "px";
158 ac.style.left= ((pos.pageX - curleft)+10) + "px";
159 ac.style.display='block';
160 ac.style.background='white';
161
162
163 //remove all options, starting a fresh list
164 ac.options.length = 0;
165
166
167 //loop through WP tags and check for a match
168 if (autocomplete_wordpress){
169 var tag;
170 for(i in autocomplete_wordpress) {
171 //if(!html_tags.hasOwnProperty(i) ){
172 // continue;
173 //}
174
175 tag= i;
176 //see if the tag is a match
177 if( text !== tag.substr(0,text.length) ){
178 continue;
179 }
180
181 //add parentheses
182 tag = tag + "()";
183
184 var option = document.createElement('option');
185 option.text = tag;
186 option.value = tag;
187 option.setAttribute('title', wpide_app_path + 'images/wpac.png');//path to icon image or wpac.png
188
189
190 try {
191 ac.add(option, null); // standards compliant; doesn't work in IE
192 }
193 catch(ex) {
194 ac.add(option); // IE only
195 }
196
197 }//end for
198 }//end php autocomplete
199
200 //loop through PHP tags and check for a match
201 if (autocomplete_php){
202 var tag;
203 for(i in autocomplete_php) {
204 //if(!html_tags.hasOwnProperty(i) ){
205 // continue;
206 //}
207
208 tag= i;
209 //see if the tag is a match
210 if( text !== tag.substr(0,text.length) ){
211 continue;
212 }
213
214 //add parentheses
215 tag = tag + "()";
216
217 var option = document.createElement('option');
218 option.text = tag;
219 option.value = tag;
220 option.setAttribute('title', wpide_app_path + 'images/phpac.png');//path to icon image or wpac.png
221
222 try {
223 ac.add(option, null); // standards compliant; doesn't work in IE
224 }
225 catch(ex) {
226 ac.add(option); // IE only
227 }
228
229
230 }//end for
231 }//end php autocomplete
232
233
234 //check for matches
235 if ( ac.length === 0 ) {
236 wpide_close_autocomplete();
237 } else {
238
239 ac.selectedIndex=0;
240 autocompleting=true;
241 oHandler = jQuery("#ac").msDropDown({visibleRows:10, rowHeight:20}).data("dd");
242
243 jQuery("#ac_child").click(function(item){
244 //console.log(item.srcElement.textContent);
245 selectACitem(item.srcElement.textContent);
246 });
247
248 jQuery("#ac_child a").mouseover(function(item){
249 //show the code in the info panel
250
251 //if this command item is enabled
252 if (jQuery("#"+item.srcElement.id).hasClass("enabled")){
253
254 var selected_item_index = jQuery("#"+item.srcElement.id).index();
255
256 if (selected_item_index > -1){ //if select item is valid
257
258 //set the selected menu item
259 oHandler.selectedIndex(selected_item_index);
260 //show command help panel for this command
261 wpide_function_help();
262
263 }
264 }
265
266 });
267
268
269 jQuery("#ac_child").css("z-index", "9999");
270 jQuery("#ac_child").css("background-color", "#ffffff");
271 jQuery("#ac_msdd").css("z-index", "9999");
272 jQuery("#ac_msdd").css("position", "absolute");
273 jQuery("#ac_msdd").css("top", ac.style.top);
274 jQuery("#ac_msdd").css("left", ac.style.left);
275
276 //show command help panel for this command
277 wpide_function_help();
278
279 }
280
281 }
282
283 function token_test(){
284
285 var iterator = new TokenIterator(editor.getSession(), range.start.row, range.start.column);
286 var current_token_type = iterator.getCurrentToken().type;
287 return iterator.getCurrentToken();
288 }
289
290 function wpide_close_autocomplete(){
291 if (ac) ac.style.display='none';
292 if (oHandler) oHandler.close();
293
294 autocompleting = false;
295
296 //clear the text in the command help panel
297 //jQuery("#wpide_info_content").html("");
298 }
299
300 function wpide_function_help() {
301 //mouse over
302
303 try
304 {
305 var selected_command_item = jQuery("#ac_child a.selected");
306
307
308 key = selected_command_item.find("span.ddTitleText").text().replace("()","");
309
310 //wordpress autocomplete
311 if ( selected_command_item.find("img").attr("src").indexOf("wpac.png") >= 0){
312
313 if (autocomplete_wordpress[key].desc != undefined){
314
315 //compose the param info
316 var param_text ="";
317 for(i=0; i<autocomplete_wordpress[key].params.length; i++) {
318
319 //wrap params in a span to highlight not required
320 if (autocomplete_wordpress[key].params[i].required == "no"){
321 param_text = param_text + "<span class='wpide_func_arg_notrequired'>" + autocomplete_wordpress[key].params[i]['param'] + "<em>optional</em></span><br /> <br />";
322 }else{
323 param_text = param_text + autocomplete_wordpress[key].params[i]['param'] + "<br /> <br />";
324 }
325
326 }
327 //compose returns text
328 if (autocomplete_wordpress[key].returns.length > 0){
329 returns_text = "<br /><br /><strong>Returns:</strong> " + autocomplete_wordpress[key].returns;
330 }else{
331 returns_text = "";
332 }
333
334
335 //output command info
336 jQuery("#wpide_info_content").html(
337 "<strong class='wpide_func_highlight_black'>Function: </strong><strong class='wpide_func_highlight'>" + key + "(</strong><br />" +
338 "<span class='wpide_func_desc'>" + autocomplete_wordpress[key].desc + "</span><br /><br /><em class='wpide_func_params'>" +
339 param_text + "</em>"+
340 "<strong class='wpide_func_highlight'>)</strong> " +
341 returns_text
342 );
343 }
344
345 }
346
347 //php autocomplete
348 if ( selected_command_item.find("img").attr("src").indexOf("phpac.png") >= 0){
349
350 if (autocomplete_php[key].returns != undefined){
351
352 //params text
353 var param_text ="";
354 for(i=0; i<autocomplete_php[key].params.length; i++) {
355
356 //wrap params in a span to highlight not required
357 if (autocomplete_php[key].params[i].required == "no"){
358 param_text = param_text + "<span class='wpide_func_arg_notrequired'>" + autocomplete_php[key].params[i]['param'] + "<em>optional</em></span><br /> <br />";
359 }else{
360 param_text = param_text + autocomplete_php[key].params[i]['param'] + "<br /> <br />";
361 }
362
363 }
364 //compose returns text
365 if (autocomplete_php[key].returns.length > 0){
366 returns_text = "<br /><br /><strong>Returns:</strong> " + autocomplete_php[key].returns;
367 }else{
368 returns_text = "";
369 }
370
371 jQuery("#wpide_info_content").html(
372 "<strong class='wpide_func_highlight_black'>Function: </strong><strong class='wpide_func_highlight'>" + key + "(</strong><br />" +
373 autocomplete_php[key].desc + "<br /><br /><em class='wpide_func_params'>" +
374 param_text + "</em>" +
375 "<strong class='wpide_func_highlight'>)</strong>" +
376 returns_text
377 );
378
379 }
380
381 }
382
383
384
385 }
386 catch(err)
387 {
388 //Handle errors here
389 }
390
391 }
392
393 //open another file and add to editor
394 function wpide_set_file_contents(file, callback_func){
395 "use strict";
396
397 //ajax call to get file contents we are about to edit
398 var data = { action: 'wpide_get_file', filename: file, _wpnonce: jQuery('#_wpnonce').val(), _wp_http_referer: jQuery('#_wp_http_referer').val() };
399
400 jQuery.post(ajaxurl, data, function(response) {
401 var the_path = file.replace(/^.*[\\\/]/, '');
402 var the_id = "wpide_tab_" + last_added_editor_session;
403
404 //enable editor now we have a file open
405 jQuery('#fancyeditordiv textarea').removeAttr("disabled");
406
407 jQuery("#wpide_toolbar_tabs").append('<span id="'+the_id+'" sessionrel="'+last_added_editor_session+'" title=" '+file+' " rel="'+file+'" class="wpide_tab">'+ the_path +'</a> <a class="close_tab" href="#">x</a> ');
408
409 saved_editor_sessions[last_added_editor_session] = new EditSession(response);//set saved session
410 saved_editor_sessions[last_added_editor_session].on('change', onSessionChange);
411 saved_undo_manager[last_added_editor_session] = new UndoManager(editor.getSession().getUndoManager());//new undo manager for this session
412
413 last_added_editor_session++; //increment session counter
414
415 //add click event for the new tab.
416 //We are actually clearing the click event and adding it again for all tab elements, it's the only way I could get the click handler listening on all dynamically added tabs
417 jQuery(".wpide_tab").off('click').on("click", function(event){
418 event.preventDefault();
419
420 jQuery('input[name=filename]').val( jQuery(this).attr('rel') );
421
422 //save current editor into session
423 //get old editor out of session and apply to editor
424 var clicksesh = jQuery(this).attr('sessionrel'); //editor id number
425 saved_editor_sessions[ clicksesh ].setUndoManager(saved_undo_manager[ clicksesh ]);
426 editor.setSession( saved_editor_sessions[ clicksesh ] );
427
428 //set this tab as active
429 jQuery(".wpide_tab").removeClass('active');
430 jQuery(this).addClass('active');
431
432 var currentFilename = jQuery(this).attr('rel');
433 var mode;
434
435 //turn autocomplete off initially, then enable as needed
436 editor.getSession().enable_autocomplete = false;
437
438 //set the editor mode based on file name
439 if (/\.css$/.test(currentFilename)) {
440 mode = require("ace/mode/css").Mode;
441 }
442 else if (/\.less$/.test(currentFilename)) {
443 mode = require("ace/mode/css").Mode;
444 }
445 else if (/\.js$/.test(currentFilename)) {
446 mode = require("ace/mode/javascript").Mode;
447 }
448 else {
449 mode = require("ace/mode/php").Mode; //default to php
450 //only enable session change / auto complete if needed
451 editor.getSession().enable_autocomplete = true;
452 }
453 editor.getSession().setMode(new mode());
454
455 editor.getSession().on('change', onSessionChange);
456
457 editor.resize();
458 editor.focus();
459 //make a note of current editor
460 current_editor_session = clicksesh;
461
462 });
463
464 //add click event for tab close.
465 //We are actually clearing the click event and adding it again for all tab elements, it's the only way I could get the click handler listening on all dynamically added tabs
466 jQuery(".close_tab").off('click').on("click", function(event){
467 event.preventDefault();
468 var clicksesh = jQuery(this).parent().attr('sessionrel');
469 var activeFallback;
470
471 //if the currently selected tab is being removed then remember to make the first tab active
472 if ( jQuery("#wpide_tab_"+clicksesh).hasClass('active') ) {
473 activeFallback = true;
474 }else{
475 activeFallback = false;
476 }
477
478 //remove tab
479 jQuery(this).parent().remove();
480
481 //clear session and undo
482 saved_undo_manager[clicksesh] = undefined;
483 saved_editor_sessions[clicksesh] = undefined;
484
485 //Clear the active editor if all tabs closed or activate first tab if required since the active tab may have been deleted
486 if (jQuery(".wpide_tab").length == 0){
487 editor.getSession().setValue( "" );
488 }else if ( activeFallback ){
489 jQuery( "#" + jQuery(".wpide_tab")[0].id ).click();
490 }
491
492 });
493
494 jQuery("#"+the_id).click();
495
496 if (callback_func != null) {
497 callback_func(response);
498 }
499
500 });
501
502
503 }
504
505 function saveDocument() {
506 //ajax call to save the file and generate a backup if needed
507 var data = { action: 'wpide_save_file', filename: jQuery('input[name=filename]').val(), _wpnonce: jQuery('#_wpnonce').val(), _wp_http_referer: jQuery('#_wp_http_referer').val(), content: editor.getSession().getValue() };
508 jQuery.post(ajaxurl, data, function(response) {
509 if (response === 'success') {
510 jQuery("#wpide_message").html('<span>File saved.</span>');
511 jQuery("#wpide_message").show();
512 jQuery("#wpide_message").fadeOut(5000);
513 } else {
514 alert("error: " + response);
515 }
516 });
517 }
518
519 //enter/return command
520 function selectACitem (item) {
521 if( document.getElementById('ac').style.display === 'block' ){
522 var ac_dropdwn = document.getElementById('ac');
523 var tag = ac_dropdwn.options[ac_dropdwn.selectedIndex].value;
524 var sel = editor.selection.getRange();
525 var line = editor.getSession().getLine(sel.start.row);
526 sel.start.column = sel.start.column - autocompletelength;
527
528 if (item.length){
529 tag = item; //get tag from new msdropdown passed as arg
530 }else{
531 tag = jQuery("#ac_msdd a.selected").children("span.ddTitleText").text(); //get tag from new msdropdown
532 }
533
534 //clean up the tag/command
535 tag = tag.replace(")", ""); //remove end parenthesis
536
537
538 editor.selection.setSelectionRange(sel);
539 editor.insert(tag);
540
541 wpide_close_autocomplete();
542 } else {
543 editor.insert('\n');
544 }
545 }
546
547
548 jQuery(document).ready(function($) {
549 $("#wpide_save").click(saveDocument);
550
551
552
553 //add div for ace editor to latch on to
554 //$('#template').prepend("<div style='width:80%;height:500px;margin-right:0!important;' id='fancyeditordiv'></div>");
555 //create the editor instance
556 editor = ace.edit("fancyeditordiv");
557 //set the editor theme
558 editor.setTheme("ace/theme/dawn");
559 //get a copy of the initial file contents (the file being edited)
560 //var intialData = $('#newcontent').val()
561 var intialData = "Use the file manager to find a file you wish edit, click the file name to edit. \n\n";
562
563
564 //startup info - usefull for debugging
565 var data = { action: 'wpide_startup_check', _wpnonce: jQuery('#_wpnonce').val(), _wp_http_referer: jQuery('#_wp_http_referer').val() };
566
567 jQuery.post(ajaxurl, data, function(response) {
568 if (response == "-1"){
569 intialData = intialData + "Permission/security problem with ajax request. Refresh WPide and try again. \n\n";
570 }else{
571 intialData = intialData + response;
572 }
573
574 editor.getSession().setValue( intialData );
575
576 });
577
578
579
580 //make initial editor read only
581 $('#fancyeditordiv textarea').attr("disabled", "disabled");
582
583 //use editors php mode
584 var phpMode = require("ace/mode/php").Mode;
585 editor.getSession().setMode(new phpMode());
586
587 //START AUTOCOMPLETE
588 //create the autocomplete dropdown
589 var ac = document.createElement('select');
590 ac.id = 'ac';
591 ac.name = 'ac';
592 ac.style.position='absolute';
593 ac.style.zIndex=100;
594 ac.style.width='auto';
595 ac.style.display='none';
596 ac.style.height='auto';
597 ac.size=10;
598 editor.container.appendChild(ac);
599
600 //hook onto any change in editor contents
601 editor.getSession().on('change', onSessionChange);//end editor change event
602
603
604
605 //START COMMANDS
606
607 //Key up command
608 editor.commands.addCommand({
609 name: "up",
610 bindKey: {
611 win: "Up",
612 mac: "Up",
613 sender: "editor"
614 },
615
616 exec: function(env, args, request) {
617 if (oHandler && oHandler.visible() === 'block'){
618 oHandler.previous();
619
620 //show command help panel for this command
621 wpide_function_help();
622
623 }else if( document.getElementById('ac').style.display === 'block' ) {
624 var select=document.getElementById('ac');
625 if( select.selectedIndex === 0 ) {
626 select.selectedIndex = select.options.length-1;
627 } else {
628 select.selectedIndex = select.selectedIndex-1;
629 }
630 } else {
631 var range = editor.getSelectionRange();
632 editor.clearSelection();
633 editor.moveCursorTo(range.end.row - 1, range.end.column);
634 }
635 }
636 });
637
638
639 //key down command
640 editor.commands.addCommand({
641 name: "down",
642 bindKey: {
643 win: "Down",
644 mac: "Down",
645 sender: "editor"
646 },
647 exec: function(env, args, request) {
648
649 if (oHandler && oHandler.visible() === 'block'){
650 oHandler.next();
651
652 //show command help panel for this command
653 wpide_function_help();
654
655 }else if ( document.getElementById('ac').style.display === 'block' ) {
656 var select=document.getElementById('ac');
657 if ( select.selectedIndex === select.options.length-1 ) {
658 select.selectedIndex=0;
659 } else {
660 select.selectedIndex=select.selectedIndex+1;
661 }
662 } else {
663 var range = editor.getSelectionRange();
664 editor.clearSelection();
665 editor.moveCursorTo(range.end.row +1, range.end.column);
666 }
667 }
668 });
669
670
671
672 editor.commands.addCommand({
673 name: "enter",
674 bindKey: {
675 win: "Return",
676 mac: "Return",
677 sender: "editor"
678 },
679 exec: selectACitem
680 });
681
682 // save command:
683 editor.commands.addCommand({
684 name: "save",
685 bindKey: {
686 win: "Ctrl-S",
687 mac: "Command-S",
688 sender: "editor"
689 },
690 exec: saveDocument
691 });
692
693 //END COMMANDS
694
695
696 //click action for new directory/file submit link
697 $("#wpide_create_new_directory, #wpide_create_new_file").click(function(e){
698 e.preventDefault();
699
700 var data_input = jQuery(this).parent().find("input.has_data");
701 var item = eval('('+ data_input.attr("rel") +')');
702
703 //item.path file|directory
704 var data = { action: 'wpide_create_new', path: item.path, type: item.type, file: data_input.val(), _wpnonce: jQuery('#_wpnonce').val(), _wp_http_referer: jQuery('#_wp_http_referer').val() };
705
706 jQuery.post(ajaxurl, data, function(response) {
707
708 if (response == "1"){
709 //remove the file/dir name from the text input
710 data_input.val("");
711
712 if ( jQuery("ul.jqueryFileTree a[rel='"+ item.path +"']").length == 0){
713
714 //if no parent then we are adding something to the wp-content folder so regenerate the whole filetree
715 the_filetree();
716
717 }
718
719 //click the parent once to hide
720 jQuery("ul.jqueryFileTree a[rel='"+ item.path +"']").click();
721
722 //hide the parent input block
723 data_input.parent().hide();
724
725 //click the parent once again to show with new folder and focus on this area
726 jQuery("ul.jqueryFileTree a[rel='"+ item.path +"']").click();
727 jQuery("ul.jqueryFileTree a[rel='"+ item.path +"']").focus();
728
729 }else if (response == "-1"){
730 alert("Permission/security problem. Refresh WPide and try again.");
731 }else{
732 alert(response);
733 }
734
735
736 });
737
738 });
739
740 });//end jquery load
741