| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  | import server from "./server.js"; | 
					
						
							|  |  |  | import linkService from "./link.js"; | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  | import utils from "./utils.js"; | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  | import treeCache from "./tree_cache.js"; | 
					
						
							| 
									
										
										
										
											2019-10-05 10:55:29 +02:00
										 |  |  | import renderService from "./render.js"; | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  | import protectedSessionHolder from "./protected_session_holder.js"; | 
					
						
							|  |  |  | import protectedSessionService from "./protected_session.js"; | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | const MIN_ZOOM_LEVEL = 1; | 
					
						
							|  |  |  | const MAX_ZOOM_LEVEL = 6; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const ZOOMS = { | 
					
						
							| 
									
										
										
										
											2019-10-05 10:55:29 +02:00
										 |  |  |     1: { | 
					
						
							|  |  |  |         width: "100%", | 
					
						
							|  |  |  |         height: "100%" | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     2: { | 
					
						
							|  |  |  |         width: "49%", | 
					
						
							|  |  |  |         height: "350px" | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     3: { | 
					
						
							|  |  |  |         width: "32%", | 
					
						
							|  |  |  |         height: "250px" | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     4: { | 
					
						
							|  |  |  |         width: "24%", | 
					
						
							|  |  |  |         height: "200px" | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     5: { | 
					
						
							|  |  |  |         width: "19%", | 
					
						
							|  |  |  |         height: "175px" | 
					
						
							|  |  |  |     }, | 
					
						
							|  |  |  |     6: { | 
					
						
							|  |  |  |         width: "16%", | 
					
						
							|  |  |  |         height: "150px" | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | class NoteDetailBook { | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * @param {TabContext} ctx | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     constructor(ctx) { | 
					
						
							|  |  |  |         this.ctx = ctx; | 
					
						
							|  |  |  |         this.$component = ctx.$tabContent.find('.note-detail-book'); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |         this.$content = this.$component.find('.note-detail-book-content'); | 
					
						
							| 
									
										
										
										
											2019-10-05 11:22:42 +02:00
										 |  |  |         this.$zoomInButton = this.$component.find('.book-zoom-in-button'); | 
					
						
							|  |  |  |         this.$zoomOutButton = this.$component.find('.book-zoom-out-button'); | 
					
						
							|  |  |  |         this.$expandChildrenButton = this.$component.find('.expand-children-button'); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |         this.$zoomInButton.click(() => this.setZoom(this.zoomLevel - 1)); | 
					
						
							|  |  |  |         this.$zoomOutButton.click(() => this.setZoom(this.zoomLevel + 1)); | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 11:22:42 +02:00
										 |  |  |         this.$expandChildrenButton.click(async () => { | 
					
						
							|  |  |  |             for (let i = 1; i < 30; i++) { // protection against infinite cycle
 | 
					
						
							|  |  |  |                 const $unexpandedLinks = this.$content.find('.note-book-open-children-button:visible'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 if ($unexpandedLinks.length === 0) { | 
					
						
							|  |  |  |                     break; | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 for (const link of $unexpandedLinks) { | 
					
						
							|  |  |  |                     const $card = $(link).closest(".note-book-card"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     await this.expandCard($card); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  |         this.$content.on('click', '.note-book-open-children-button', async ev => { | 
					
						
							|  |  |  |             const $card = $(ev.target).closest('.note-book-card'); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 11:22:42 +02:00
										 |  |  |             await this.expandCard($card); | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  |         }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.$content.on('click', '.note-book-hide-children-button', async ev => { | 
					
						
							|  |  |  |             const $card = $(ev.target).closest('.note-book-card'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $card.find('.note-book-open-children-button').show(); | 
					
						
							|  |  |  |             $card.find('.note-book-hide-children-button').hide(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $card.find('.note-book-children-content').empty(); | 
					
						
							|  |  |  |         }); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 11:22:42 +02:00
										 |  |  |     async expandCard($card) { | 
					
						
							|  |  |  |         const noteId = $card.attr('data-note-id'); | 
					
						
							|  |  |  |         const note = await treeCache.getNote(noteId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $card.find('.note-book-open-children-button').hide(); | 
					
						
							|  |  |  |         $card.find('.note-book-hide-children-button').show(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         await this.renderIntoElement(note, $card.find('.note-book-children-content')); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |     setZoom(zoomLevel) { | 
					
						
							| 
									
										
										
										
											2019-10-05 12:01:00 +02:00
										 |  |  |         if (!(zoomLevel in ZOOMS)) { | 
					
						
							| 
									
										
										
										
											2019-10-05 20:27:30 +02:00
										 |  |  |             zoomLevel = this.getDefaultZoomLevel(); | 
					
						
							| 
									
										
										
										
											2019-10-05 12:01:00 +02:00
										 |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |         this.zoomLevel = zoomLevel; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         this.$zoomInButton.prop("disabled", zoomLevel === MIN_ZOOM_LEVEL); | 
					
						
							|  |  |  |         this.$zoomOutButton.prop("disabled", zoomLevel === MAX_ZOOM_LEVEL); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 10:55:29 +02:00
										 |  |  |         this.$content.find('.note-book-card').css("flex-basis", ZOOMS[zoomLevel].width); | 
					
						
							|  |  |  |         this.$content.find('.note-book-content').css("max-height", ZOOMS[zoomLevel].height); | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async render() { | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |         this.$content.empty(); | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 20:27:30 +02:00
										 |  |  |         if (this.isAutoBook()) { | 
					
						
							|  |  |  |             const $addTextLink = $('<a href="javascript:">here</a>').click(() => { | 
					
						
							|  |  |  |                 this.ctx.renderComponent(true); | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             this.$content.append($('<div class="note-book-auto-message"></div>') | 
					
						
							| 
									
										
										
										
											2019-10-06 12:33:47 +02:00
										 |  |  |                 .append(`This note doesn't have any content so we display its children. Click `) | 
					
						
							| 
									
										
										
										
											2019-10-05 20:27:30 +02:00
										 |  |  |                 .append($addTextLink) | 
					
						
							|  |  |  |                 .append(' if you want to add some text.')) | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         const zoomLevel = parseInt(await this.ctx.note.getLabelValue('bookZoomLevel')) || this.getDefaultZoomLevel(); | 
					
						
							| 
									
										
										
										
											2019-10-05 12:01:00 +02:00
										 |  |  |         this.setZoom(zoomLevel); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  |         await this.renderIntoElement(this.ctx.note, this.$content); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     async renderIntoElement(note, $container) { | 
					
						
							|  |  |  |         for (const childNote of await note.getChildNotes()) { | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |             const type = this.getRenderingType(childNote); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-09 15:31:47 +01:00
										 |  |  |             const childNotePath = this.ctx.notePath + '/' + childNote.noteId; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  |             const $card = $('<div class="note-book-card">') | 
					
						
							|  |  |  |                 .attr('data-note-id', childNote.noteId) | 
					
						
							| 
									
										
										
										
											2019-10-05 10:55:29 +02:00
										 |  |  |                 .css("flex-basis", ZOOMS[this.zoomLevel].width) | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |                 .addClass("type-" + type) | 
					
						
							| 
									
										
										
										
											2019-11-09 15:31:47 +01:00
										 |  |  |                 .append($('<h5 class="note-book-title">').append(await linkService.createNoteLink(childNotePath, null, false))) | 
					
						
							| 
									
										
										
										
											2019-10-05 10:55:29 +02:00
										 |  |  |                 .append($('<div class="note-book-content">') | 
					
						
							|  |  |  |                     .css("max-height", ZOOMS[this.zoomLevel].height) | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |                     .append(await this.getNoteContent(type, childNote))); | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |             const childCount = childNote.getChildNoteIds().length; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (childCount > 0) { | 
					
						
							|  |  |  |                 const label = `${childCount} child${childCount > 1 ? 'ren' : ''}`; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 $card.append($('<div class="note-book-children">') | 
					
						
							| 
									
										
										
										
											2019-10-05 10:55:29 +02:00
										 |  |  |                     .append($(`<a class="note-book-open-children-button" href="javascript:">+ Show ${label}</a>`)) | 
					
						
							|  |  |  |                     .append($(`<a class="note-book-hide-children-button" href="javascript:">- Hide ${label}</a>`).hide()) | 
					
						
							| 
									
										
										
										
											2019-10-05 09:33:31 +02:00
										 |  |  |                     .append($('<div class="note-book-children-content">')) | 
					
						
							|  |  |  |                 ); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $container.append($card); | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |     async getNoteContent(type, note) { | 
					
						
							|  |  |  |         if (type === 'text') { | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  |             const fullNote = await server.get('notes/' + note.noteId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const $content = $("<div>").html(fullNote.content); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 20:27:30 +02:00
										 |  |  |             if (utils.isHtmlEmpty(fullNote.content)) { | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  |                 return ""; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 return $content; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |         else if (type === 'code') { | 
					
						
							| 
									
										
										
										
											2019-10-02 19:40:22 +02:00
										 |  |  |             const fullNote = await server.get('notes/' + note.noteId); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (fullNote.content.trim() === "") { | 
					
						
							|  |  |  |                 return ""; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return $("<pre>").text(fullNote.content); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |         else if (type === 'image') { | 
					
						
							| 
									
										
										
										
											2019-10-02 19:40:22 +02:00
										 |  |  |             return $("<img>").attr("src", `api/images/${note.noteId}/${note.title}`); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |         else if (type === 'file') { | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |             function getFileUrl() { | 
					
						
							|  |  |  |                 // electron needs absolute URL so we extract current host, port, protocol
 | 
					
						
							|  |  |  |                 return utils.getHost() + "/api/notes/" + note.noteId + "/download"; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             const $downloadButton = $('<button class="file-download btn btn-primary" type="button">Download</button>'); | 
					
						
							|  |  |  |             const $openButton = $('<button class="file-open btn btn-primary" type="button">Open</button>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $downloadButton.click(() => utils.download(getFileUrl())); | 
					
						
							|  |  |  |             $openButton.click(() => { | 
					
						
							|  |  |  |                 if (utils.isElectron()) { | 
					
						
							|  |  |  |                     const open = require("open"); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-16 19:42:42 +02:00
										 |  |  |                     open(getFileUrl(), {url: true}); | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |                 } | 
					
						
							|  |  |  |                 else { | 
					
						
							|  |  |  |                     window.location.href = getFileUrl(); | 
					
						
							|  |  |  |                 } | 
					
						
							|  |  |  |             }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             // open doesn't work for protected notes since it works through browser which isn't in protected session
 | 
					
						
							|  |  |  |             $openButton.toggle(!note.isProtected); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return $('<div>') | 
					
						
							|  |  |  |                 .append($downloadButton) | 
					
						
							|  |  |  |                 .append('   ') | 
					
						
							|  |  |  |                 .append($openButton); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |         else if (type === 'render') { | 
					
						
							| 
									
										
										
										
											2019-10-05 10:55:29 +02:00
										 |  |  |             const $el = $('<div>'); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             await renderService.render(note, $el, this.ctx); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return $el; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |         else if (type === 'protected-session') { | 
					
						
							|  |  |  |             const $button = $(`<button class="btn btn-sm"><span class="jam jam-door"></span> Enter protected session</button>`) | 
					
						
							|  |  |  |                 .click(protectedSessionService.enterProtectedSession); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return $("<div>") | 
					
						
							|  |  |  |                 .append("<div>This note is protected and to access it you need to enter password.</div>") | 
					
						
							|  |  |  |                 .append("<br/>") | 
					
						
							|  |  |  |                 .append($button); | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  |         else { | 
					
						
							|  |  |  |             return "<em>Content of this note cannot be displayed in the book format</em>"; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-05 20:27:30 +02:00
										 |  |  |     /** @return {boolean} true if this is "auto book" activated (empty text note) and not explicit book note */ | 
					
						
							|  |  |  |     isAutoBook() { | 
					
						
							|  |  |  |         return this.ctx.note.type !== 'book'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     getDefaultZoomLevel() { | 
					
						
							| 
									
										
										
										
											2019-10-14 12:06:10 +02:00
										 |  |  |         if (this.isAutoBook()) { | 
					
						
							|  |  |  |             const w = this.$component.width(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             if (w <= 600) { | 
					
						
							|  |  |  |                 return 1; | 
					
						
							|  |  |  |             } else if (w <= 900) { | 
					
						
							|  |  |  |                 return 2; | 
					
						
							|  |  |  |             } else if (w <= 1300) { | 
					
						
							|  |  |  |                 return 3; | 
					
						
							|  |  |  |             } else { | 
					
						
							|  |  |  |                 return 4; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         else { | 
					
						
							|  |  |  |             return 1; | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2019-10-05 20:27:30 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-06 11:21:12 +02:00
										 |  |  |     getRenderingType(childNote) { | 
					
						
							|  |  |  |         let type = childNote.type; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if (childNote.isProtected) { | 
					
						
							|  |  |  |             if (protectedSessionHolder.isProtectedSessionAvailable()) { | 
					
						
							|  |  |  |                 protectedSessionHolder.touchProtectedSession(); | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |             else { | 
					
						
							|  |  |  |                 type = 'protected-session'; | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return type; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-11-07 23:25:58 +01:00
										 |  |  |     getContent() { | 
					
						
							|  |  |  |         // for auto-book cases when renaming title there should be content
 | 
					
						
							|  |  |  |         return ""; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  |     show() { | 
					
						
							|  |  |  |         this.$component.show(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     focus() {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     onNoteChange() {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     cleanup() { | 
					
						
							| 
									
										
										
										
											2019-10-04 22:21:14 +02:00
										 |  |  |         this.$content.empty(); | 
					
						
							| 
									
										
										
										
											2019-10-01 21:11:11 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     scrollToTop() { | 
					
						
							|  |  |  |         this.$component.scrollTop(0); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | export default NoteDetailBook; |