From fab8b77794115fef9fd38137c0d25d4a09d849ef Mon Sep 17 00:00:00 2001 From: zadam Date: Sun, 12 May 2019 21:45:30 +0200 Subject: [PATCH] configurable hiding of tab row for one tab --- .../0135__add_hideTabRowForOneTab_option.sql | 2 + src/public/javascripts/dialogs/options.js | 13 +++++- .../javascripts/services/note_detail.js | 10 +++-- .../javascripts/services/options_init.js | 33 +++++++++++++-- .../services/protected_session_holder.js | 2 +- src/public/javascripts/services/tab_row.js | 20 ++++++--- src/public/javascripts/services/zoom.js | 2 +- src/routes/api/options.js | 3 +- src/services/app_info.js | 2 +- src/views/dialogs/options.ejs | 41 ++++++++++++------- 10 files changed, 95 insertions(+), 33 deletions(-) create mode 100644 db/migrations/0135__add_hideTabRowForOneTab_option.sql diff --git a/db/migrations/0135__add_hideTabRowForOneTab_option.sql b/db/migrations/0135__add_hideTabRowForOneTab_option.sql new file mode 100644 index 000000000..2eff060c5 --- /dev/null +++ b/db/migrations/0135__add_hideTabRowForOneTab_option.sql @@ -0,0 +1,2 @@ +INSERT INTO options (name, value, utcDateCreated, utcDateModified, isSynced) + VALUES ('hideTabRowForOneTab', 'false', '2019-05-01T18:31:00.874Z', '2019-05-01T18:31:00.874Z', 0); \ No newline at end of file diff --git a/src/public/javascripts/dialogs/options.js b/src/public/javascripts/dialogs/options.js index c2b721388..146b623e4 100644 --- a/src/public/javascripts/dialogs/options.js +++ b/src/public/javascripts/dialogs/options.js @@ -6,6 +6,7 @@ import infoService from "../services/info.js"; import zoomService from "../services/zoom.js"; import utils from "../services/utils.js"; import cssLoader from "../services/css_loader.js"; +import optionsInit from "../services/options_init.js"; const $dialog = $("#options-dialog"); @@ -43,6 +44,7 @@ export default { addTabHandler((function() { const $themeSelect = $("#theme-select"); const $zoomFactorSelect = $("#zoom-factor-select"); + const $oneTabDisplaySelect = $("#one-tab-display-select"); const $leftPaneMinWidth = $("#left-pane-min-width"); const $leftPaneWidthPercent = $("#left-pane-width-percent"); const $mainFontSize = $("#main-font-size"); @@ -76,6 +78,8 @@ addTabHandler((function() { $zoomFactorSelect.prop('disabled', true); } + $oneTabDisplaySelect.val(options.hideTabRowForOneTab === 'true' ? 'hide' : 'show'); + $leftPaneMinWidth.val(options.leftPaneMinWidth); $leftPaneWidthPercent.val(options.leftPaneWidthPercent); @@ -116,6 +120,13 @@ addTabHandler((function() { $container.css("grid-template-columns", `minmax(${leftPaneMinWidth}px, ${leftPanePercent}fr) ${rightPanePercent}fr`); } + $oneTabDisplaySelect.change(function() { + const hideTabRowForOneTab = $(this).val() === 'hide' ? 'true' : 'false'; + + server.put('options/hideTabRowForOneTab/' + hideTabRowForOneTab) + .then(optionsInit.loadOptions); + }); + $leftPaneMinWidth.change(async function() { await server.put('options/leftPaneMinWidth/' + $(this).val()); @@ -217,7 +228,7 @@ addTabHandler((function() { const protectedSessionTimeout = $protectedSessionTimeout.val(); saveOptions({ 'protectedSessionTimeout': protectedSessionTimeout }).then(() => { - protectedSessionHolder.setProtectedSessionTimeout(protectedSessionTimeout); + optionsInit.loadOptions(); }); return false; diff --git a/src/public/javascripts/services/note_detail.js b/src/public/javascripts/services/note_detail.js index 0a7ac4f75..818ec9edd 100644 --- a/src/public/javascripts/services/note_detail.js +++ b/src/public/javascripts/services/note_detail.js @@ -310,7 +310,7 @@ $tabContentsContainer.on("drop", e => { }); }); -async function createEmptyTab() { +async function openEmptyTab() { const ctx = new TabContext(tabRow); tabContexts.push(ctx); @@ -319,7 +319,7 @@ async function createEmptyTab() { await tabRow.setCurrentTab(ctx.tab); } -tabRow.addListener('newTab', createEmptyTab); +tabRow.addListener('newTab', openEmptyTab); tabRow.addListener('activeTabChange', async ({ detail }) => { const tabId = detail.tabEl.getAttribute('data-tab-id'); @@ -342,6 +342,10 @@ tabRow.addListener('tabRemove', async ({ detail }) => { tabContexts = tabContexts.filter(nc => nc.tabId !== tabId); console.log(`Removed tab ${tabId}`); + + if (tabContexts.length === 0) { + openEmptyTab(); + } }); $(tabRow.el).on('contextmenu', '.note-tab', e => { @@ -363,7 +367,7 @@ $(tabRow.el).on('contextmenu', '.note-tab', e => { if (utils.isElectron()) { utils.bindShortcut('ctrl+t', () => { - createEmptyTab(); + openEmptyTab(); }); utils.bindShortcut('ctrl+w', () => { diff --git a/src/public/javascripts/services/options_init.js b/src/public/javascripts/services/options_init.js index 02c60aecf..a3010e449 100644 --- a/src/public/javascripts/services/options_init.js +++ b/src/public/javascripts/services/options_init.js @@ -1,9 +1,34 @@ import server from "./server.js"; -const optionsReady = new Promise((resolve, reject) => { - $(document).ready(() => server.get('options').then(resolve)); -}); +let optionsReady; + +const loadListeners = []; + +function loadOptions() { + optionsReady = new Promise((resolve, reject) => { + server.get('options').then(options => { + resolve(options); + + for (const listener of loadListeners) { + listener(options); + } + }); + }); +} + +loadOptions(); // initial load + +function addLoadListener(listener) { + loadListeners.push(listener); + + // useful when listener has been added after the promise resolved, but can cause double emit if not yet + // that should not be an issue though + optionsReady.then(listener); +} export default { - optionsReady + // use addLoadListener() which will be called also on refreshes + optionsReady, + addLoadListener, + loadOptions } \ No newline at end of file diff --git a/src/public/javascripts/services/protected_session_holder.js b/src/public/javascripts/services/protected_session_holder.js index 89a6f4324..176a9cbb0 100644 --- a/src/public/javascripts/services/protected_session_holder.js +++ b/src/public/javascripts/services/protected_session_holder.js @@ -6,7 +6,7 @@ const PROTECTED_SESSION_ID_KEY = 'protectedSessionId'; let lastProtectedSessionOperationDate = null; let protectedSessionTimeout = null; -optionsInitService.optionsReady.then(options => protectedSessionTimeout = options.protectedSessionTimeout); +optionsInitService.addLoadListener(options => setProtectedSessionTimeout(options.protectedSessionTimeout)); setInterval(() => { if (lastProtectedSessionOperationDate !== null && Date.now() - lastProtectedSessionOperationDate.getTime() > protectedSessionTimeout * 1000) { diff --git a/src/public/javascripts/services/tab_row.js b/src/public/javascripts/services/tab_row.js index 647058c7a..d70850d83 100644 --- a/src/public/javascripts/services/tab_row.js +++ b/src/public/javascripts/services/tab_row.js @@ -5,6 +5,8 @@ * MIT license */ +import optionsInit from './options_init.js'; + !function(i,e){"function"==typeof define&&define.amd?define("jquery-bridget/jquery-bridget",["jquery"],function(t){return e(i,t)}):"object"==typeof module&&module.exports?module.exports=e(i,require("jquery")):i.jQueryBridget=e(i,i.jQuery)}(window,function(t,i){"use strict";var c=Array.prototype.slice,e=t.console,p=void 0===e?function(){}:function(t){e.error(t)};function n(d,o,u){(u=u||i||t.jQuery)&&(o.prototype.option||(o.prototype.option=function(t){u.isPlainObject(t)&&(this.options=u.extend(!0,this.options,t))}),u.fn[d]=function(t){if("string"==typeof t){var i=c.call(arguments,1);return s=i,a="$()."+d+'("'+(r=t)+'")',(e=this).each(function(t,i){var e=u.data(i,d);if(e){var n=e[r];if(n&&"_"!=r.charAt(0)){var o=n.apply(e,s);h=void 0===h?o:h}else p(a+" is not a valid method")}else p(d+" not initialized. Cannot call methods, i.e. "+a)}),void 0!==h?h:e}var e,r,s,h,a,n;return n=t,this.each(function(t,i){var e=u.data(i,d);e?(e.option(n),e._init()):(e=new o(i,n),u.data(i,d,e))}),this},r(u))}function r(t){!t||t&&t.bridget||(t.bridget=n)}return r(i||t.jQuery),n}),function(t,i){"use strict";"function"==typeof define&&define.amd?define("get-size/get-size",[],function(){return i()}):"object"==typeof module&&module.exports?module.exports=i():t.getSize=i()}(window,function(){"use strict";function m(t){var i=parseFloat(t);return-1==t.indexOf("%")&&!isNaN(i)&&i}var e="undefined"==typeof console?function(){}:function(t){console.error(t)},y=["paddingLeft","paddingRight","paddingTop","paddingBottom","marginLeft","marginRight","marginTop","marginBottom","borderLeftWidth","borderRightWidth","borderTopWidth","borderBottomWidth"],b=y.length;function E(t){var i=getComputedStyle(t);return i||e("Style returned "+i+". Are you running this code in a hidden iframe on Firefox? See http://bit.ly/getsizebug1"),i}var _,x=!1;function P(t){if(function(){if(!x){x=!0;var t=document.createElement("div");t.style.width="200px",t.style.padding="1px 2px 3px 4px",t.style.borderStyle="solid",t.style.borderWidth="1px 2px 3px 4px",t.style.boxSizing="border-box";var i=document.body||document.documentElement;i.appendChild(t);var e=E(t);P.isBoxSizeOuter=_=200==m(e.width),i.removeChild(t)}}(),"string"==typeof t&&(t=document.querySelector(t)),t&&"object"==typeof t&&t.nodeType){var i=E(t);if("none"==i.display)return function(){for(var t={width:0,height:0,innerWidth:0,innerHeight:0,outerWidth:0,outerHeight:0},i=0;i 1 ? "block" : "none"; + this.el.style.display = (this.tabEls.length > 1 || !this.hideTabRowForOneTab) ? "block" : "none"; } get tabEls() { @@ -392,7 +399,8 @@ class TabRow { } const noteTabRowEl = document.querySelector('.note-tab-row'); -const tabRow = new TabRow(); -tabRow.init(noteTabRowEl); +const tabRow = new TabRow(noteTabRowEl); + +optionsInit.addLoadListener(options => tabRow.setHideTabRowForOneTab(options.hideTabRowForOneTab === 'true')); export default tabRow; \ No newline at end of file diff --git a/src/public/javascripts/services/zoom.js b/src/public/javascripts/services/zoom.js index 9eb45d61c..6900779be 100644 --- a/src/public/javascripts/services/zoom.js +++ b/src/public/javascripts/services/zoom.js @@ -40,7 +40,7 @@ function getCurrentZoom() { } if (utils.isElectron()) { - optionsInitService.optionsReady.then(options => setZoomFactor(options.zoomFactor)) + optionsInitService.addLoadListener(options => setZoomFactor(options.zoomFactor)) } export default { diff --git a/src/routes/api/options.js b/src/routes/api/options.js index ca95fc4e7..60783a509 100644 --- a/src/routes/api/options.js +++ b/src/routes/api/options.js @@ -19,7 +19,8 @@ const ALLOWED_OPTIONS = [ 'mainFontSize', 'treeFontSize', 'detailFontSize', - 'openTabs' + 'openTabs', + 'hideTabRowForOneTab' ]; async function getOptions() { diff --git a/src/services/app_info.js b/src/services/app_info.js index ff794645d..3d4443583 100644 --- a/src/services/app_info.js +++ b/src/services/app_info.js @@ -4,7 +4,7 @@ const build = require('./build'); const packageJson = require('../../package'); const {TRILIUM_DATA_DIR} = require('./data_dir'); -const APP_DB_VERSION = 134; +const APP_DB_VERSION = 135; const SYNC_VERSION = 8; module.exports = { diff --git a/src/views/dialogs/options.ejs b/src/views/dialogs/options.ejs index 4fb8c3e14..87231869b 100644 --- a/src/views/dialogs/options.ejs +++ b/src/views/dialogs/options.ejs @@ -35,22 +35,31 @@

Settings on this options tab are saved automatically after each change.

-
- - -
+
+
+ + +
-
- +
+ - + +
+ +
+ + +

Zooming can be controlled with CTRL-+ and CTRL-= shortcuts as well.

Font sizes

-
@@ -90,16 +99,18 @@

Left pane sizing

-
- +
+
+ - -
+ +
-
- +
+ - + +

Left pane width is calculated from the percent of window size, if this is smaller than minimum width, then minimum width is used. If you want to have fixed width left pane, set minimum width to the desired width and set percent to 0.