From 87a6294d54a4ceae9b2b4dc10a9bd726d8bc4472 Mon Sep 17 00:00:00 2001 From: penge Date: Thu, 13 Aug 2020 17:47:09 +0200 Subject: [PATCH 1/9] Remove margin-right in #sidebar-notes --- notes.css | 1 - 1 file changed, 1 deletion(-) diff --git a/notes.css b/notes.css index 700f2954..f7b09772 100644 --- a/notes.css +++ b/notes.css @@ -117,7 +117,6 @@ body.with-sidebar { left: 25%; } body:not(.with-sidebar) { left: 0 !important; } #sidebar-notes { - margin-right: 1px; /* Drag */ padding: .5em; overflow-y: auto; flex-grow: 1; From e8206e6892019dac9dd79881aaef708dbb384434 Mon Sep 17 00:00:00 2001 From: penge Date: Sun, 11 Oct 2020 13:58:33 +0200 Subject: [PATCH 2/9] Remove old comment --- notes/reserved.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/notes/reserved.js b/notes/reserved.js index 1328ecec..180853b6 100644 --- a/notes/reserved.js +++ b/notes/reserved.js @@ -1,8 +1,5 @@ /** * Notes that cannot be renamed or deleted - * - * They have as well a different color to be easily recognized - * See notes.css => .reserved */ const reserved = [ "Clipboard", From 733833a00f56fb64edbf0087551024ef47a53306 Mon Sep 17 00:00:00 2001 From: penge Date: Thu, 13 Aug 2020 17:47:54 +0200 Subject: [PATCH 3/9] Use history to navigate between notes This restores the default behavior of Ctrl + [ and Ctrl + ]. It also resolves the bug where Ctrl + Shift + [ and Ctrl + Shift + ] wasn't working in Full Screen. --- notes.js | 20 +++++++++++++++++--- notes/history.js | 32 ++++++++++++++++++++++++++++++++ notes/hotkeys.js | 12 ------------ notes/state/index.js | 3 +++ options.html | 4 ++-- 5 files changed, 54 insertions(+), 17 deletions(-) create mode 100644 notes/history.js diff --git a/notes.js b/notes.js index 1b891db9..d47bad7f 100644 --- a/notes.js +++ b/notes.js @@ -1,4 +1,4 @@ -/* global chrome, window, document, Set, localStorage, setTimeout */ +/* global chrome, window, document, Set, localStorage */ // Setting application state and view updates are done via a Proxy import state from "./notes/state/index.js"; @@ -12,6 +12,8 @@ import sidebar from "./notes/sidebar.js"; import { newNoteModal } from "./notes/modals.js"; import contextMenu from "./notes/context-menu.js"; +import notesHistory from "./notes/history.js"; + let tabId; // important so can update the content in other tabs (except the tab that has made the changes) chrome.tabs.getCurrent((tab) => { // set as a "string" to quickly compare with localStorage.getItem("notesChangedBy") @@ -77,7 +79,7 @@ chrome.storage.local.get([ const { notification, font, size, sidebar, sidebarWidth, toolbar, theme, customTheme, - notes, active, + notes, active : lastActive, focus, tab, sync } = local; @@ -93,7 +95,12 @@ chrome.storage.local.get([ // Notes state.notes = notes; - state.active = (active in notes) ? active : null; + const activeFromUrl = window.location.search.startsWith("?") && window.location.search.substring(1); // Bookmark + const activeCandidate = activeFromUrl || lastActive || "Clipboard"; + state.active = (activeCandidate in notes) ? activeCandidate : null; + if (state.active && !activeFromUrl) { + notesHistory.replace(activeCandidate); + } // Options state.focus = focus; @@ -152,6 +159,7 @@ chrome.storage.onChanged.addListener((changes, areaName) => { const newActive = changes["active"] && changes["active"].newValue; if (newActive && newActive in newNotes) { state.active = newActive; + notesHistory.push(newActive); return; } @@ -169,6 +177,7 @@ chrome.storage.onChanged.addListener((changes, areaName) => { ) { const newActive = state.active; state.active = newActive; + notesHistory.replace(newActive); return; } @@ -182,6 +191,7 @@ chrome.storage.onChanged.addListener((changes, areaName) => { const newSet = new Set(Object.keys(newNotes)); if (oldSet.size > newSet.size) { state.active = "Clipboard"; + notesHistory.replace("Clipboard"); return; } @@ -191,6 +201,7 @@ chrome.storage.onChanged.addListener((changes, areaName) => { if (diff.size === 1) { const newActive = diff.values().next().value; state.active = newActive; + notesHistory.replace(newActive); } } } @@ -229,6 +240,9 @@ window.addEventListener("blur", () => { document.body.classList.remove("with-command"); }); +// History +notesHistory.attach(state); + // Notes are saved every 1 second by "saveNotesDebounce()" // When the window is closed sooner, save the notes immediately, if changed window.addEventListener("beforeunload", () => { diff --git a/notes/history.js b/notes/history.js new file mode 100644 index 00000000..e9ed0ffc --- /dev/null +++ b/notes/history.js @@ -0,0 +1,32 @@ +/* global window */ + +// Use replace when a note is renamed or deleted +const replace = (noteName) => + window.history.replaceState({ noteName }, noteName, `?${noteName}`); + +// Use push when a note is created +const push = (noteName) => + window.history.pushState({ noteName }, noteName, `?${noteName}`); + +let attached = false; +const attach = (state) => { + if (attached) { + return; + } + + window.onpopstate = (e) => { + const noteName = e.state && e.state.noteName; + if (noteName && noteName in state.notes) { + state.active = noteName; + } + }; + + attached = true; +}; + +export default { + replace, + push, + + attach, +}; diff --git a/notes/hotkeys.js b/notes/hotkeys.js index 2c202bd3..07d77c59 100644 --- a/notes/hotkeys.js +++ b/notes/hotkeys.js @@ -63,18 +63,6 @@ const keydown = (state) => document.addEventListener("keydown", (event) => { return; } - if ((event.metaKey || event.ctrlKey) && event.key === "[") { - event.preventDefault(); - state.previousNote(); - return; - } - - if ((event.metaKey || event.ctrlKey) && event.key === "]") { - event.preventDefault(); - state.nextNote(); - return; - } - if ((event.metaKey || event.ctrlKey) && event.shiftKey && (event.key === "F" || event.key === "f")) { event.preventDefault(); state.active && toggleFocus(); // toggle focus only when a note is open diff --git a/notes/state/index.js b/notes/state/index.js index ecce3840..28066b37 100644 --- a/notes/state/index.js +++ b/notes/state/index.js @@ -6,6 +6,8 @@ import deleteNote from "./delete-note.js"; import view from "../view/index.js"; +import notesHistory from "../history.js"; + let stateProxy; const activateNote = (noteName) => { @@ -15,6 +17,7 @@ const activateNote = (noteName) => { if (noteName in stateProxy.notes) { stateProxy.active = noteName; + notesHistory.push(noteName); } else { stateProxy.active = null; } diff --git a/options.html b/options.html index 83156f16..0ae9faa7 100644 --- a/options.html +++ b/options.html @@ -94,11 +94,11 @@

Hotkeys

⌘ + e - Go to Previous note + Navigate Backward one note ⌘ + [ - Go to Next note + Navigate Forward one note ⌘ + ] From b6aa255298f55ac4c7393063207ea4bdb744b2d6 Mon Sep 17 00:00:00 2001 From: penge Date: Thu, 27 Aug 2020 10:12:40 +0200 Subject: [PATCH 4/9] Rename with-command to with-control --- notes.css | 2 +- notes.js | 6 +++--- notes/hotkeys.js | 6 +++--- notes/view/set-notes.js | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/notes.css b/notes.css index f7b09772..491d048d 100644 --- a/notes.css +++ b/notes.css @@ -219,7 +219,7 @@ body.resizing-sidebar-locked-max { cursor: w-resize; } font-weight: bold; } -body.with-command #content a { +body.with-control #content a { cursor: pointer; } diff --git a/notes.js b/notes.js index d47bad7f..22adabb2 100644 --- a/notes.js +++ b/notes.js @@ -155,7 +155,7 @@ chrome.storage.onChanged.addListener((changes, areaName) => { const newNotes = changes["notes"].newValue; state.notes = newNotes; - // Autoactivate the created note + // Auto-activate the created note const newActive = changes["active"] && changes["active"].newValue; if (newActive && newActive in newNotes) { state.active = newActive; @@ -224,7 +224,7 @@ chrome.storage.onChanged.addListener((changes, areaName) => { }); const openLink = (event) => { - if (!document.body.classList.contains("with-command")) { + if (!document.body.classList.contains("with-control")) { return; } @@ -237,7 +237,7 @@ content.addEventListener("click", openLink); // Chrome OS, Windows content.addEventListener("contextmenu", openLink); // OSX would open Context menu when holding Ctrl window.addEventListener("blur", () => { - document.body.classList.remove("with-command"); + document.body.classList.remove("with-control"); }); // History diff --git a/notes/hotkeys.js b/notes/hotkeys.js index 07d77c59..e463bfc2 100644 --- a/notes/hotkeys.js +++ b/notes/hotkeys.js @@ -10,7 +10,7 @@ const toggleFocus = () => { const keydown = (state) => document.addEventListener("keydown", (event) => { if (event.ctrlKey) { - document.body.classList.add("with-command"); + document.body.classList.add("with-control"); const hoveredNote = document.querySelector(".note.over"); hoveredNote && state.activateNote(hoveredNote.innerText); } @@ -32,7 +32,7 @@ const keydown = (state) => document.addEventListener("keydown", (event) => { // Look for #confirm in #modal const confirm = document.getElementById("confirm"); if (confirm) { - // if modal is open and thefore can be confirmed and closed with Enter, + // if modal is open and therefore can be confirmed and closed with Enter, // prevent default behaviour of Enter event.preventDefault(); confirm.click(); @@ -77,7 +77,7 @@ const keydown = (state) => document.addEventListener("keydown", (event) => { }); const keyup = () => document.addEventListener("keyup", () => { - document.body.classList.remove("with-command"); + document.body.classList.remove("with-control"); }); const register = (state) => { diff --git a/notes/view/set-notes.js b/notes/view/set-notes.js index e64c9b23..3745dfaa 100644 --- a/notes/view/set-notes.js +++ b/notes/view/set-notes.js @@ -18,7 +18,7 @@ const createSidebarNote = (noteName, { activeNote, activateNote }) => { oneNote.addEventListener("mouseenter", () => { oneNote.classList.add("over"); - if (document.body.classList.contains("with-command") && !document.body.classList.contains("with-modal")) { + if (document.body.classList.contains("with-control") && !document.body.classList.contains("with-modal")) { activateNote(noteName); } }); From 5621d40c6da5d2735a24c43555e212ff62b973a3 Mon Sep 17 00:00:00 2001 From: penge Date: Sun, 11 Oct 2020 13:52:49 +0200 Subject: [PATCH 5/9] Don't show context menu for Clipboard - Clipboard cannot be renamed or deleted at the moment --- notes/context-menu.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/notes/context-menu.js b/notes/context-menu.js index 716ea03c..33c52463 100644 --- a/notes/context-menu.js +++ b/notes/context-menu.js @@ -5,6 +5,7 @@ import range from "./range.js"; import { contextMenu, renameAction, deleteAction } from "./view/elements.js"; import { renameNoteModal, deleteNoteModal } from "./modals.js"; +import { isReserved } from "./reserved.js"; const hide = () => { if (!document.body.classList.contains("with-context-menu")) { @@ -15,6 +16,10 @@ const hide = () => { }; const show = (x, y, noteName) => { + if (isReserved(noteName)) { + return; + } + range.save(); contextMenu.style.left = x + "px"; From 6b6645a34700b7c09e68b30919de944f52def19b Mon Sep 17 00:00:00 2001 From: penge Date: Sun, 11 Oct 2020 15:53:10 +0200 Subject: [PATCH 6/9] Add description to Insert Link Modal --- notes.css | 5 +++++ notes.html | 6 ++++++ notes/modals.js | 13 ++++++++++--- options.css | 10 ---------- themes/shared.css | 13 +++++++++++++ 5 files changed, 34 insertions(+), 13 deletions(-) diff --git a/notes.css b/notes.css index 491d048d..1dc931ab 100644 --- a/notes.css +++ b/notes.css @@ -366,6 +366,11 @@ body.with-modal #toolbar { color: var(--modal-button-text-color); } +#modal .modal-description { + font-size: .75em; + margin-top: 1.5em; +} + body.with-overlay #modal { border: none !important; } diff --git a/notes.html b/notes.html index cbdb8f82..32793256 100644 --- a/notes.html +++ b/notes.html @@ -277,6 +277,12 @@ + + + + diff --git a/notes/modals.js b/notes/modals.js index c6589808..f406a5e0 100644 --- a/notes/modals.js +++ b/notes/modals.js @@ -17,16 +17,22 @@ const removeModal = (onRemove) => { return true; }; -const createModal = ({ clazz, overlay, captionValue, inputValue, cancelValue, confirmValue, validate, onConfirm, onRemove }) => { +const createModal = ({ clazz, overlay, captionValue, inputValue, cancelValue, confirmValue, descriptionId, validate, onConfirm, onRemove }) => { removeModal(); range.save(); const node = modalTemplate.content.cloneNode(true); - const modal = node.children[0]; + const modal = node.getElementById("modal"); + if (clazz) { modal.className = clazz; } + if (descriptionId) { + const modalDescription = node.getElementById(descriptionId); + modal.append(modalDescription); + } + const caption = node.getElementById("caption"); if (captionValue) { caption.innerHTML = captionValue; } else { caption.className = "hide"; } const input = node.getElementById("input"); if (typeof inputValue === "string") { input.value = inputValue; } else { input.className = "hide"; } const cancel = node.getElementById("cancel"); if (cancelValue) { cancel.value = cancelValue; } @@ -60,7 +66,7 @@ const createModal = ({ clazz, overlay, captionValue, inputValue, cancelValue, co document.body.classList.add("with-modal"); if (overlay) { document.body.classList.add("with-overlay", overlay); } - document.body.prepend(node); + document.body.prepend(modal); input.focus(); input.onblur = () => { @@ -85,6 +91,7 @@ export const insertLinkModal = (onConfirm) => { captionValue: "Link URL", inputValue: "", confirmValue: "Insert", + descriptionId: "insert-link-modal-description", validate: (inputValue) => inputValue.length > 0, onConfirm, }); diff --git a/options.css b/options.css index 13bf42a2..184b35b7 100644 --- a/options.css +++ b/options.css @@ -130,16 +130,6 @@ input, select { /* Hotkeys */ -.hotkey { - border-radius: 3px; - padding: 3px 8px; - font-weight: bold; - display: inline-block; - font-family: "Courier New", Courier, monospace; - background: var(--hotkey-background-color); - color: var(--hotkey-text-color); -} - table .hotkey { margin-left: 2em; } diff --git a/themes/shared.css b/themes/shared.css index e1a8c3a0..334a1567 100644 --- a/themes/shared.css +++ b/themes/shared.css @@ -28,3 +28,16 @@ a:hover { .hide { display: none !important; } + +.hotkey, .hotlink { + border-radius: 3px; + padding: 3px 8px; + display: inline-block; + font-family: "Courier New", Courier, monospace; + background: var(--hotkey-background-color); + color: var(--hotkey-text-color); +} + +.hotkey { + font-weight: bold; +} From 63eea7c4ea028a17023018c31f38a8d31cdaea02 Mon Sep 17 00:00:00 2001 From: penge Date: Sun, 11 Oct 2020 13:04:45 +0200 Subject: [PATCH 7/9] Add .editorconfig --- .editorconfig | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 .editorconfig diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..73db316c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,8 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true From 00741a4287e5a7b8fe3d02e67368b7f6889b6f1c Mon Sep 17 00:00:00 2001 From: penge Date: Sun, 11 Oct 2020 13:04:55 +0200 Subject: [PATCH 8/9] Update README --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 0236bf0d..9ecc1cce 100644 --- a/README.md +++ b/README.md @@ -76,8 +76,7 @@ My Notes needs to be open in the second computer and same Google Account needs t ## Google Drive Sync -Google Drive Sync (see Options) saves your notes to Google Drive and synchronizes the changes between your local My Notes and your Google Drive -every time you hit the Sync button (bottom left corner). +Google Drive Sync (see Options) saves your notes to your personal Google Drive and synchronizes the changes between your local My Notes and your Google Drive every time you hit the Sync button (bottom left corner). Benefits: @@ -88,18 +87,23 @@ Benefits: ### Location -Notes are uploaded to your Google Drive to the folder **My Notes**. This folder is created automatically. -If the folder exists from a previous installation, notes are downloaded and uploaded. +Notes are uploaded to your Google Drive to the folder "My Notes". This folder is created automatically. +If the folder exists from a previous installation, notes are downloaded and uploaded and the synchronization continues. ### Synchronization -Notes are synchronized every time you hit the Sync button (bottom left corner). Synchronization works in both ways — to Google Drive, from Google Drive. +Notes are synchronized every time you hit the Sync button. +While the synchronization is in progress, Sync button will spin. +Sync button tooltip shows the time of the most recent synchronization. + ### Access -My Notes has only access to the folder **My Notes**. -It cannot see any other files in your Google Drive. +My Notes has only access to the folder "My Notes" and only to the files it created in this folder. +It cannot see, access or modify any other files in your Google Drive. + +Google Drive Sync works only if the extension is installed from Web Store.

@@ -148,6 +152,7 @@ tests/ # Entrypoint for tests # - Prints "Assertion failed: console.assert" if any assertion failed +.editorconfig # To enforce same editor configuration .eslintrc # To enforce code quality and same coding style .gitignore # To exclude any generated files (only .DS_Store at this point) @@ -172,6 +177,25 @@ README.md

+## Browser support + +My Notes has full support in Google Chrome only. Although it may be possible to install it in other browsers, the support is not complete. + +Support for other Chromium-based browsers will be added if possible. + +

+ +## Security and Privacy + +My Notes doesn't collect any personal information or data. +All your notes are stored locally in your browser. +If you use Google Drive Sync, My Notes can backup the notes to your personal Google Drive. + +To provide Google Drive functionality, My Notes has an application in Google Cloud. +The sole purpose of this application is to authenticate you securely towards the Google Drive and to allow the synchronization of notes. + +

+ ## Permissions My Notes has the permissions listed in `manifest.json`. @@ -181,12 +205,20 @@ My Notes has the permissions listed in `manifest.json`. - `"storage"` — used to save the notes and options to Chrome Storage - `"contextMenus"` — used to create My Notes Context menu +Required permissions are shown to the user before installing the extension, and are needed at all times to provide the basic functionality. + **Optional:** -- `"tabs"` — used by **Open My Notes in every New Tab** (see **Options**) -- `"identity"` — used by **Enable Google Drive Sync** (see **Options**) +- `"tabs"` — needed for "Open My Notes in every New Tab" (see Options) +- `"identity"` — needed for "Enable Google Drive Sync" (see Options) + +Optional permissions are needed only to provide additional functionality that can be enabled via a checkbox in Options. + +User has the choice to either approve or deny the permissions. -`"tabs"` is a more powerful permission — the displayed warning may contain an unrelated message — `It can: Read your Browsing history`. +`"tabs"` is a more powerful permission and browsers usually display a generic, in this case unrelated warning as `It can: Read your Browsing history`. +My Notes doesn't read your browsing history. The permission is only needed to enable "Open My Notes in every New Tab". +To read more about the warnings, see the [offical documentation](https://developer.chrome.com/extensions/permission_warnings).

From bbce3f2f4e3a352367f58ce8b42e6df0415c537d Mon Sep 17 00:00:00 2001 From: penge Date: Sat, 29 Aug 2020 12:40:20 +0200 Subject: [PATCH 9/9] 3.4.2 --- manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/manifest.json b/manifest.json index 2aa1bace..2dce84bd 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "manifest_version": 2, "name": "My Notes", "description": "Simple and fast note-taking.", - "version": "3.4.1", + "version": "3.4.2", "homepage_url": "https://github.com/penge/my-notes", "icons": { "128": "images/icon128.png" }, "options_page": "options.html",