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.