diff --git a/src/public/javascripts/services/bootstrap.js b/src/public/javascripts/services/bootstrap.js index 2aaee1f1c..3410a1dd1 100644 --- a/src/public/javascripts/services/bootstrap.js +++ b/src/public/javascripts/services/bootstrap.js @@ -33,6 +33,9 @@ import bundle from "./bundle.js"; import treeCache from "./tree_cache.js"; import libraryLoader from "./library_loader.js"; import hoistedNoteService from './hoisted_note.js'; +import noteTypeService from './note_type.js'; +import linkService from './link.js'; +import noteAutocompleteService from './note_autocomplete.js'; // required for CKEditor image upload plugin window.glob.getCurrentNode = treeService.getCurrentNode; @@ -144,3 +147,9 @@ entrypoints.registerEntrypoints(); noteTooltipService.setupGlobalTooltip(); bundle.executeStartupBundles(); + +noteTypeService.init(); + +linkService.init(); + +noteAutocompleteService.init(); \ No newline at end of file diff --git a/src/public/javascripts/services/link.js b/src/public/javascripts/services/link.js index 96150bb6f..bc08aa846 100644 --- a/src/public/javascripts/services/link.js +++ b/src/public/javascripts/services/link.js @@ -88,17 +88,19 @@ function addTextToEditor(text) { }); } -ko.bindingHandlers.noteLink = { - init: async function(element, valueAccessor, allBindings, viewModel, bindingContext) { - const noteId = ko.unwrap(valueAccessor()); +function init() { + ko.bindingHandlers.noteLink = { + init: async function(element, valueAccessor, allBindings, viewModel, bindingContext) { + const noteId = ko.unwrap(valueAccessor()); - if (noteId) { - const link = await createNoteLink(noteId); + if (noteId) { + const link = await createNoteLink(noteId); - $(element).append(link); + $(element).append(link); + } } - } -}; + }; +} // when click on link popup, in case of internal link, just go the the referenced note instead of default behavior // of opening the link in new window/tab @@ -124,5 +126,6 @@ export default { getNotePathFromUrl, createNoteLink, addLinkToEditor, - addTextToEditor + addTextToEditor, + init }; \ No newline at end of file diff --git a/src/public/javascripts/services/mobile.js b/src/public/javascripts/services/mobile.js index daec6ceec..750dcf61c 100644 --- a/src/public/javascripts/services/mobile.js +++ b/src/public/javascripts/services/mobile.js @@ -1,3 +1,43 @@ import treeService from "./tree.js"; +import noteDetailService from "./note_detail.js"; +import dragAndDropSetup from "./drag_and_drop.js"; +import treeCache from "./tree_cache.js"; +import treeBuilder from "./tree_builder.js"; -treeService.showTree(); \ No newline at end of file +const $tree = $("#tree"); + +async function showTree() { + const tree = await treeService.loadTree(); + + $tree.fancytree({ + autoScroll: true, + keyboard: false, // we takover keyboard handling in the hotkeys plugin + extensions: ["dnd5", "clones"], + source: tree, + scrollParent: $tree, + minExpandLevel: 2, // root can't be collapsed + activate: (event, data) => { + const node = data.node; + const noteId = node.data.noteId; + + treeService.setCurrentNotePathToHash(node); + + noteDetailService.switchToNote(noteId, true); + }, + expand: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, true), + collapse: (event, data) => treeService.setExpandedToServer(data.node.data.branchId, false), + init: (event, data) => treeService.treeInitialized(), // don't collapse to short form + dnd5: dragAndDropSetup, + lazyLoad: function(event, data) { + const noteId = data.node.data.noteId; + + data.result = treeCache.getNote(noteId).then(note => treeBuilder.prepareBranch(note)); + }, + clones: { + highlightActiveClones: true + } + }); + +} + +showTree(); \ No newline at end of file diff --git a/src/public/javascripts/services/note_autocomplete.js b/src/public/javascripts/services/note_autocomplete.js index 4e9ad1f38..00bf55f3b 100644 --- a/src/public/javascripts/services/note_autocomplete.js +++ b/src/public/javascripts/services/note_autocomplete.js @@ -101,40 +101,42 @@ function initNoteAutocomplete($el, options) { return $el; } -$.fn.getSelectedPath = function() { - if (!$(this).val().trim()) { - return ""; - } - else { - return $(this).attr(SELECTED_PATH_KEY); - } -}; +function init() { + $.fn.getSelectedPath = function () { + if (!$(this).val().trim()) { + return ""; + } else { + return $(this).attr(SELECTED_PATH_KEY); + } + }; -$.fn.setSelectedPath = function(path) { - path = path || ""; + $.fn.setSelectedPath = function (path) { + path = path || ""; - $(this).attr(SELECTED_PATH_KEY, path); + $(this).attr(SELECTED_PATH_KEY, path); - $(this) - .closest(".input-group") - .find(".go-to-selected-note-button") - .toggleClass("disabled", !path.trim()) - .attr(SELECTED_PATH_KEY, path); // we also set attr here so tooltip can be displayed -}; + $(this) + .closest(".input-group") + .find(".go-to-selected-note-button") + .toggleClass("disabled", !path.trim()) + .attr(SELECTED_PATH_KEY, path); // we also set attr here so tooltip can be displayed + }; -ko.bindingHandlers.noteAutocomplete = { - init: function(element, valueAccessor, allBindings, viewModel, bindingContext) { - initNoteAutocomplete($(element)); + ko.bindingHandlers.noteAutocomplete = { + init: function (element, valueAccessor, allBindings, viewModel, bindingContext) { + initNoteAutocomplete($(element)); - $(element).setSelectedPath(bindingContext.$data.selectedPath); + $(element).setSelectedPath(bindingContext.$data.selectedPath); - $(element).on('autocomplete:selected', function(event, suggestion, dataset) { - bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : ''; - }); - } -}; + $(element).on('autocomplete:selected', function (event, suggestion, dataset) { + bindingContext.$data.selectedPath = $(element).val().trim() ? suggestion.path : ''; + }); + } + }; +} export default { initNoteAutocomplete, - showRecentNotes + showRecentNotes, + init } \ No newline at end of file diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js index 60d778e19..a3c246792 100644 --- a/src/public/javascripts/services/note_detail.js +++ b/src/public/javascripts/services/note_detail.js @@ -17,6 +17,7 @@ import noteDetailRender from './note_detail_render.js'; import noteDetailRelationMap from './note_detail_relation_map.js'; import bundleService from "./bundle.js"; import attributeService from "./attributes.js"; +import utils from "./utils.js"; const $noteTitle = $("#note-title"); @@ -89,11 +90,11 @@ async function reload() { await loadNoteDetail(getCurrentNoteId()); } -async function switchToNote(noteId) { +async function switchToNote(noteId, mobile) { if (getCurrentNoteId() !== noteId) { await saveNoteIfChanged(); - await loadNoteDetail(noteId); + await loadNoteDetail(noteId, mobile); } } @@ -177,8 +178,10 @@ async function loadNoteDetail(noteId) { // only now that we're in sync with tree active node we will switch currentNote currentNote = loadedNote; - // needs to happend after loading the note itself because it references current noteId - attributeService.refreshAttributes(); + if (utils.isDesktop()) { + // needs to happen after loading the note itself because it references current noteId + attributeService.refreshAttributes(); + } if (isNewNoteCreated) { isNewNoteCreated = false; @@ -197,8 +200,10 @@ async function loadNoteDetail(noteId) { try { $noteTitle.val(currentNote.title); - noteTypeService.setNoteType(currentNote.type); - noteTypeService.setNoteMime(currentNote.mime); + if (utils.isDesktop()) { + noteTypeService.setNoteType(currentNote.type); + noteTypeService.setNoteMime(currentNote.mime); + } for (const componentType in components) { if (componentType !== currentNote.type) { @@ -225,13 +230,15 @@ async function loadNoteDetail(noteId) { // after loading new note make sure editor is scrolled to the top getComponent(currentNote.type).scrollToTop(); - $scriptArea.empty(); + if (utils.isDesktop()) { + $scriptArea.empty(); - await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView'); + await bundleService.executeRelationBundles(getCurrentNote(), 'runOnNoteView'); - await attributeService.showAttributes(); + await attributeService.showAttributes(); - await showChildrenOverview(); + await showChildrenOverview(); + } } async function showChildrenOverview() { diff --git a/src/public/javascripts/services/note_type.js b/src/public/javascripts/services/note_type.js index 97e1d1e5e..6e9b29ad5 100644 --- a/src/public/javascripts/services/note_type.js +++ b/src/public/javascripts/services/note_type.js @@ -44,7 +44,7 @@ const DEFAULT_MIME_TYPES = [ { mime: 'text/x-yaml', title: 'YAML' } ]; -const noteTypeModel = new NoteTypeModel(); +let noteTypeModel; function NoteTypeModel() { const self = this; @@ -153,7 +153,11 @@ function NoteTypeModel() { } } -ko.applyBindings(noteTypeModel, document.getElementById('note-type-wrapper')); +function init() { + noteTypeModel = new NoteTypeModel(); + + ko.applyBindings(noteTypeModel, document.getElementById('note-type-wrapper')); +} export default { getNoteType: () => noteTypeModel.type(), @@ -168,5 +172,6 @@ export default { getDefaultCodeMimeTypes: () => DEFAULT_MIME_TYPES.slice(), getCodeMimeTypes: () => noteTypeModel.codeMimeTypes(), - setCodeMimeTypes: types => noteTypeModel.codeMimeTypes(types) + setCodeMimeTypes: types => noteTypeModel.codeMimeTypes(types), + init }; \ No newline at end of file diff --git a/src/public/javascripts/services/tree.js b/src/public/javascripts/services/tree.js index 205ecaad5..a68a3d2b6 100644 --- a/src/public/javascripts/services/tree.js +++ b/src/public/javascripts/services/tree.js @@ -359,7 +359,7 @@ function initFancyTree(tree) { $tree.fancytree({ autoScroll: true, keyboard: false, // we takover keyboard handling in the hotkeys plugin - extensions: ["hotkeys", "filter", "dnd5", "clones"], + extensions: ["hotkeys", "dnd5", "clones"], source: tree, scrollParent: $tree, minExpandLevel: 2, // root can't be collapsed @@ -397,18 +397,6 @@ function initFancyTree(tree) { hotkeys: { keydown: treeKeyBindings }, - filter: { - autoApply: true, // Re-apply last filter if lazy data is loaded - autoExpand: true, // Expand all branches that contain matches while filtered - counter: false, // Show a badge with number of matching child nodes near parent icons - fuzzy: false, // Match single characters in order, e.g. 'fb' will match 'FooBar' - hideExpandedCounter: true, // Hide counter badge if parent is expanded - hideExpanders: false, // Hide expanders if all child nodes are hidden by filter - highlight: true, // Highlight matches by wrapping inside tags - leavesOnly: false, // Match end nodes only - nodata: true, // Display a 'no data' status node if result is empty - mode: "hide" // Grayout unmatched nodes (pass "hide" to remove unmatched node instead) - }, dnd5: dragAndDropSetup, lazyLoad: function(event, data) { const noteId = data.node.data.noteId; @@ -696,5 +684,8 @@ export default { getSelectedNodes, clearSelectedNodes, sortAlphabetically, - showTree + showTree, + loadTree, + treeInitialized, + setExpandedToServer }; \ No newline at end of file diff --git a/src/public/javascripts/services/utils.js b/src/public/javascripts/services/utils.js index d88a8e574..32d4f8e77 100644 --- a/src/public/javascripts/services/utils.js +++ b/src/public/javascripts/services/utils.js @@ -143,6 +143,14 @@ function bindShortcut(keyboardShortcut, handler) { }); } +function isMobile() { + return window.device === "mobile"; +} + +function isDesktop() { + return window.device === "desktop"; +} + export default { reloadApp, parseDate, @@ -166,5 +174,7 @@ export default { download, toObject, randomString, - bindShortcut + bindShortcut, + isMobile, + isDesktop }; \ No newline at end of file diff --git a/src/views/index.ejs b/src/views/index.ejs index 6c8d045c1..aefc485c0 100644 --- a/src/views/index.ejs +++ b/src/views/index.ejs @@ -205,6 +205,7 @@ - - - - -