Desktop markdown wiki app. Built with node, Electron Framework and AngularJS.

file-service.js 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  1. angular.module('codexApp')
  2. .service('FileService', [ '$rootScope', '$http', 'ThumbnailService', function($rootScope, $http, ThumbnailService) {
  3. var notes_dir = "/Users/james/dev/codex/codex";
  4. var default_notes_dir = "/Users/james/dev/codex/codex/inbox";
  5. var default_home_note = "/Users/james/dev/codex/codex/index.md"
  6. var notes = [];
  7. var current_note = "";
  8. var note_history = [];
  9. var note_history_index = 0;
  10. var prettySize = function(bytes) {
  11. if (bytes <= 1024) {
  12. return bytes + " KB"
  13. } else {
  14. var megabytes = parseFloat(Math.round(bytes/1024 * 100) / 100).toFixed(0);
  15. return megabytes + " MB"
  16. }
  17. }
  18. var getFilePathExtension = function(path) {
  19. var filename = path.split('\\').pop().split('/').pop();
  20. var lastIndex = filename.lastIndexOf(".");
  21. if (lastIndex < 1) return "";
  22. return filename.substr(lastIndex + 1);
  23. }
  24. var getFileType = function(path) {
  25. var extension = getFilePathExtension(path);
  26. if (typeof(extension)==='undefined' || extension == "") extension = 'dir';
  27. switch (extension) {
  28. case "pdf":
  29. return "Document";
  30. case "jpg":
  31. return "Image";
  32. case "png":
  33. return "Image";
  34. case "md":
  35. return "Markdown";
  36. case 'dir':
  37. return "Folder";
  38. default:
  39. return "File";
  40. }
  41. }
  42. var directorySize = function(dir) {
  43. var filesystem = require("fs");
  44. var size = 0;
  45. var results = [];
  46. filesystem.readdirSync(dir).forEach(function(file) {
  47. file_path = dir+'/'+file;
  48. var stat = filesystem.statSync(file_path);
  49. if (stat && stat.isDirectory()) {
  50. results = results.concat(directorySize(file_path))
  51. } else {
  52. if(file != ".DS_Store") {
  53. size = size + stat["size"];
  54. //console.log("* " + stat["size"] + " KB -> " + file_path)
  55. }
  56. }
  57. });
  58. return size;
  59. }
  60. var noteCount = function(){
  61. var count = $scope.notes.length
  62. switch (count) {
  63. case 0:
  64. return '0 notes';
  65. case 1:
  66. return '1 note';
  67. default:
  68. return count + ' notes';
  69. }
  70. }
  71. var getThumbnail = function(file_path) {
  72. var type = getFileType(file_path);
  73. switch (type) {
  74. case "Markdown":
  75. return ThumbnailService.createNoteThumbnail(file_path);
  76. default:
  77. return "";
  78. }
  79. }
  80. var isValidFile = function(file) {
  81. if(file != ".DS_Store" && file != "info.json") {
  82. var parts = file.split('.');
  83. if (parts[parts.length -2] == "thumb") {
  84. return false;
  85. } else {
  86. return true
  87. }
  88. }
  89. }
  90. var SetFileInfo = function(jsonData, dir, file_path, stat) {
  91. //console.log(jsonData.title);
  92. if (typeof(jsonData)==='undefined') jsonData = {};
  93. if(jsonData.title != "" && jsonData.title != undefined){
  94. var title = jsonData.title;
  95. } else {
  96. var title = getNameFromPath(file_path);
  97. }
  98. if(jsonData.thumbnail != "" && jsonData.thumbnail != undefined){
  99. var thumbnail_path = jsonData.thumbnail;
  100. } else {
  101. var thumbnail_path = getThumbnail(file_path);
  102. }
  103. var file_obj = {
  104. title: title,
  105. path: file_path,
  106. size: prettySize(directorySize(dir)),
  107. type: getFileType(file_path),
  108. author: jsonData.author,
  109. index: jsonData.index,
  110. id: jsonData.id,
  111. created_at: dateFormat(stat["birthdate"], "mediumDate"),
  112. modified_at: dateFormat(stat["mtime"], "mediumDate"),
  113. accessed_at: dateFormat(stat["atime"], "mediumDate"),
  114. thumbnail: thumbnail_path
  115. }
  116. return file_obj;
  117. }
  118. var getNotesFromFolders = function(dir) {
  119. if (typeof(dir)==='undefined') dir = notes_dir;
  120. var filesystem = require("fs");
  121. filesystem.readdirSync(dir).forEach(function(file) {
  122. file_path = dir+'/'+file;
  123. var stat = filesystem.statSync(file_path);
  124. if (stat && stat.isDirectory()) {
  125. notes = notes.concat(getNotesFromFolders(file_path))
  126. } else {
  127. if(file == "info.json"){
  128. filesystem.readFile(file_path, function(err, data) {
  129. var jsonData = JSON.parse(data);
  130. var file_obj = SetFileInfo(jsonData, dir, file_path, stat)
  131. notes.push(file_obj);
  132. });
  133. }
  134. }
  135. });
  136. return notes;
  137. };
  138. this.getNotesFromFolders = getNotesFromFolders;
  139. var getAllFilesFromFolder = function(dir) {
  140. if (typeof(dir)==='undefined') dir = notes_dir;
  141. var filesystem = require("fs");
  142. var results = [];
  143. filesystem.readdirSync(dir).forEach(function(file) {
  144. file_path = dir+'/'+file;
  145. var stat = filesystem.statSync(file_path);
  146. if (stat && stat.isDirectory()) {
  147. results = results.concat(getAllFilesFromFolder(file_path))
  148. } else {
  149. if(isValidFile(file)) {
  150. var jsonData = {};
  151. var file_obj = SetFileInfo(jsonData, dir, file_path, stat)
  152. results.push(file_obj);
  153. }
  154. }
  155. //console.log(file_obj);
  156. });
  157. $rootScope.$broadcast('file-service:files-loaded');
  158. return results;
  159. };
  160. var getFilesFromFolder = function(dir) {
  161. if (typeof(dir)==='undefined') dir = notes_dir;
  162. var filesystem = require("fs");
  163. var results = [];
  164. filesystem.readdirSync(dir).forEach(function(file) {
  165. file_path = dir+'/'+file;
  166. var stat = filesystem.statSync(file_path);
  167. if(isValidFile(file)) {
  168. var jsonData = {};
  169. var file_obj = SetFileInfo(jsonData, dir, file_path, stat)
  170. results.push(file_obj);
  171. }
  172. });
  173. $rootScope.$broadcast('file-service:files-loaded');
  174. return results;
  175. };
  176. var findNoteInFolder = function(note_id, dir) {
  177. if (typeof(dir)==='undefined') dir = notes_dir;
  178. var filesystem = require("fs");
  179. var results = [];
  180. filesystem.readdirSync(dir).forEach(function(file) {
  181. file_path = dir+'/'+file;
  182. var stat = filesystem.statSync(file_path);
  183. if (stat && stat.isDirectory()) {
  184. results = results.concat(findNoteInFolder(note_id, file_path))
  185. } else {
  186. if(file == "info.json"){
  187. filesystem.readFile(file_path, function(err, data) {
  188. var jsonData = JSON.parse(data);
  189. console.log(jsonData.id)
  190. if(jsonData.id == note_id){
  191. var file_obj = SetFileInfo(jsonData, dir, file_path, stat)
  192. results.push(file_obj);
  193. }
  194. });
  195. }
  196. }
  197. });
  198. console.log(results);
  199. return results[0];
  200. };
  201. this.saveFile = function(file_path, content){
  202. var fs = require('fs');
  203. fs.writeFile(file_path, content, 'utf8', function(err) {
  204. if(err) {
  205. console.log("-> ERROR SAVING FILE: " + file_path);
  206. console.log(err);
  207. } else {
  208. console.log("-> FILE SAVED: " + file_path);
  209. }
  210. });
  211. }
  212. var getNote = function(file_path){
  213. var filesystem = require("fs");
  214. var stat = filesystem.statSync(file_path);
  215. var file_obj = {
  216. title: "",
  217. path: file_path,
  218. size: stat['size'],
  219. type: getFileType(file_path),
  220. author: "",
  221. index: "",
  222. id: "",
  223. created_at: dateFormat(stat["birthdate"], "mediumDate"),
  224. modified_at: dateFormat(stat["mtime"], "mediumDate"),
  225. accessed_at: dateFormat(stat["atime"], "mediumDate")
  226. }
  227. return file_obj
  228. }
  229. var getNameFromPath = function(path) {
  230. path = path.split('/');
  231. var filename = path[path.length - 1];
  232. //filename = filename.split('.');
  233. //filename.pop();
  234. //name = filename[filename.length -1];
  235. return filename
  236. }
  237. var getUrlParts = function(url) {
  238. var a = document.createElement('a');
  239. a.href = url;
  240. return {
  241. href: a.href,
  242. host: a.host,
  243. hostname: a.hostname,
  244. port: a.port,
  245. pathname: a.pathname,
  246. protocol: a.protocol,
  247. hash: a.hash,
  248. search: a.search
  249. };
  250. }
  251. var absoluteToRelativeURL = function(current_url, absolute_url) {
  252. //console.log(current_url);
  253. //console.log(absolute_url);
  254. // split urls and create arrays
  255. var current_path = current_url.split('/');
  256. var absolute_path = getUrlParts(absolute_url).pathname.split('/');
  257. var root_path = getUrlParts(notes_dir).pathname.split('/');
  258. // remove the current note's filename from the url and the image filename from the url
  259. //current_path.pop();
  260. current_path.shift();
  261. //absolute_path.shift();
  262. // count how many folders the current path has
  263. var current_path_count = 0;
  264. for (var i = 0; i < current_path.length; i++) {
  265. current_path_count = current_path_count + 1;
  266. }
  267. // count how many folders the absolute path has
  268. var absolute_path_count = 0;
  269. for (var i = 0; i < absolute_path.length; i++) {
  270. absolute_path_count = absolute_path_count + 1;
  271. }
  272. var root_path_count = 0;
  273. for (var i = 0; i < root_path.length; i++) {
  274. root_path_count = root_path_count + 1;
  275. }
  276. var count = current_path_count - root_path_count;
  277. console.log(current_path_count + " - " + root_path_count + " = " + count);
  278. //dif = current_path_count - (absolute_path_count -1);
  279. for (var i = 0; i < count; i++) {
  280. absolute_path.shift();
  281. }
  282. // make the relative path a string again
  283. var relative_path = absolute_path.join('/');
  284. console.log("* Converted relative URL: " + relative_path)
  285. return relative_path;
  286. }
  287. // Absolute to relative URL
  288. this.absoluteToRelativeURL = function(current_url, absolute_url) {
  289. return absoluteToRelativeURL(current_url, absolute_url);
  290. }
  291. var shortenPath = function(path) {
  292. //console.log(current_url);
  293. //console.log(absolute_url);
  294. // split urls and create arrays
  295. var current_path = path.split('/');
  296. var root_path = getUrlParts(notes_dir).pathname.split('/');
  297. // count how many folders the current path has
  298. var current_path_count = 0;
  299. for (var i = 0; i < current_path.length; i++) {
  300. current_path_count = current_path_count + 1;
  301. }
  302. var root_path_count = 0;
  303. for (var i = 0; i < root_path.length; i++) {
  304. root_path_count = root_path_count + 1;
  305. }
  306. var diff = current_path_count - root_path_count;
  307. var count = current_path_count - diff;
  308. console.log(current_path_count + " - " + root_path_count + " = " + count);
  309. //dif = current_path_count - (absolute_path_count -1);
  310. for (var i = 0; i < count; i++) {
  311. current_path.shift();
  312. }
  313. // make the relative path a string again
  314. var relative_path = current_path.join('/');
  315. console.log("* Shortened Path: " + relative_path)
  316. return relative_path;
  317. }
  318. // Absolute to relative URL
  319. this.shortenPath = function(path) {
  320. return shortenPath(path);
  321. }
  322. // Get folders
  323. var getFolders = function(root) {
  324. if (typeof(root)==='undefined') root = notes_dir;
  325. var filesystem = require("fs");
  326. var results = [];
  327. filesystem.readdirSync(root).forEach(function(file) {
  328. file_path = root+'/'+file;
  329. var stat = filesystem.statSync(file_path);
  330. if (stat && stat.isDirectory()) {
  331. results.push(SetFileInfo( undefined, root, file_path, stat));
  332. }
  333. });
  334. console.log(results);
  335. return results;
  336. }
  337. this.getFolders = function(root){
  338. return getFolders(root);
  339. }
  340. // Sort files
  341. var date_sort_asc = function (date1, date2) {
  342. if (date1.modified_at > date2.modified_at) return 1;
  343. if (date1.modified_at < date2.modified_at) return -1;
  344. return 0;
  345. };
  346. var date_sort_desc = function (date1, date2) {
  347. if (date1.modified_at > date2.modified_at) return -1;
  348. if (date1.modified_at < date2.modified_at) return 1;
  349. return 0;
  350. };
  351. var filterNotes = function(files) {
  352. var filtered = [];
  353. for (var i = 0; i < files.length; i++) {
  354. if(files[i].type == "Markdown") {
  355. filtered.push(files[i]);
  356. }
  357. }
  358. return filtered;
  359. }
  360. // RESPONSE
  361. this.getAllFiles = function(dir) {
  362. if (typeof(dir)==='undefined') dir = notes_dir;
  363. notes = getAllFilesFromFolder(dir);
  364. return notes.sort(date_sort_asc);
  365. }
  366. this.getFiles = function(dir) {
  367. if (typeof(dir)==='undefined') dir = notes_dir;
  368. notes = getFilesFromFolder(dir);
  369. return notes.sort(date_sort_asc);
  370. }
  371. this.getAllNotes = function() {
  372. notes = getAllFilesFromFolder();
  373. notes = filterNotes(notes);
  374. return notes.sort(date_sort_asc);
  375. }
  376. this.getNote = function(path) {
  377. return getNote(path);
  378. }
  379. this.getCurrentNote = function() {
  380. return current_note;
  381. }
  382. this.setCurrentNote = function(note) {
  383. //console.log("searcing for: " + note_id)
  384. current_note = note;
  385. if((note_history.length -1) != note_history_index){
  386. var dif = note_history.length - note_history_index - 1;
  387. for (var i = 0; i < dif; i++) {
  388. note_history.pop();
  389. }
  390. }
  391. note_history.push(current_note);
  392. note_history_index = note_history.length -1;
  393. //console.log(current_note);
  394. //console.log("Current_note: " + current_note.title)
  395. }
  396. this.goToPreviousNote = function(){
  397. if(note_history_index > 0) {
  398. note_history_index = note_history_index - 1;
  399. current_note = note_history[note_history_index];
  400. }
  401. }
  402. this.goToNextNote = function(){
  403. if(note_history_index < (note_history.length - 1)){
  404. note_history_index = note_history_index + 1;
  405. current_note = note_history[note_history_index];
  406. }
  407. }
  408. this.getNotesDir = function() {
  409. return notes_dir;
  410. }
  411. this.getDefaultNotesDir = function() {
  412. return default_notes_dir;
  413. }
  414. this.getDefaultNote = function() {
  415. return getNote(default_home_note);
  416. }
  417. }])