editor.js 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. function setEditorSize(){
  2. // Sets the size of the text editor window.
  3. fillWindow($('#editor'));
  4. }
  5. function getFileExtension(file){
  6. var parts=file.split('.');
  7. return parts[parts.length-1];
  8. }
  9. function setSyntaxMode(ext){
  10. // Loads the syntax mode files and tells the editor
  11. var filetype = new Array();
  12. // add file extensions like this: filetype["extension"] = "filetype":
  13. filetype["h"] = "c_cpp";
  14. filetype["c"] = "c_cpp";
  15. filetype["clj"] = "clojure";
  16. filetype["coffee"] = "coffee"; // coffescript can be compiled to javascript
  17. filetype["coldfusion"] = "cfc";
  18. filetype["cpp"] = "c_cpp";
  19. filetype["cs"] = "csharp";
  20. filetype["css"] = "css";
  21. filetype["groovy"] = "groovy";
  22. filetype["haxe"] = "hx";
  23. filetype["htm"] = "html";
  24. filetype["html"] = "html";
  25. filetype["java"] = "java";
  26. filetype["js"] = "javascript";
  27. filetype["jsm"] = "javascript";
  28. filetype["json"] = "json";
  29. filetype["latex"] = "latex";
  30. filetype["less"] = "less";
  31. filetype["ly"] = "latex";
  32. filetype["ily"] = "latex";
  33. filetype["lua"] = "lua";
  34. filetype["markdown"] = "markdown";
  35. filetype["md"] = "markdown";
  36. filetype["mdown"] = "markdown";
  37. filetype["mdwn"] = "markdown";
  38. filetype["mkd"] = "markdown";
  39. filetype["ml"] = "ocaml";
  40. filetype["mli"] = "ocaml";
  41. filetype["pl"] = "perl";
  42. filetype["php"] = "php";
  43. filetype["powershell"] = "ps1";
  44. filetype["py"] = "python";
  45. filetype["rb"] = "ruby";
  46. filetype["scad"] = "scad"; // seems to be something like 3d model files printed with e.g. reprap
  47. filetype["scala"] = "scala";
  48. filetype["scss"] = "scss"; // "sassy css"
  49. filetype["sh"] = "sh";
  50. filetype["sql"] = "sql";
  51. filetype["svg"] = "svg";
  52. filetype["textile"] = "textile"; // related to markdown
  53. filetype["xml"] = "xml";
  54. if(filetype[ext]!=null){
  55. // Then it must be in the array, so load the custom syntax mode
  56. // Set the syntax mode
  57. OC.addScript('files_texteditor','aceeditor/mode-'+filetype[ext], function(){
  58. var SyntaxMode = require("ace/mode/"+filetype[ext]).Mode;
  59. window.aceEditor.getSession().setMode(new SyntaxMode());
  60. });
  61. }
  62. }
  63. function showControls(filename,writeperms){
  64. // Loads the control bar at the top.
  65. // Load the new toolbar.
  66. var editorbarhtml = '<div id="editorcontrols" style="display: none;"><div class="crumb svg last" id="breadcrumb_file" style="background-image:url(&quot;'+OC.imagePath('core','breadcrumb.png')+'&quot;)"><p>'+filename.replace(/</, "&lt;").replace(/>/, "&gt;")+'</p></div>';
  67. if(writeperms=="true"){
  68. editorbarhtml += '<button id="editor_save">'+t('files_texteditor','Save')+'</button><div class="separator"></div>';
  69. }
  70. editorbarhtml += '<label for="editorseachval">Search:</label><input type="text" name="editorsearchval" id="editorsearchval"><div class="separator"></div><button id="editor_close">'+t('files_texteditor','Close')+'</button></div>';
  71. // Change breadcrumb classes
  72. $('#controls .last').removeClass('last');
  73. $('#controls').append(editorbarhtml);
  74. $('#editorcontrols').fadeIn('slow');
  75. }
  76. function bindControlEvents(){
  77. $("#editor_save").die('click',doFileSave).live('click',doFileSave);
  78. $('#editor_close').die('click',hideFileEditor).live('click',hideFileEditor);
  79. $('#editorsearchval').die('keyup', doSearch).live('keyup', doSearch);
  80. $('#clearsearchbtn').die('click', resetSearch).live('click', resetSearch);
  81. $('#nextsearchbtn').die('click', nextSearchResult).live('click', nextSearchResult);
  82. }
  83. // returns true or false if the editor is in view or not
  84. function editorIsShown(){
  85. // Not working as intended. Always returns true.
  86. return is_editor_shown;
  87. }
  88. //resets the search
  89. function resetSearch(){
  90. $('#editorsearchval').val('');
  91. $('#nextsearchbtn').remove();
  92. $('#clearsearchbtn').remove();
  93. window.aceEditor.gotoLine(0);
  94. }
  95. // moves the cursor to the next search resukt
  96. function nextSearchResult(){
  97. window.aceEditor.findNext();
  98. }
  99. // Performs the initial search
  100. function doSearch(){
  101. // check if search box empty?
  102. if($('#editorsearchval').val()==''){
  103. // Hide clear button
  104. window.aceEditor.gotoLine(0);
  105. $('#nextsearchbtn').remove();
  106. $('#clearsearchbtn').remove();
  107. } else {
  108. // New search
  109. // Reset cursor
  110. window.aceEditor.gotoLine(0);
  111. // Do search
  112. window.aceEditor.find($('#editorsearchval').val(),{
  113. backwards: false,
  114. wrap: false,
  115. caseSensitive: false,
  116. wholeWord: false,
  117. regExp: false
  118. });
  119. // Show next and clear buttons
  120. // check if already there
  121. if($('#nextsearchbtn').length==0){
  122. var nextbtnhtml = '<button id="nextsearchbtn">Next</button>';
  123. var clearbtnhtml = '<button id="clearsearchbtn">Clear</button>';
  124. $('#editorsearchval').after(nextbtnhtml).after(clearbtnhtml);
  125. }
  126. }
  127. }
  128. // Tries to save the file.
  129. function doFileSave(){
  130. if(editorIsShown()){
  131. // Changed contents?
  132. if($('#editor').attr('data-edited')=='true'){
  133. // Get file path
  134. var path = $('#editor').attr('data-dir')+'/'+$('#editor').attr('data-filename');
  135. // Get original mtime
  136. var mtime = $('#editor').attr('data-mtime');
  137. // Show saving spinner
  138. $("#editor_save").die('click',doFileSave);
  139. $('#save_result').remove();
  140. $('#editor_save').text(t('files_texteditor','Saving...'));
  141. // Get the data
  142. var filecontents = window.aceEditor.getSession().getValue();
  143. // Send the data
  144. $.post(OC.filePath('files_texteditor','ajax','savefile.php'), { filecontents: filecontents, path: path, mtime: mtime },function(jsondata){
  145. if(jsondata.status!='success'){
  146. // Save failed
  147. $('#editor_save').text(t('files_texteditor','Save'));
  148. $('#editor_save').after('<p id="save_result" style="float: left">Failed to save file</p>');
  149. $("#editor_save").live('click',doFileSave);
  150. } else {
  151. // Save OK
  152. // Update mtime
  153. $('#editor').attr('data-mtime',jsondata.data.mtime);
  154. $('#editor_save').text(t('files_texteditor','Save'));
  155. $("#editor_save").live('click',doFileSave);
  156. // Update titles
  157. $('#editor').attr('data-edited', 'false');
  158. $('#breadcrumb_file').text($('#editor').attr('data-filename'));
  159. document.title = $('#editor').attr('data-filename')+' - ownCloud';
  160. }
  161. },'json');
  162. }
  163. }
  164. giveEditorFocus();
  165. };
  166. // Gives the editor focus
  167. function giveEditorFocus(){
  168. window.aceEditor.focus();
  169. };
  170. // Loads the file editor. Accepts two parameters, dir and filename.
  171. function showFileEditor(dir,filename){
  172. // Delete any old editors
  173. $('#editor').remove();
  174. if(!editorIsShown()){
  175. // Loads the file editor and display it.
  176. $('#content').append('<div id="editor"></div>');
  177. var data = $.getJSON(
  178. OC.filePath('files_texteditor','ajax','loadfile.php'),
  179. {file:filename,dir:dir},
  180. function(result){
  181. if(result.status == 'success'){
  182. // Save mtime
  183. $('#editor').attr('data-mtime', result.data.mtime);
  184. // Initialise the editor
  185. $('.actions,#file_action_panel').fadeOut('slow');
  186. $('table').fadeOut('slow', function() {
  187. // Show the control bar
  188. showControls(filename,result.data.write);
  189. // Update document title
  190. document.title = filename+' - ownCloud';
  191. $('#editor').text(result.data.filecontents);
  192. $('#editor').attr('data-dir', dir);
  193. $('#editor').attr('data-filename', filename);
  194. $('#editor').attr('data-edited', 'false');
  195. window.aceEditor = ace.edit("editor");
  196. aceEditor.setShowPrintMargin(false);
  197. aceEditor.getSession().setUseWrapMode(true);
  198. if(result.data.write=='false'){
  199. aceEditor.setReadOnly(true);
  200. }
  201. setEditorSize();
  202. setSyntaxMode(getFileExtension(filename));
  203. OC.addScript('files_texteditor','aceeditor/theme-clouds', function(){
  204. window.aceEditor.setTheme("ace/theme/clouds");
  205. });
  206. window.aceEditor.getSession().on('change', function(){
  207. if($('#editor').attr('data-edited')!='true'){
  208. $('#editor').attr('data-edited', 'true');
  209. $('#breadcrumb_file').text($('#breadcrumb_file').text()+' *');
  210. document.title = $('#editor').attr('data-filename')+' * - ownCloud';
  211. }
  212. });
  213. // Add the ctrl+s event
  214. window.aceEditor.commands.addCommand({ name: "save", bindKey: { win: "Ctrl-S", mac: "Command-S", sender: "editor" }, exec: function(){
  215. doFileSave();
  216. } });
  217. });
  218. } else {
  219. // Failed to get the file.
  220. OC.dialogs.alert(result.data.message, t('files_texteditor','An error occurred!'));
  221. }
  222. // End success
  223. }
  224. // End ajax
  225. );
  226. is_editor_shown = true;
  227. }
  228. }
  229. // Fades out the editor.
  230. function hideFileEditor(){
  231. if($('#editor').attr('data-edited') == 'true'){
  232. // Hide, not remove
  233. $('#editorcontrols').fadeOut('slow',function(){
  234. // Check if there is a folder in the breadcrumb
  235. if($('.crumb.ui-droppable').length){
  236. $('.crumb.ui-droppable:last').addClass('last');
  237. }
  238. });
  239. // Fade out editor
  240. $('#editor').fadeOut('slow', function(){
  241. // Reset document title
  242. document.title = "ownCloud";
  243. $('.actions,#file_access_panel').fadeIn('slow');
  244. $('table').fadeIn('slow');
  245. });
  246. $('#notification').text(t('files_texteditor','There were unsaved changes, click here to go back'));
  247. $('#notification').data('reopeneditor',true);
  248. $('#notification').fadeIn();
  249. is_editor_shown = false;
  250. } else {
  251. // Remove editor
  252. $('#editorcontrols').fadeOut('slow',function(){
  253. $(this).remove();
  254. $(".crumb:last").addClass('last');
  255. });
  256. // Fade out editor
  257. $('#editor').fadeOut('slow', function(){
  258. $(this).remove();
  259. // Reset document title
  260. document.title = "ownCloud";
  261. $('.actions,#file_access_panel').fadeIn('slow');
  262. $('table').fadeIn('slow');
  263. });
  264. is_editor_shown = false;
  265. }
  266. }
  267. // Reopens the last document
  268. function reopenEditor(){
  269. $('.actions,#file_action_panel').fadeOut('slow');
  270. $('table').fadeOut('slow', function(){
  271. $('#controls .last').not('#breadcrumb_file').removeClass('last');
  272. $('#editor').fadeIn('fast');
  273. $('#editorcontrols').fadeIn('fast', function(){
  274. });
  275. });
  276. is_editor_shown = true;
  277. }
  278. // resizes the editor window
  279. $(window).resize(function() {
  280. setEditorSize();
  281. });
  282. var is_editor_shown = false;
  283. $(document).ready(function(){
  284. if(typeof FileActions!=='undefined'){
  285. FileActions.register('text','Edit','',function(filename){
  286. showFileEditor($('#dir').val(),filename);
  287. });
  288. FileActions.setDefault('text','Edit');
  289. FileActions.register('application/xml','Edit','',function(filename){
  290. showFileEditor($('#dir').val(),filename);
  291. });
  292. FileActions.setDefault('application/xml','Edit');
  293. }
  294. OC.search.customResults.Text=function(row,item){
  295. var text=item.link.substr(item.link.indexOf('?file=')+6);
  296. var a=row.find('a');
  297. a.data('file',text);
  298. a.attr('href','#');
  299. a.click(function(){
  300. var pos=text.lastIndexOf('/')
  301. var file=text.substr(pos + 1);
  302. var dir=text.substr(0,pos);
  303. showFileEditor(dir,file);
  304. });
  305. };
  306. // Binds the file save and close editor events, and gotoline button
  307. bindControlEvents();
  308. $('#editor').remove();
  309. $('#notification').click(function(){
  310. if($('#notification').data('reopeneditor'))
  311. {
  312. reopenEditor();
  313. }
  314. $('#notification').fadeOut();
  315. });
  316. });