From 93f8d6bbe771dd6eca099638eb45d2e1f20e8951 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Thu, 11 Mar 2021 15:07:39 +0100 Subject: [PATCH 01/18] refactor: use setState --- app/assets/javascripts/views/notes/notes_view.ts | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/views/notes/notes_view.ts b/app/assets/javascripts/views/notes/notes_view.ts index 9d71f391b..5eee017f7 100644 --- a/app/assets/javascripts/views/notes/notes_view.ts +++ b/app/assets/javascripts/views/notes/notes_view.ts @@ -706,7 +706,12 @@ class NotesViewCtrl extends PureViewCtrl { async onIncludeProtectedNoteTextChange(event: Event) { this.searchBarInput?.[0].focus(); if (this.state.noteFilter.includeProtectedNoteText) { - this.state.noteFilter.includeProtectedNoteText = false; + await this.setState({ + noteFilter: { + ...this.state.noteFilter, + includeProtectedNoteText: false, + }, + }); this.reloadNotesDisplayOptions(); await this.reloadNotes(); } else { @@ -715,7 +720,12 @@ class NotesViewCtrl extends PureViewCtrl { }); event.preventDefault(); if (await this.application.authorizeSearchingProtectedNotesText()) { - this.state.noteFilter.includeProtectedNoteText = true; + await this.setState({ + noteFilter: { + ...this.state.noteFilter, + includeProtectedNoteText: true, + }, + }); this.reloadNotesDisplayOptions(); await this.reloadNotes(); } From 59dbbcf6fd179c6d4555b52ea04eb68350819ac8 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Thu, 11 Mar 2021 15:41:29 +0100 Subject: [PATCH 02/18] feat: authorize CloudLink access --- app/assets/javascripts/ui_models/application.ts | 15 +++++++++++---- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/app/assets/javascripts/ui_models/application.ts b/app/assets/javascripts/ui_models/application.ts index 38cc85274..d47790a9f 100644 --- a/app/assets/javascripts/ui_models/application.ts +++ b/app/assets/javascripts/ui_models/application.ts @@ -204,10 +204,17 @@ export class WebApplication extends SNApplication { } async openModalComponent(component: SNComponent): Promise { - if (component.package_info?.identifier === "org.standardnotes.batch-manager") { - if (!await this.authorizeBatchManagerAccess()) { - return; - } + switch (component.package_info?.identifier) { + case 'org.standardnotes.batch-manager': + if (!await this.authorizeBatchManagerAccess()) { + return; + } + break; + case 'org.standardnotes.cloudlink': + if (!await this.authorizeCloudLinkAccess()) { + return; + } + break; } const scope = this.scope!.$new(true) as Partial; scope.componentUuid = component.uuid; diff --git a/package.json b/package.json index 6a94b0981..e453f4715 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@reach/alert-dialog": "^0.13.0", "@reach/dialog": "^0.13.0", "@standardnotes/sncrypto-web": "^1.2.10", - "@standardnotes/snjs": "^2.0.67", + "@standardnotes/snjs": "^2.0.69", "mobx": "^6.1.6", "preact": "^10.5.12" } diff --git a/yarn.lock b/yarn.lock index e12a45984..415e03bb0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1850,10 +1850,10 @@ "@standardnotes/sncrypto-common" "^1.2.7" libsodium-wrappers "^0.7.8" -"@standardnotes/snjs@^2.0.67": - version "2.0.67" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.0.67.tgz#87e29f40bb5efaa36f30ddc5905164f7dce194d9" - integrity sha512-XCDxlFQCh0zmV3Hc9mjU7ritZ/2Ma5JPoCbDy4CIAlkKdmVL4tu/4jCfRFILM0zpKF/kLsCTbLGdG7TgU/ReKg== +"@standardnotes/snjs@^2.0.69": + version "2.0.69" + resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.0.69.tgz#8bb5184547673442555bd07a33b998b85117885c" + integrity sha512-S+7ozn+Xi2BAKZE1yM0wWHPLXOR4wAqUomZRU0jP1SK8XJwb2XMUKhM84wSK2AOfFDTvONzeqC5/lAK9ZXT+Sw== dependencies: "@standardnotes/auth" "^2.0.0" "@standardnotes/sncrypto-common" "^1.2.9" From 5bd0db302c6dc95c45467deff1ab338bcae260c6 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Thu, 11 Mar 2021 15:53:11 +0100 Subject: [PATCH 03/18] fix: remove scrollbars on paragraphs --- app/assets/stylesheets/_main.scss | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/stylesheets/_main.scss b/app/assets/stylesheets/_main.scss index 7503712c6..348a6d75a 100644 --- a/app/assets/stylesheets/_main.scss +++ b/app/assets/stylesheets/_main.scss @@ -93,7 +93,6 @@ a { } p { - overflow: auto; color: var(--sn-stylekit-paragraph-text-color); margin: 0; } From cd7b5cc455942d1a74be38211524d3ca064f7a7a Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Thu, 11 Mar 2021 15:53:26 +0100 Subject: [PATCH 04/18] fix: prevent cutting off lines on windows --- app/assets/stylesheets/_main.scss | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/stylesheets/_main.scss b/app/assets/stylesheets/_main.scss index 348a6d75a..06c659c4e 100644 --- a/app/assets/stylesheets/_main.scss +++ b/app/assets/stylesheets/_main.scss @@ -63,7 +63,7 @@ h3 { input, button, select, textarea { font-family: inherit; font-size: inherit; - line-height: inherit; + line-height: normal; } a { From cc474da0c3bae7c07c45e6b12ec343866b084c6d Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Mon, 22 Mar 2021 16:51:49 +0100 Subject: [PATCH 05/18] feat: warning for protected note without protection - Use `.sn-button` everywhere - Delete permissions modal - Capitalize "Clear session data" --- app/assets/javascripts/app.ts | 6 +- .../components/NoAccountWarning.tsx | 11 +- .../components/NoProtectionsNoteWarning.tsx | 37 ++ .../javascripts/components/SessionsModal.tsx | 10 +- app/assets/javascripts/components/utils.ts | 14 +- .../javascripts/directives/views/index.ts | 1 - .../directives/views/permissionsModal.ts | 47 -- app/assets/javascripts/index.ts | 1 - .../account_switcher/account-switcher.pug | 5 +- .../views/application/application-view.pug | 2 +- .../views/challenge_modal/challenge_modal.tsx | 10 +- .../javascripts/views/editor/editor-view.pug | 536 +++++++++--------- .../javascripts/views/editor/editor_view.ts | 19 +- .../views/editor_group/editor-group-view.pug | 8 +- app/assets/stylesheets/_sn.scss | 16 - app/assets/stylesheets/_ui.scss | 14 +- app/assets/stylesheets/index.css.scss | 1 - .../templates/directives/account-menu.pug | 57 +- .../templates/directives/component-view.pug | 22 +- app/assets/templates/directives/menu-row.pug | 5 +- .../templates/directives/password-wizard.pug | 5 +- .../directives/permissions-modal.pug | 25 - .../directives/sync-resolution-menu.pug | 33 +- package.json | 2 +- yarn.lock | 7 +- 25 files changed, 418 insertions(+), 476 deletions(-) create mode 100644 app/assets/javascripts/components/NoProtectionsNoteWarning.tsx delete mode 100644 app/assets/javascripts/directives/views/permissionsModal.ts delete mode 100644 app/assets/stylesheets/_sn.scss delete mode 100644 app/assets/templates/directives/permissions-modal.pug diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts index 8f1aab4d7..396efb323 100644 --- a/app/assets/javascripts/app.ts +++ b/app/assets/javascripts/app.ts @@ -43,7 +43,6 @@ import { MenuRow, PanelResizer, PasswordWizard, - PermissionsModal, RevisionPreviewModal, HistoryMenu, SyncResolutionMenu, @@ -57,6 +56,7 @@ import { StartApplication } from './startApplication'; import { Bridge } from './services/bridge'; import { SessionsModalDirective } from './components/SessionsModal'; import { NoAccountWarningDirective } from './components/NoAccountWarning'; +import { NoProtectionsdNoteWarningDirective } from './components/NoProtectionsNoteWarning'; function reloadHiddenFirefoxTab(): boolean { @@ -138,12 +138,12 @@ const startApplication: StartApplication = async function startApplication( .directive('menuRow', () => new MenuRow()) .directive('panelResizer', () => new PanelResizer()) .directive('passwordWizard', () => new PasswordWizard()) - .directive('permissionsModal', () => new PermissionsModal()) .directive('revisionPreviewModal', () => new RevisionPreviewModal()) .directive('historyMenu', () => new HistoryMenu()) .directive('syncResolutionMenu', () => new SyncResolutionMenu()) .directive('sessionsModal', SessionsModalDirective) - .directive('noAccountWarning', NoAccountWarningDirective); + .directive('noAccountWarning', NoAccountWarningDirective) + .directive('protectedNotePanel', NoProtectionsdNoteWarningDirective); // Filters angular.module('app').filter('trusted', ['$sce', trusted]); diff --git a/app/assets/javascripts/components/NoAccountWarning.tsx b/app/assets/javascripts/components/NoAccountWarning.tsx index 83b7dc9c4..f9f8ea719 100644 --- a/app/assets/javascripts/components/NoAccountWarning.tsx +++ b/app/assets/javascripts/components/NoAccountWarning.tsx @@ -2,7 +2,9 @@ import { toDirective, useAutorunValue } from './utils'; import Close from '../../icons/ic_close.svg'; import { AppState } from '@/ui_models/app_state'; -function NoAccountWarning({ appState }: { appState: AppState }) { +type Props = { appState: AppState }; + +function NoAccountWarning({ appState }: Props) { const canShow = useAutorunValue(() => appState.noAccountWarning.show); if (!canShow) { return null; @@ -14,7 +16,7 @@ function NoAccountWarning({ appState }: { appState: AppState }) { Sign in or register to back up your notes.

); } -export const NoAccountWarningDirective = toDirective(NoAccountWarning); +export const NoAccountWarningDirective = toDirective(NoAccountWarning); diff --git a/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx b/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx new file mode 100644 index 000000000..ab84eaff2 --- /dev/null +++ b/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx @@ -0,0 +1,37 @@ +import { AppState } from '@/ui_models/app_state'; +import { toDirective } from './utils'; + +type Props = { appState: AppState; onViewNote: () => void }; + +function NoProtectionsNoteWarning({ appState, onViewNote }: Props) { + console.log("🚀 ~ file: NoProtectionsNoteWarning.tsx ~ line 7 ~ NoProtectionsNoteWarning ~ onViewNote", onViewNote) + return ( +
+

This note is protected

+

+ Add a passcode or create an account to require authentication to view + this note. +

+
+ + +
+
+ ); +} + +export const NoProtectionsdNoteWarningDirective = toDirective( + NoProtectionsNoteWarning, + { + onViewNote: '&', + } +); diff --git a/app/assets/javascripts/components/SessionsModal.tsx b/app/assets/javascripts/components/SessionsModal.tsx index 67c534a9e..e00b07a26 100644 --- a/app/assets/javascripts/components/SessionsModal.tsx +++ b/app/assets/javascripts/components/SessionsModal.tsx @@ -171,7 +171,7 @@ const SessionsModal: FunctionComponent<{ {formatter.format(session.updated_at)}

- diff --git a/app/assets/javascripts/components/utils.ts b/app/assets/javascripts/components/utils.ts index 96fa8a4f8..f1918328f 100644 --- a/app/assets/javascripts/components/utils.ts +++ b/app/assets/javascripts/components/utils.ts @@ -20,11 +20,9 @@ export function useAutorun( useEffect(() => autorun(view, opts), [view, opts]); } -export function toDirective( - component: FunctionComponent<{ - application: WebApplication; - appState: AppState; - }> +export function toDirective( + component: FunctionComponent, + scope: Record = {} ) { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types return function () { @@ -37,10 +35,7 @@ export function toDirective( return { $onChanges() { render( - h(component, { - application: $scope.application, - appState: $scope.appState, - }), + h(component, $scope), $element[0] ); }, @@ -50,6 +45,7 @@ export function toDirective( scope: { application: '=', appState: '=', + ...scope, }, }; }; diff --git a/app/assets/javascripts/directives/views/index.ts b/app/assets/javascripts/directives/views/index.ts index 99931e2bb..386e123d1 100644 --- a/app/assets/javascripts/directives/views/index.ts +++ b/app/assets/javascripts/directives/views/index.ts @@ -7,7 +7,6 @@ export { InputModal } from './inputModal'; export { MenuRow } from './menuRow'; export { PanelResizer } from './panelResizer'; export { PasswordWizard } from './passwordWizard'; -export { PermissionsModal } from './permissionsModal'; export { RevisionPreviewModal } from './revisionPreviewModal'; export { HistoryMenu } from './historyMenu'; export { SyncResolutionMenu } from './syncResolutionMenu'; diff --git a/app/assets/javascripts/directives/views/permissionsModal.ts b/app/assets/javascripts/directives/views/permissionsModal.ts deleted file mode 100644 index b547fec05..000000000 --- a/app/assets/javascripts/directives/views/permissionsModal.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { WebDirective } from './../../types'; -import template from '%/directives/permissions-modal.pug'; - -class PermissionsModalCtrl { - - $element: JQLite - callback!: (success: boolean) => void - - /* @ngInject */ - constructor($element: JQLite) { - this.$element = $element; - } - - dismiss() { - const elem = this.$element; - const scope = elem.scope(); - scope.$destroy(); - elem.remove(); - } - - accept() { - this.callback(true); - this.dismiss(); - } - - deny() { - this.callback(false); - this.dismiss(); - } -} - -export class PermissionsModal extends WebDirective { - constructor() { - super(); - this.restrict = 'E'; - this.template = template; - this.controller = PermissionsModalCtrl; - this.controllerAs = 'ctrl'; - this.bindToController = true; - this.scope = { - show: '=', - component: '=', - permissionsString: '=', - callback: '=' - }; - } -} diff --git a/app/assets/javascripts/index.ts b/app/assets/javascripts/index.ts index d623c79f5..592300a31 100644 --- a/app/assets/javascripts/index.ts +++ b/app/assets/javascripts/index.ts @@ -4,7 +4,6 @@ import '@reach/dialog/styles.css'; import 'sn-stylekit/dist/stylekit.css'; import '../stylesheets/index.css.scss'; -// import '../stylesheets/_reach-sub.scss'; // Vendor import 'angular'; diff --git a/app/assets/javascripts/views/account_switcher/account-switcher.pug b/app/assets/javascripts/views/account_switcher/account-switcher.pug index 8596611a7..b65e05fa9 100644 --- a/app/assets/javascripts/views/account_switcher/account-switcher.pug +++ b/app/assets/javascripts/views/account_switcher/account-switcher.pug @@ -26,7 +26,6 @@ .sk-sublabel(ng-if='descriptor.identifier == ctrl.activeApplication.identifier') | Current Application .sk-menu-panel-column(ng-if='descriptor.identifier == ctrl.activeApplication.identifier') - .sk-button.success( + button.sn-button.success( ng-click='ctrl.renameDescriptor($event, descriptor)' - ) - .sk-label Rename \ No newline at end of file + ) Rename diff --git a/app/assets/javascripts/views/application/application-view.pug b/app/assets/javascripts/views/application/application-view.pug index b428a9fab..34d47c37e 100644 --- a/app/assets/javascripts/views/application/application-view.pug +++ b/app/assets/javascripts/views/application/application-view.pug @@ -1,4 +1,4 @@ -.main-ui-view( +.main-ui-view.sn-component( ng-class='self.platformString' ) #app.app( diff --git a/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx b/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx index a1f486b7c..d5564f59d 100644 --- a/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx +++ b/app/assets/javascripts/views/challenge_modal/challenge_modal.tsx @@ -279,18 +279,16 @@ function ChallengeModalView({ ctrl }: { ctrl: ChallengeModalCtrl }) {
-
ctrl.submit()} > -
- {ctrl.state.processing ? 'Generating Keys…' : 'Submit'} -
-
+ {ctrl.state.processing ? 'Generating Keys…' : 'Submit'} + {ctrl.challenge.cancelable && ( <>
diff --git a/app/assets/javascripts/views/editor/editor-view.pug b/app/assets/javascripts/views/editor/editor-view.pug index 4784a9151..fd59d0ba9 100644 --- a/app/assets/javascripts/views/editor/editor-view.pug +++ b/app/assets/javascripts/views/editor/editor-view.pug @@ -1,267 +1,275 @@ #editor-column.section.editor.sn-component(aria-label='Note') - .sn-component - .sk-app-bar.no-edges( - ng-if='self.noteLocked', - ng-init="self.lockText = 'Note Locked'", - ng-mouseleave="self.lockText = 'Note Locked'", - ng-mouseover="self.lockText = 'Unlock'" - ) - .left - .sk-app-bar-item(ng-click='self.toggleLockNote()') - .sk-label.warning - i.icon.ion-locked - | {{self.lockText}} - #editor-title-bar.section-title-bar( - ng-class="{'locked' : self.noteLocked}", - ng-show='self.note && !self.note.errorDecrypting' - ) - .title - input#note-title-editor.input( - ng-blur='self.onTitleBlur()', - ng-change='self.onTitleChange()', - ng-disabled='self.noteLocked', - ng-focus='self.onTitleFocus()', - ng-keyup='$event.keyCode == 13 && self.onTitleEnter($event)', - ng-model='self.editorValues.title', - select-on-focus='true', - spellcheck='false' - ) - #save-status - .message( - ng-class="{'warning sk-bold': self.state.syncTakingTooLong, 'danger sk-bold': self.state.saveError}" - ) {{self.state.noteStatus.message}} - .desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}} - .editor-tags - #note-tags-component-container(ng-if='self.state.tagsComponent && !self.note.errorDecrypting') - component-view.component-view( - component-uuid='self.state.tagsComponent.uuid', - ng-class="{'locked' : self.noteLocked}", - ng-style="self.noteLocked && {'pointer-events' : 'none'}", - application='self.application' - ) - input.tags-input( - ng-blur='self.onTagsInputBlur()', - ng-disabled='self.noteLocked', - ng-if='!self.state.tagsComponent', - ng-keyup='$event.keyCode == 13 && $event.target.blur();', - ng-model='self.editorValues.tagsInputValue', - placeholder='#tags', - spellcheck='false', - type='text' - ) - .sn-component(ng-if='self.note') - #editor-menu-bar.sk-app-bar.no-edges - .left - .sk-app-bar-item( - click-outside=`self.setMenuState('showOptionsMenu', false)`, - is-open='self.state.showOptionsMenu', - ng-class="{'selected' : self.state.showOptionsMenu}", - ng-click="self.toggleMenu('showOptionsMenu')" - ) - .sk-label Options - .sk-menu-panel.dropdown-menu(ng-if='self.state.showOptionsMenu') - .sk-menu-panel-section - .sk-menu-panel-header - .sk-menu-panel-header-title Note Options - menu-row( - action='self.selectedMenuItem(true); self.togglePin()' - desc="'Pin or unpin a note from the top of your list'", - label="self.note.pinned ? 'Unpin' : 'Pin'" - ) - menu-row( - action='self.selectedMenuItem(true); self.toggleArchiveNote()' - desc="'Archive or unarchive a note from your Archived system tag'", - label="self.note.archived ? 'Unarchive' : 'Archive'" - ) - menu-row( - action='self.selectedMenuItem(true); self.toggleLockNote()' - desc="'Locking notes prevents unintentional editing'", - label="self.noteLocked ? 'Unlock' : 'Lock'" - ) - menu-row( - action='self.selectedMenuItem(true); self.toggleProtectNote()' - desc=`'Protecting a note will require credentials to view it'`, - label="self.note.protected ? 'Unprotect' : 'Protect'" - ) - menu-row( - action='self.selectedMenuItem(true); self.toggleNotePreview()' - circle="self.note.hidePreview ? 'danger' : 'success'", - circle-align="'right'", - desc="'Hide or unhide the note preview from the list of notes'", - label="'Preview'" - ) - menu-row( - action='self.selectedMenuItem(); self.deleteNote()' - desc="'Send this note to the trash'", - label="'Move to Trash'", - ng-show='!self.state.altKeyDown && !self.note.trashed && !self.note.errorDecrypting', - stylekit-class="'warning'" - ) - menu-row( - action='self.selectedMenuItem(); self.deleteNotePermanantely()' - desc="'Delete this note permanently from all your devices'", - label="'Delete Permanently'", - ng-show='!self.note.trashed && self.note.errorDecrypting', - stylekit-class="'danger'" - ) - div(ng-if='self.note.trashed || self.state.altKeyDown') - menu-row( - action='self.selectedMenuItem(true); self.restoreTrashedNote()' - desc="'Undelete this note and restore it back into your notes'", - label="'Restore'", - ng-show='self.note.trashed', - stylekit-class="'info'" - ) - menu-row( - action='self.selectedMenuItem(true); self.deleteNotePermanantely()' - desc="'Delete this note permanently from all your devices'", - label="'Delete Permanently'", - stylekit-class="'danger'" - ) - menu-row( - action='self.selectedMenuItem(true); self.emptyTrash()' - desc="'Permanently delete all notes in the trash'", - label="'Empty Trash'", - ng-show='self.note.trashed || !self.state.altKeyDown', - stylekit-class="'danger'", - subtitle="self.getTrashCount() + ' notes in trash'" - ) - .sk-menu-panel-section - .sk-menu-panel-header - .sk-menu-panel-header-title Global Display - menu-row( - action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMonospace)" - circle="self.state.monospaceFont ? 'success' : 'neutral'", - desc="'Toggles the font style for the default editor'", - disabled='self.state.editorComponent', - label="'Monospace Font'", - subtitle="self.state.editorComponent ? 'Not available with editor extensions' : null" - ) - menu-row( - action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeySpellcheck)" - circle="self.state.spellcheck ? 'success' : 'neutral'", - desc="'Toggles spellcheck for the default editor'", - disabled='self.state.editorComponent', - label="'Spellcheck'", - subtitle=` - self.state.editorComponent - ? 'Not available with editor extensions' - : (self.state.isDesktop ? 'May degrade editor performance' : null) - `) - menu-row( - action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMarginResizers)" - circle="self.state.marginResizersEnabled ? 'success' : 'neutral'", - desc="'Allows for editor left and right margins to be resized'", - faded='!self.state.marginResizersEnabled', - label="'Margin Resizers'" - ) - .sk-app-bar-item( - click-outside=`self.setMenuState('showEditorMenu', false)` - is-open='self.state.showEditorMenu', - ng-class="{'selected' : self.state.showEditorMenu}", - ng-click="self.toggleMenu('showEditorMenu')" - ) - .sk-label Editor - editor-menu( - callback='self.editorMenuOnSelect', - current-item='self.note', - ng-if='self.state.showEditorMenu', - selected-editor-uuid='self.state.editorComponent && self.state.editorComponent.uuid', - application='self.application' - ) - .sk-app-bar-item( - click-outside=`self.setMenuState('showActionsMenu', false)`, - is-open='self.state.showActionsMenu', - ng-class="{'selected' : self.state.showActionsMenu}", - ng-click="self.toggleMenu('showActionsMenu')" - ) - .sk-label Actions - actions-menu( - item='self.note', - ng-if='self.state.showActionsMenu', - application='self.application' - ) - .sk-app-bar-item( - click-outside=`self.setMenuState('showHistoryMenu', false)`, - is-open='self.state.showHistoryMenu', - ng-class="{'selected' : self.state.showHistoryMenu}", - ng-click="self.toggleMenu('showHistoryMenu')" - ) - .sk-label History - history-menu( - item='self.note', - ng-if='self.state.showHistoryMenu', - application='self.application' - ) - #editor-content.editor-content(ng-if='!self.note.errorDecrypting') - panel-resizer.left( - control='self.leftPanelPuppet', - hoverable='true', - min-width='300', - ng-if='self.state.marginResizersEnabled', - on-resize-finish='self.onPanelResizeFinish', - panel-id="'editor-content'", - property="'left'" - ) - component-view.component-view( - component-uuid='self.state.editorComponent.uuid', - ng-if='self.state.editorComponent && !self.state.editorUnloading', - on-load='self.onEditorLoad', - application='self.application' - ) - textarea#note-text-editor.editable.font-editor( - dir='auto', - ng-attr-spellcheck='{{self.state.spellcheck}}', - ng-change='self.contentChanged()', - ng-click='self.clickedTextArea()', - ng-focus='self.onContentFocus()', - ng-if='!self.state.editorComponent && !self.state.textareaUnloading', - ng-model='self.editorValues.text', - ng-model-options='{ debounce: self.state.editorDebounce}', - ng-readonly='self.noteLocked', - ng-trim='false' - autocomplete='off' - ) - | {{self.onSystemEditorLoad()}} - panel-resizer( - control='self.rightPanelPuppet', - hoverable='true', min-width='300', - ng-if='self.state.marginResizersEnabled', - on-resize-finish='self.onPanelResizeFinish', - panel-id="'editor-content'", - property="'right'" - ) - .section(ng-show='self.note.errorDecrypting') - .sn-component#error-decrypting-container - .sk-panel#error-decrypting-panel - .sk-panel-header - .sk-panel-header-title {{self.note.waitingForKey ? 'Waiting for Key' : 'Unable to Decrypt'}} - .sk-panel-content - .sk-panel-section - p.sk-p(ng-if='self.note.waitingForKey') - | This note is awaiting its encryption key to be ready. Please wait for syncing to complete - | for this note to be decrypted. - p.sk-p(ng-if='!self.note.waitingForKey') - | There was an error decrypting this item. Ensure you are running the - | latest version of this app, then sign out and sign back in to try again. - #editor-pane-component-stack(ng-if='!self.note.errorDecrypting' ng-show='self.note') - #component-stack-menu-bar.sk-app-bar.no-edges(ng-if='self.state.stackComponents.length') - .left - .sk-app-bar-item( - ng-repeat='component in self.state.stackComponents track by component.uuid' - ng-click='self.toggleStackComponentForCurrentItem(component)', - ) - .sk-app-bar-item-column - .sk-circle.small( - ng-class="{'info' : !self.stackComponentHidden(component) && component.active, 'neutral' : self.stackComponentHidden(component) || !component.active}" - ) - .sk-app-bar-item-column - .sk-label {{component.name}} + protected-note-panel.h-full.flex.justify-center.items-center( + ng-if='self.note.protected && !self.state.showEditor' + app-state='self.appState' + on-view-note='self.dismissProtectedWarning()' + ) + div( + ng-if='self.state.showEditor' + ) .sn-component - component-view.component-view.component-stack-item( - ng-repeat='component in self.state.stackComponents track by component.uuid', - component-uuid='component.uuid', - manual-dealloc='true', - ng-show='!self.stackComponentHidden(component)', - application='self.application' + .sk-app-bar.no-edges( + ng-if='self.noteLocked', + ng-init="self.lockText = 'Note Locked'", + ng-mouseleave="self.lockText = 'Note Locked'", + ng-mouseover="self.lockText = 'Unlock'" + ) + .left + .sk-app-bar-item(ng-click='self.toggleLockNote()') + .sk-label.warning + i.icon.ion-locked + | {{self.lockText}} + #editor-title-bar.section-title-bar( + ng-class="{'locked' : self.noteLocked}", + ng-show='self.note && !self.note.errorDecrypting' ) + .title + input#note-title-editor.input( + ng-blur='self.onTitleBlur()', + ng-change='self.onTitleChange()', + ng-disabled='self.noteLocked', + ng-focus='self.onTitleFocus()', + ng-keyup='$event.keyCode == 13 && self.onTitleEnter($event)', + ng-model='self.editorValues.title', + select-on-focus='true', + spellcheck='false' + ) + #save-status + .message( + ng-class="{'warning sk-bold': self.state.syncTakingTooLong, 'danger sk-bold': self.state.saveError}" + ) {{self.state.noteStatus.message}} + .desc(ng-show='self.state.noteStatus.desc') {{self.state.noteStatus.desc}} + .editor-tags + #note-tags-component-container(ng-if='self.state.tagsComponent && !self.note.errorDecrypting') + component-view.component-view( + component-uuid='self.state.tagsComponent.uuid', + ng-class="{'locked' : self.noteLocked}", + ng-style="self.noteLocked && {'pointer-events' : 'none'}", + application='self.application' + ) + input.tags-input( + ng-blur='self.onTagsInputBlur()', + ng-disabled='self.noteLocked', + ng-if='!self.state.tagsComponent', + ng-keyup='$event.keyCode == 13 && $event.target.blur();', + ng-model='self.editorValues.tagsInputValue', + placeholder='#tags', + spellcheck='false', + type='text' + ) + .sn-component(ng-if='self.note') + #editor-menu-bar.sk-app-bar.no-edges + .left + .sk-app-bar-item( + click-outside=`self.setMenuState('showOptionsMenu', false)`, + is-open='self.state.showOptionsMenu', + ng-class="{'selected' : self.state.showOptionsMenu}", + ng-click="self.toggleMenu('showOptionsMenu')" + ) + .sk-label Options + .sk-menu-panel.dropdown-menu(ng-if='self.state.showOptionsMenu') + .sk-menu-panel-section + .sk-menu-panel-header + .sk-menu-panel-header-title Note Options + menu-row( + action='self.selectedMenuItem(true); self.togglePin()' + desc="'Pin or unpin a note from the top of your list'", + label="self.note.pinned ? 'Unpin' : 'Pin'" + ) + menu-row( + action='self.selectedMenuItem(true); self.toggleArchiveNote()' + desc="'Archive or unarchive a note from your Archived system tag'", + label="self.note.archived ? 'Unarchive' : 'Archive'" + ) + menu-row( + action='self.selectedMenuItem(true); self.toggleLockNote()' + desc="'Locking notes prevents unintentional editing'", + label="self.noteLocked ? 'Unlock' : 'Lock'" + ) + menu-row( + action='self.selectedMenuItem(true); self.toggleProtectNote()' + desc=`'Protecting a note will require credentials to view it'`, + label="self.note.protected ? 'Unprotect' : 'Protect'" + ) + menu-row( + action='self.selectedMenuItem(true); self.toggleNotePreview()' + circle="self.note.hidePreview ? 'danger' : 'success'", + circle-align="'right'", + desc="'Hide or unhide the note preview from the list of notes'", + label="'Preview'" + ) + menu-row( + action='self.selectedMenuItem(); self.deleteNote()' + desc="'Send this note to the trash'", + label="'Move to Trash'", + ng-show='!self.state.altKeyDown && !self.note.trashed && !self.note.errorDecrypting', + stylekit-class="'warning'" + ) + menu-row( + action='self.selectedMenuItem(); self.deleteNotePermanantely()' + desc="'Delete this note permanently from all your devices'", + label="'Delete Permanently'", + ng-show='!self.note.trashed && self.note.errorDecrypting', + stylekit-class="'danger'" + ) + div(ng-if='self.note.trashed || self.state.altKeyDown') + menu-row( + action='self.selectedMenuItem(true); self.restoreTrashedNote()' + desc="'Undelete this note and restore it back into your notes'", + label="'Restore'", + ng-show='self.note.trashed', + stylekit-class="'info'" + ) + menu-row( + action='self.selectedMenuItem(true); self.deleteNotePermanantely()' + desc="'Delete this note permanently from all your devices'", + label="'Delete Permanently'", + stylekit-class="'danger'" + ) + menu-row( + action='self.selectedMenuItem(true); self.emptyTrash()' + desc="'Permanently delete all notes in the trash'", + label="'Empty Trash'", + ng-show='self.note.trashed || !self.state.altKeyDown', + stylekit-class="'danger'", + subtitle="self.getTrashCount() + ' notes in trash'" + ) + .sk-menu-panel-section + .sk-menu-panel-header + .sk-menu-panel-header-title Global Display + menu-row( + action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMonospace)" + circle="self.state.monospaceFont ? 'success' : 'neutral'", + desc="'Toggles the font style for the default editor'", + disabled='self.state.editorComponent', + label="'Monospace Font'", + subtitle="self.state.editorComponent ? 'Not available with editor extensions' : null" + ) + menu-row( + action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeySpellcheck)" + circle="self.state.spellcheck ? 'success' : 'neutral'", + desc="'Toggles spellcheck for the default editor'", + disabled='self.state.editorComponent', + label="'Spellcheck'", + subtitle=` + self.state.editorComponent + ? 'Not available with editor extensions' + : (self.state.isDesktop ? 'May degrade editor performance' : null) + `) + menu-row( + action="self.selectedMenuItem(true); self.toggleWebPrefKey(self.prefKeyMarginResizers)" + circle="self.state.marginResizersEnabled ? 'success' : 'neutral'", + desc="'Allows for editor left and right margins to be resized'", + faded='!self.state.marginResizersEnabled', + label="'Margin Resizers'" + ) + .sk-app-bar-item( + click-outside=`self.setMenuState('showEditorMenu', false)` + is-open='self.state.showEditorMenu', + ng-class="{'selected' : self.state.showEditorMenu}", + ng-click="self.toggleMenu('showEditorMenu')" + ) + .sk-label Editor + editor-menu( + callback='self.editorMenuOnSelect', + current-item='self.note', + ng-if='self.state.showEditorMenu', + selected-editor-uuid='self.state.editorComponent && self.state.editorComponent.uuid', + application='self.application' + ) + .sk-app-bar-item( + click-outside=`self.setMenuState('showActionsMenu', false)`, + is-open='self.state.showActionsMenu', + ng-class="{'selected' : self.state.showActionsMenu}", + ng-click="self.toggleMenu('showActionsMenu')" + ) + .sk-label Actions + actions-menu( + item='self.note', + ng-if='self.state.showActionsMenu', + application='self.application' + ) + .sk-app-bar-item( + click-outside=`self.setMenuState('showHistoryMenu', false)`, + is-open='self.state.showHistoryMenu', + ng-class="{'selected' : self.state.showHistoryMenu}", + ng-click="self.toggleMenu('showHistoryMenu')" + ) + .sk-label History + history-menu( + item='self.note', + ng-if='self.state.showHistoryMenu', + application='self.application' + ) + #editor-content.editor-content(ng-if='!self.note.errorDecrypting') + panel-resizer.left( + control='self.leftPanelPuppet', + hoverable='true', + min-width='300', + ng-if='self.state.marginResizersEnabled', + on-resize-finish='self.onPanelResizeFinish', + panel-id="'editor-content'", + property="'left'" + ) + component-view.component-view( + component-uuid='self.state.editorComponent.uuid', + ng-if='self.state.editorComponent && !self.state.editorUnloading', + on-load='self.onEditorLoad', + application='self.application' + ) + textarea#note-text-editor.editable.font-editor( + dir='auto', + ng-attr-spellcheck='{{self.state.spellcheck}}', + ng-change='self.contentChanged()', + ng-click='self.clickedTextArea()', + ng-focus='self.onContentFocus()', + ng-if='!self.state.editorComponent && !self.state.textareaUnloading', + ng-model='self.editorValues.text', + ng-model-options='{ debounce: self.state.editorDebounce}', + ng-readonly='self.noteLocked', + ng-trim='false' + autocomplete='off' + ) + | {{self.onSystemEditorLoad()}} + panel-resizer( + control='self.rightPanelPuppet', + hoverable='true', min-width='300', + ng-if='self.state.marginResizersEnabled', + on-resize-finish='self.onPanelResizeFinish', + panel-id="'editor-content'", + property="'right'" + ) + .section(ng-show='self.note.errorDecrypting') + .sn-component#error-decrypting-container + .sk-panel#error-decrypting-panel + .sk-panel-header + .sk-panel-header-title {{self.note.waitingForKey ? 'Waiting for Key' : 'Unable to Decrypt'}} + .sk-panel-content + .sk-panel-section + p.sk-p(ng-if='self.note.waitingForKey') + | This note is awaiting its encryption key to be ready. Please wait for syncing to complete + | for this note to be decrypted. + p.sk-p(ng-if='!self.note.waitingForKey') + | There was an error decrypting this item. Ensure you are running the + | latest version of this app, then sign out and sign back in to try again. + #editor-pane-component-stack(ng-if='!self.note.errorDecrypting' ng-show='self.note') + #component-stack-menu-bar.sk-app-bar.no-edges(ng-if='self.state.stackComponents.length') + .left + .sk-app-bar-item( + ng-repeat='component in self.state.stackComponents track by component.uuid' + ng-click='self.toggleStackComponentForCurrentItem(component)', + ) + .sk-app-bar-item-column + .sk-circle.small( + ng-class="{'info' : !self.stackComponentHidden(component) && component.active, 'neutral' : self.stackComponentHidden(component) || !component.active}" + ) + .sk-app-bar-item-column + .sk-label {{component.name}} + .sn-component + component-view.component-view.component-stack-item( + ng-repeat='component in self.state.stackComponents track by component.uuid', + component-uuid='component.uuid', + manual-dealloc='true', + ng-show='!self.stackComponentHidden(component)', + application='self.application' + ) diff --git a/app/assets/javascripts/views/editor/editor_view.ts b/app/assets/javascripts/views/editor/editor_view.ts index 5f36183d7..ee841f627 100644 --- a/app/assets/javascripts/views/editor/editor_view.ts +++ b/app/assets/javascripts/views/editor/editor_view.ts @@ -80,6 +80,7 @@ type EditorState = { textareaUnloading: boolean /** Fields that can be directly mutated by the template */ mutable: any + showEditor: boolean } type EditorValues = { @@ -223,7 +224,8 @@ class EditorViewCtrl extends PureViewCtrl { textareaUnloading: false, mutable: { tagsString: '' - } + }, + showEditor: false, } as EditorState; } @@ -272,15 +274,17 @@ class EditorViewCtrl extends PureViewCtrl { async handleEditorNoteChange() { this.cancelPendingSetStatus(); + const note = this.editor.note; + const showEditor = !note.protected; await this.setState({ showActionsMenu: false, showOptionsMenu: false, showEditorMenu: false, showHistoryMenu: false, altKeyDown: false, - noteStatus: undefined + noteStatus: undefined, + showEditor, }); - const note = this.editor.note; this.editorValues.title = note.title; this.editorValues.text = note.text; this.reloadEditor(); @@ -288,11 +292,18 @@ class EditorViewCtrl extends PureViewCtrl { this.reloadPreferences(); this.reloadStackComponents(); this.reloadNoteTagsComponent(); - if (note.safeText().length === 0) { + if (note.safeText().length === 0 && showEditor) { this.focusTitle(); } } + async dismissProtectedWarning() { + await this.setState({ + showEditor: true + }); + this.focusTitle(); + } + /** * Because note.locked accesses note.content.appData, * we do not want to expose the template to direct access to note.locked, diff --git a/app/assets/javascripts/views/editor_group/editor-group-view.pug b/app/assets/javascripts/views/editor_group/editor-group-view.pug index 22f7e72ec..96a0517e0 100644 --- a/app/assets/javascripts/views/editor_group/editor-group-view.pug +++ b/app/assets/javascripts/views/editor_group/editor-group-view.pug @@ -1,5 +1,7 @@ -editor-view( +.flex-grow( ng-repeat='editor in self.editors' - application='self.application' - editor='editor' +) + editor-view( + application='self.application' + editor='editor' ) diff --git a/app/assets/stylesheets/_sn.scss b/app/assets/stylesheets/_sn.scss deleted file mode 100644 index 420dd8b24..000000000 --- a/app/assets/stylesheets/_sn.scss +++ /dev/null @@ -1,16 +0,0 @@ -/* Generic UI controls that have yet to be extracted into Stylekit */ - -.sn-btn { - @extend .border-0; - @extend .bg-main; - @extend .cursor-pointer; - @extend .capitalize; - @extend .font-bold; - @extend .py-2; - @extend .px-3; - @extend .rounded; - @extend .text-info-contrast; - @extend .text-sm; - - @extend .hover\:brightness-130; -} diff --git a/app/assets/stylesheets/_ui.scss b/app/assets/stylesheets/_ui.scss index 2b44ab40f..e4785998d 100644 --- a/app/assets/stylesheets/_ui.scss +++ b/app/assets/stylesheets/_ui.scss @@ -81,14 +81,6 @@ $screen-md-max: ($screen-lg-min - 1) !default; opacity: 0.5; } -.flex { - display: flex; -} - -.flex-column { - flex-direction: column; -} - .self-start { align-self: flex-start; } @@ -226,6 +218,12 @@ $screen-md-max: ($screen-lg-min - 1) !default; .grid-template-cols-1fr { grid-template-columns: 1fr; } +.col-span-all { + grid-column: 1 / -1; +} +.grid-col-2 { + grid-column: 2; +} .relative { position: relative; diff --git a/app/assets/stylesheets/index.css.scss b/app/assets/stylesheets/index.css.scss index 2dc340e5e..52ca8b997 100644 --- a/app/assets/stylesheets/index.css.scss +++ b/app/assets/stylesheets/index.css.scss @@ -11,4 +11,3 @@ @import "ionicons"; @import "reach-sub"; @import "sessions-modal"; -@import "sn"; diff --git a/app/assets/templates/directives/account-menu.pug b/app/assets/templates/directives/account-menu.pug index bde3c0f21..1f797c0ad 100644 --- a/app/assets/templates/directives/account-menu.pug +++ b/app/assets/templates/directives/account-menu.pug @@ -12,12 +12,11 @@ ) .sk-panel-row .sk-h1 Sign in or register to enable sync and end-to-end encryption. - .sk-panel-row - .sk-button-group.stretch - .sk-button.info.featured(ng-click='self.state.formData.showLogin = true') - .sk-label Sign In - .sk-button.info.featured(ng-click='self.showRegister()') - .sk-label Register + .flex.gap-3.my-1 + button.sn-button.info.flex-grow.text-base.py-3(ng-click='self.state.formData.showLogin = true') + | Sign In + button.sn-button.info.flex-grow.text-base.py-3(ng-click='self.showRegister()') + | Register .sk-panel-row.sk-p | Standard Notes is free on every platform, and comes | standard with sync and encryption. @@ -95,12 +94,10 @@ target='_blank' ) (Learn more) .sk-panel-section.form-submit(ng-if='!self.state.formData.authenticating') - .sk-button-group.stretch - .sk-button.info.featured( - ng-click='self.submitAuthForm()', - ng-disabled='self.state.formData.authenticating' - ) - .sk-label {{self.state.formData.showLogin ? "Sign In" : "Register"}} + button.sn-button.info.text-base.py-3.text-center( + ng-click='self.submitAuthForm()', + ng-disabled='self.state.formData.authenticating' + ) {{self.state.formData.showLogin ? "Sign In" : "Register"}} .sk-notification.neutral(ng-if='self.state.formData.showRegister') .sk-notification-title No Password Reset. .sk-notification-text @@ -174,17 +171,16 @@ | or revoking an active session, require additional authentication | like entering your account password or application passcode. .sk-panel-row(ng-if="self.state.protectionsDisabledUntil") - button.sk-button.info(ng-click="self.enableProtections()") - span.sk-label.capitalize Enable protections + button.sn-button.info(ng-click="self.enableProtections()") + | Enable protections .sk-panel-section .sk-panel-section-title Passcode Lock div(ng-if='!self.state.hasPasscode') div(ng-if='self.state.canAddPasscode') .sk-panel-row(ng-if='!self.state.formData.showPasscodeForm') - .sk-button.info( + button.sn-button.info( ng-click='self.addPasscodeClicked(); $event.stopPropagation();' - ) - .sk-label Add Passcode + ) Add Passcode p.sk-p | Add a passcode to lock the application and | encrypt on-device key storage. @@ -211,12 +207,10 @@ placeholder='Confirm Passcode', type='password' ) - .sk-button-group.stretch.sk-panel-row.form-submit - button.sk-button.info(type='submit') - .sk-label Set Passcode - a.neutral.sk-a.sk-panel-row( + button.sn-button.info.mt-2(type='submit') Set Passcode + button.sn-button.outlined.ml-2( ng-click='self.state.formData.showPasscodeForm = false' - ) Cancel + ) Cancel div(ng-if='self.state.hasPasscode && !self.state.formData.showPasscodeForm') .sk-panel-section-subtitle.info Passcode lock is enabled .sk-notification.contrast @@ -245,7 +239,6 @@ .sk-panel-section-title Data Backups .sk-p | Download a backup of all your data. - .sk-panel-row form.sk-panel-form.sk-panel-row(ng-if='self.state.encryptionEnabled') .sk-input-group label.sk-horizontal-group.tight @@ -265,17 +258,17 @@ ) p.sk-p Decrypted .sk-panel-row - .sk-button-group.sk-panel-row.justify-left - .sk-button.info(ng-click='self.downloadDataArchive()') - .sk-label Download Backup - label.sk-button.info + .flex + button.sn-button.info(ng-click='self.downloadDataArchive()') + | Download Backup + label.sn-button.info.ml-2 input( file-change='->', handler='self.importFileSelected(files)', style='display: none;', type='file' - ) - .sk-label Import Backup + ) + | Import Backup span(ng-if='self.isDesktopApplication()') | Backups are automatically created on desktop and can be managed | via the "Backups" top-level menu. @@ -296,8 +289,8 @@ | local storage, and a new identifier will be created should you | decide to enable error reporting again in the future. .sk-panel-row - button(ng-click="self.toggleErrorReportingEnabled()").sk-button.info - span.sk-label {{ self.state.errorReportingEnabled ? 'Disable' : 'Enable'}} Error Reporting + button(ng-click="self.toggleErrorReportingEnabled()").sn-button.info + | {{ self.state.errorReportingEnabled ? 'Disable' : 'Enable'}} Error Reporting .sk-panel-row a(ng-click="self.openErrorReportingDialog()").sk-a What data is being sent? .sk-panel-footer @@ -313,7 +306,7 @@ ng-if='self.state.formData.showLogin || self.state.formData.showRegister' ) | Cancel - a.sk-a.right.danger( + a.sk-a.right.danger.capitalize( ng-click='self.destroyLocalData()', ng-if=` !self.state.formData.showLogin && diff --git a/app/assets/templates/directives/component-view.pug b/app/assets/templates/directives/component-view.pug index f31383027..4ae471f85 100644 --- a/app/assets/templates/directives/component-view.pug +++ b/app/assets/templates/directives/component-view.pug @@ -5,8 +5,7 @@ .sk-label.warning There was an issue loading {{ctrl.component.name}}. .right .sk-app-bar-item(ng-click='ctrl.reloadIframe()') - .sk-button.info - .sk-label Reload + button.sn-button.info Reload .sn-component(ng-if='ctrl.expired') .sk-app-bar.no-edges.no-top-edge.dynamic-height .left @@ -26,16 +25,14 @@ | Extensions are in a read-only state. .right .sk-app-bar-item(ng-click='ctrl.reloadStatus(true)') - .sk-button.info - .sk-label Reload + button.sn-button.info Reload .sk-app-bar-item .sk-app-bar-item-column - .sk-button.warning - a.sk-label( - href='https://standardnotes.org/help/41/expired', - rel='noopener', - target='_blank' - ) Help + a.sn-button.warning( + href='https://standardnotes.org/help/41/expired', + rel='noopener', + target='_blank' + ) Help .sn-component(ng-if="ctrl.error == 'offline-restricted'") .sk-panel.static @@ -57,11 +54,10 @@ li.sk-p strong Use the Desktop application. .sk-panel-row - .sk-button.info( + button.sn-button.info( ng-click='ctrl.reloadStatus()', ng-if='!ctrl.reloading' - ) - .sk-label Reload + ) Reload .sk-spinner.info.small(ng-if='ctrl.reloading') .sn-component(ng-if="ctrl.error == 'url-missing'") .sk-panel.static diff --git a/app/assets/templates/directives/menu-row.pug b/app/assets/templates/directives/menu-row.pug index 25b7a18ea..6714228cd 100644 --- a/app/assets/templates/directives/menu-row.pug +++ b/app/assets/templates/directives/menu-row.pug @@ -30,10 +30,9 @@ .sk-menu-panel-column(ng-if="ctrl.circle && ctrl.circleAlign == 'right'") .sk-circle.small(ng-class='ctrl.circle') .sk-menu-panel-column(ng-if='ctrl.hasButton') - .sk-button( + button.sn-button.small( ng-class='ctrl.buttonClass', ng-click='ctrl.clickAccessoryButton($event)' - ) - .sk-label {{ctrl.buttonText}} + ) {{ctrl.buttonText}} .sk-menu-panel-column(ng-if='ctrl.spinnerClass') .sk-spinner.small(ng-class='ctrl.spinnerClass') diff --git a/app/assets/templates/directives/password-wizard.pug b/app/assets/templates/directives/password-wizard.pug index 2fde1edc6..52a58940f 100644 --- a/app/assets/templates/directives/password-wizard.pug +++ b/app/assets/templates/directives/password-wizard.pug @@ -41,8 +41,7 @@ | Please ensure you are running the latest version of Standard Notes | on all platforms to ensure maximum compatibility. .sk-panel-footer - .sk-button.info( + button.sn-button.info( ng-click='ctrl.nextStep()', ng-disabled='ctrl.state.lockContinue' - ) - .sk-label {{ctrl.state.continueTitle}} + ) {{ctrl.state.continueTitle}} diff --git a/app/assets/templates/directives/permissions-modal.pug b/app/assets/templates/directives/permissions-modal.pug deleted file mode 100644 index d401c97b1..000000000 --- a/app/assets/templates/directives/permissions-modal.pug +++ /dev/null @@ -1,25 +0,0 @@ -.sk-modal-background(ng-click='ctrl.deny()') -#permissions-modal.sk-modal-content - .sn-component - .sk-panel - .sk-panel-header - .sk-panel-header-title Activate Extension - a.sk-a.info.close-button(ng-click='ctrl.deny()') Cancel - .sk-panel-content - .sk-panel-section - .sk-panel-row - .sk-h2 - strong {{ctrl.component.name}} - | would like to interact with your - | {{ctrl.permissionsString}} - .sk-panel-row - p.sk-p - | Extensions use an offline messaging system to communicate. Learn more at - a.sk-a.info( - href='https://standardnotes.org/permissions', - rel='noopener', - target='_blank' - ) https://standardnotes.org/permissions. - .sk-panel-footer - .sk-button.info.big.block.font-bold(ng-click='ctrl.accept()') - .sk-label Continue diff --git a/app/assets/templates/directives/sync-resolution-menu.pug b/app/assets/templates/directives/sync-resolution-menu.pug index 471944349..46b18ca16 100644 --- a/app/assets/templates/directives/sync-resolution-menu.pug +++ b/app/assets/templates/directives/sync-resolution-menu.pug @@ -6,44 +6,41 @@ .sk-panel-content .sk-panel-section .sk-panel-row.sk-p - | We've detected that the data on the server may not match + | We've detected that the data on the server may not match | the data in the current application session. .sk-p.sk-panel-row .sk-panel-column strong.sk-panel-row Option 1 — Restart App: - .sk-p - | Quit the application and re-open it. + .sk-p + | Quit the application and re-open it. | Sometimes, this may resolve the issue. .sk-p.sk-panel-row .sk-panel-column strong.sk-panel-row Option 2 (recommended) — Sign Out: .sk-p - | Sign out of your account, then sign back in. + | Sign out of your account, then sign back in. | This will ensure your data is consistent with the server. | Be sure to download a backup of your data before doing so. .sk-p.sk-panel-row .sk-panel-column strong.sk-panel-row Option 3 — Sync Resolution: .sk-p - | We can attempt to reconcile changes by downloading all data from the - | server. No existing data will be overwritten. If the local contents of + | We can attempt to reconcile changes by downloading all data from the + | server. No existing data will be overwritten. If the local contents of | an item differ from what the server has, a conflicted copy will be created. div(ng-if='!ctrl.status.backupFinished') .sk-p.sk-panel-row - | Please download a backup before we attempt to + | Please download a backup before we attempt to | perform a full account sync resolution. .sk-panel-row - .sk-button-group - .sk-button.info(ng-click='ctrl.downloadBackup(true)') - .sk-label Encrypted - .sk-button.info(ng-click='ctrl.downloadBackup(false)') - .sk-label Decrypted - .sk-button.danger(ng-click='ctrl.skipBackup()') - .sk-label Skip + .flex.gap-2 + button.sn-button.info(ng-click='ctrl.downloadBackup(true)') Encrypted + button.sn-button.info(ng-click='ctrl.downloadBackup(false)') Decrypted + button.sn-button.danger(ng-click='ctrl.skipBackup()') Skip div(ng-if='ctrl.status.backupFinished') .sk-panel-row(ng-if='!ctrl.status.resolving && !ctrl.status.attemptedResolution') - .sk-button.info(ng-click='ctrl.performSyncResolution()') - .sk-label Perform Sync Resolution + button.sn-button.info(ng-click='ctrl.performSyncResolution()') + | Perform Sync Resolution .sk-panel-row.justify-left(ng-if='ctrl.status.resolving') .sk-horizontal-group .sk-spinner.small.info @@ -51,8 +48,8 @@ .sk-panel-column(ng-if='ctrl.status.fail') .sk-panel-row.sk-label.danger Sync Resolution Failed .sk-p.sk-panel-row - | We attempted to reconcile local content and server content, but were - | unable to do so. At this point, we recommend signing out of your account + | We attempted to reconcile local content and server content, but were + | unable to do so. At this point, we recommend signing out of your account | and signing back in. You may wish to download a data backup before doing so. .sk-panel-column(ng-if='ctrl.status.success') .sk-panel-row.sk-label.success Sync Resolution Success diff --git a/package.json b/package.json index e453f4715..daeda2096 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pug-loader": "^2.4.0", "sass-loader": "^8.0.2", "serve-static": "^1.14.1", - "sn-stylekit": "^2.2.1", + "sn-stylekit": "github:standardnotes/StyleKit#e3bfad37d29168bcc15e96399734ffaae1e618ba", "ts-loader": "^8.0.17", "typescript": "^4.1.5", "typescript-eslint": "0.0.1-alpha.0", diff --git a/yarn.lock b/yarn.lock index 415e03bb0..1f4e36486 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7808,10 +7808,9 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -sn-stylekit@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/sn-stylekit/-/sn-stylekit-2.2.1.tgz#4a81a05b2b2d67a11af9d06f3964ac1ece3aa84a" - integrity sha512-mrvUbf2HbWOfxbNglo7RXa5JBe9UV9rurupeGoX/Kh4/lVlB2n/56ZT103xk/4tp0/mVCpxjD7Dt1stKFxsvFA== +"sn-stylekit@github:standardnotes/StyleKit#e3bfad37d29168bcc15e96399734ffaae1e618ba": + version "3.0.0" + resolved "https://codeload.github.com/standardnotes/StyleKit/tar.gz/e3bfad37d29168bcc15e96399734ffaae1e618ba" snapdragon-node@^2.0.1: version "2.1.1" From 4f2d442ac1a8c1461617f7c54ec42c605ffcaa69 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Mon, 22 Mar 2021 17:58:03 +0100 Subject: [PATCH 06/18] fix: remove console statement --- app/assets/javascripts/components/NoProtectionsNoteWarning.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx b/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx index ab84eaff2..074bf9288 100644 --- a/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx +++ b/app/assets/javascripts/components/NoProtectionsNoteWarning.tsx @@ -4,7 +4,6 @@ import { toDirective } from './utils'; type Props = { appState: AppState; onViewNote: () => void }; function NoProtectionsNoteWarning({ appState, onViewNote }: Props) { - console.log("🚀 ~ file: NoProtectionsNoteWarning.tsx ~ line 7 ~ NoProtectionsNoteWarning ~ onViewNote", onViewNote) return (

This note is protected

From bf6cfa398e7cd67a62e9d71c76974e86be56f868 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Mon, 22 Mar 2021 18:26:31 +0100 Subject: [PATCH 07/18] fix: extend editor area to full height --- app/assets/javascripts/views/editor/editor-view.pug | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/views/editor/editor-view.pug b/app/assets/javascripts/views/editor/editor-view.pug index fd59d0ba9..23d748efc 100644 --- a/app/assets/javascripts/views/editor/editor-view.pug +++ b/app/assets/javascripts/views/editor/editor-view.pug @@ -4,7 +4,7 @@ app-state='self.appState' on-view-note='self.dismissProtectedWarning()' ) - div( + .flex-grow.flex.flex-col( ng-if='self.state.showEditor' ) .sn-component From 9f5c640bcd619ce50b4a9c7ef9660307cfabcf82 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Mon, 22 Mar 2021 18:32:31 +0100 Subject: [PATCH 08/18] feat: show protected warning after protecting a note without protections --- .../javascripts/views/editor/editor-view.pug | 4 ++-- .../javascripts/views/editor/editor_view.ts | 22 ++++++++----------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/app/assets/javascripts/views/editor/editor-view.pug b/app/assets/javascripts/views/editor/editor-view.pug index 23d748efc..a19b4c0fe 100644 --- a/app/assets/javascripts/views/editor/editor-view.pug +++ b/app/assets/javascripts/views/editor/editor-view.pug @@ -1,11 +1,11 @@ #editor-column.section.editor.sn-component(aria-label='Note') protected-note-panel.h-full.flex.justify-center.items-center( - ng-if='self.note.protected && !self.state.showEditor' + ng-if='self.state.showProtectedWarning' app-state='self.appState' on-view-note='self.dismissProtectedWarning()' ) .flex-grow.flex.flex-col( - ng-if='self.state.showEditor' + ng-if='!self.state.showProtectedWarning' ) .sn-component .sk-app-bar.no-edges( diff --git a/app/assets/javascripts/views/editor/editor_view.ts b/app/assets/javascripts/views/editor/editor_view.ts index ee841f627..7af6638b2 100644 --- a/app/assets/javascripts/views/editor/editor_view.ts +++ b/app/assets/javascripts/views/editor/editor_view.ts @@ -80,7 +80,7 @@ type EditorState = { textareaUnloading: boolean /** Fields that can be directly mutated by the template */ mutable: any - showEditor: boolean + showProtectedWarning: boolean } type EditorValues = { @@ -225,7 +225,7 @@ class EditorViewCtrl extends PureViewCtrl { mutable: { tagsString: '' }, - showEditor: false, + showProtectedWarning: false, } as EditorState; } @@ -275,7 +275,7 @@ class EditorViewCtrl extends PureViewCtrl { async handleEditorNoteChange() { this.cancelPendingSetStatus(); const note = this.editor.note; - const showEditor = !note.protected; + const showProtectedWarning = note.protected && !this.application.hasProtectionSources(); await this.setState({ showActionsMenu: false, showOptionsMenu: false, @@ -283,7 +283,7 @@ class EditorViewCtrl extends PureViewCtrl { showHistoryMenu: false, altKeyDown: false, noteStatus: undefined, - showEditor, + showProtectedWarning, }); this.editorValues.title = note.title; this.editorValues.text = note.text; @@ -292,14 +292,14 @@ class EditorViewCtrl extends PureViewCtrl { this.reloadPreferences(); this.reloadStackComponents(); this.reloadNoteTagsComponent(); - if (note.safeText().length === 0 && showEditor) { + if (note.safeText().length === 0 && !showProtectedWarning) { this.focusTitle(); } } async dismissProtectedWarning() { await this.setState({ - showEditor: true + showProtectedWarning: false }); this.focusTitle(); } @@ -730,13 +730,9 @@ class EditorViewCtrl extends PureViewCtrl { } else { const note = await this.application.protectNote(this.note); if (note?.protected && !this.application.hasProtectionSources()) { - if (await confirmDialog({ - text: Strings.protectingNoteWithoutProtectionSources, - confirmButtonText: Strings.openAccountMenu, - confirmButtonStyle: 'info', - })) { - this.appState.accountMenu.setShow(true); - } + this.setState({ + showProtectedWarning: true + }); } } } From ac634333cf9ab5695f7cac3857550faf50e5b55b Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Mon, 22 Mar 2021 18:32:50 +0100 Subject: [PATCH 09/18] style: run prettier --- .../javascripts/views/editor/editor_view.ts | 732 +++++++++--------- 1 file changed, 352 insertions(+), 380 deletions(-) diff --git a/app/assets/javascripts/views/editor/editor_view.ts b/app/assets/javascripts/views/editor/editor_view.ts index 7af6638b2..692b36c63 100644 --- a/app/assets/javascripts/views/editor/editor_view.ts +++ b/app/assets/javascripts/views/editor/editor_view.ts @@ -1,4 +1,9 @@ -import { Strings, STRING_ARCHIVE_LOCKED_ATTEMPT, STRING_SAVING_WHILE_DOCUMENT_HIDDEN, STRING_UNARCHIVE_LOCKED_ATTEMPT } from './../../strings'; +import { + Strings, + STRING_ARCHIVE_LOCKED_ATTEMPT, + STRING_SAVING_WHILE_DOCUMENT_HIDDEN, + STRING_UNARCHIVE_LOCKED_ATTEMPT, +} from './../../strings'; import { Editor } from '@/ui_models/editor'; import { WebApplication } from '@/ui_models/application'; import { PanelPuppet, WebDirective } from '@/types'; @@ -31,7 +36,7 @@ import { STRING_DELETE_PLACEHOLDER_ATTEMPT, STRING_DELETE_LOCKED_ATTEMPT, StringDeleteNote, - StringEmptyTrash + StringEmptyTrash, } from '@/strings'; import { alertDialog, confirmDialog } from '@/services/alertService'; @@ -45,89 +50,91 @@ const ElementIds = { NoteTextEditor: 'note-text-editor', NoteTitleEditor: 'note-title-editor', EditorContent: 'editor-content', - NoteTagsComponentContainer: 'note-tags-component-container' + NoteTagsComponentContainer: 'note-tags-component-container', }; type NoteStatus = { - message?: string - date?: Date -} + message?: string; + date?: Date; +}; type EditorState = { - stackComponents: SNComponent[] - editorComponent?: SNComponent - tagsComponent?: SNComponent - saveError?: any - noteStatus?: NoteStatus - tagsAsStrings?: string - marginResizersEnabled?: boolean - monospaceFont?: boolean - isDesktop?: boolean - syncTakingTooLong: boolean - showActionsMenu: boolean - showOptionsMenu: boolean - showEditorMenu: boolean - showHistoryMenu: boolean - altKeyDown: boolean - spellcheck: boolean + stackComponents: SNComponent[]; + editorComponent?: SNComponent; + tagsComponent?: SNComponent; + saveError?: any; + noteStatus?: NoteStatus; + tagsAsStrings?: string; + marginResizersEnabled?: boolean; + monospaceFont?: boolean; + isDesktop?: boolean; + syncTakingTooLong: boolean; + showActionsMenu: boolean; + showOptionsMenu: boolean; + showEditorMenu: boolean; + showHistoryMenu: boolean; + altKeyDown: boolean; + spellcheck: boolean; /** * Setting to false then true will allow the current editor component-view to be destroyed * then re-initialized. Used when changing between component editors. */ - editorUnloading: boolean + editorUnloading: boolean; /** Setting to true then false will allow the main content textarea to be destroyed * then re-initialized. Used when reloading spellcheck status. */ - textareaUnloading: boolean + textareaUnloading: boolean; /** Fields that can be directly mutated by the template */ - mutable: any - showProtectedWarning: boolean -} + mutable: any; + showProtectedWarning: boolean; +}; type EditorValues = { - title?: string - text?: string - tagsInputValue?: string -} + title?: string; + text?: string; + tagsInputValue?: string; +}; function sortAlphabetically(array: SNComponent[]): SNComponent[] { - return array.sort((a, b) => a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1); + return array.sort((a, b) => + a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1 + ); } class EditorViewCtrl extends PureViewCtrl { /** Passed through template */ - readonly application!: WebApplication - readonly editor!: Editor + readonly application!: WebApplication; + readonly editor!: Editor; - private leftPanelPuppet?: PanelPuppet - private rightPanelPuppet?: PanelPuppet - private unregisterComponent: any - private saveTimeout?: ng.IPromise - private statusTimeout?: ng.IPromise - private lastEditorFocusEventSource?: EventSource - public editorValues: EditorValues = {} - onEditorLoad?: () => void + private leftPanelPuppet?: PanelPuppet; + private rightPanelPuppet?: PanelPuppet; + private unregisterComponent: any; + private saveTimeout?: ng.IPromise; + private statusTimeout?: ng.IPromise; + private lastEditorFocusEventSource?: EventSource; + public editorValues: EditorValues = {}; + onEditorLoad?: () => void; private tags: SNTag[] = []; - private removeAltKeyObserver?: any - private removeTrashKeyObserver?: any - private removeTabObserver?: any + private removeAltKeyObserver?: any; + private removeTrashKeyObserver?: any; + private removeTabObserver?: any; - private removeTagsObserver!: () => void - private removeComponentsObserver!: () => void + private removeTagsObserver!: () => void; + private removeComponentsObserver!: () => void; - prefKeyMonospace: string - prefKeySpellcheck: string - prefKeyMarginResizers: string + prefKeyMonospace: string; + prefKeySpellcheck: string; + prefKeyMarginResizers: string; /* @ngInject */ constructor($timeout: ng.ITimeoutService) { super($timeout); this.leftPanelPuppet = { - onReady: () => this.reloadPreferences() + onReady: () => this.reloadPreferences(), }; this.rightPanelPuppet = { - onReady: () => this.reloadPreferences() + onReady: () => this.reloadPreferences(), }; /** Used by .pug template */ this.prefKeyMonospace = PrefKey.EditorMonospaceEnabled; @@ -196,7 +203,9 @@ class EditorViewCtrl extends PureViewCtrl { if (note.lastSyncEnd) { if (note.lastSyncBegan!.getTime() > note.lastSyncEnd!.getTime()) { this.showSavingStatus(); - } else if (note.lastSyncEnd!.getTime() > note.lastSyncBegan!.getTime()) { + } else if ( + note.lastSyncEnd!.getTime() > note.lastSyncBegan!.getTime() + ) { this.showAllChangesSavedStatus(); } } else { @@ -223,7 +232,7 @@ class EditorViewCtrl extends PureViewCtrl { editorUnloading: false, textareaUnloading: false, mutable: { - tagsString: '' + tagsString: '', }, showProtectedWarning: false, } as EditorState; @@ -265,8 +274,8 @@ class EditorViewCtrl extends PureViewCtrl { break; case ApplicationEvent.LocalDatabaseWriteError: this.showErrorStatus({ - message: "Offline Saving Issue", - desc: "Changes not saved" + message: 'Offline Saving Issue', + desc: 'Changes not saved', }); break; } @@ -275,7 +284,8 @@ class EditorViewCtrl extends PureViewCtrl { async handleEditorNoteChange() { this.cancelPendingSetStatus(); const note = this.editor.note; - const showProtectedWarning = note.protected && !this.application.hasProtectionSources(); + const showProtectedWarning = + note.protected && !this.application.hasProtectionSources(); await this.setState({ showActionsMenu: false, showOptionsMenu: false, @@ -299,7 +309,7 @@ class EditorViewCtrl extends PureViewCtrl { async dismissProtectedWarning() { await this.setState({ - showProtectedWarning: false + showProtectedWarning: false, }); this.focusTitle(); } @@ -342,7 +352,9 @@ class EditorViewCtrl extends PureViewCtrl { } private async reloadEditor() { - const newEditor = this.application.componentManager!.editorForNote(this.note); + const newEditor = this.application.componentManager!.editorForNote( + this.note + ); /** Editors cannot interact with template notes so the note must be inserted */ if (newEditor && this.editor.isTemplateNote) { await this.editor.insertTemplatedNote(); @@ -351,7 +363,7 @@ class EditorViewCtrl extends PureViewCtrl { if (currentEditor?.uuid !== newEditor?.uuid) { await this.setState({ /** Unload current component view so that we create a new one */ - editorUnloading: true + editorUnloading: true, }); await this.setState({ /** Reload component view */ @@ -360,12 +372,14 @@ class EditorViewCtrl extends PureViewCtrl { }); this.reloadFont(); } - this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.Editor); + this.application.componentManager!.contextItemDidChangeInArea( + ComponentArea.Editor + ); } setMenuState(menu: string, state: boolean) { this.setState({ - [menu]: state + [menu]: state, }); this.closeAllMenus(menu); } @@ -403,12 +417,15 @@ class EditorViewCtrl extends PureViewCtrl { }); this.reloadEditor(); } - if (this.state.editorComponent?.isExplicitlyEnabledForItem(this.note.uuid)) { - await this.disassociateComponentWithCurrentNote(this.state.editorComponent); + if ( + this.state.editorComponent?.isExplicitlyEnabledForItem(this.note.uuid) + ) { + await this.disassociateComponentWithCurrentNote( + this.state.editorComponent + ); } this.reloadFont(); - } - else if (component.area === ComponentArea.Editor) { + } else if (component.area === ComponentArea.Editor) { const currentEditor = this.state.editorComponent; if (currentEditor && component !== currentEditor) { await this.disassociateComponentWithCurrentNote(currentEditor); @@ -421,8 +438,7 @@ class EditorViewCtrl extends PureViewCtrl { }); } await this.associateComponentWithCurrentNote(component); - } - else if (component.area === ComponentArea.EditorStack) { + } else if (component.area === ComponentArea.EditorStack) { await this.toggleStackComponentForCurrentItem(component); } /** Dirtying can happen above */ @@ -430,8 +446,10 @@ class EditorViewCtrl extends PureViewCtrl { } hasAvailableExtensions() { - return this.application.actionsManager!. - extensionsInContextOfItem(this.note).length > 0; + return ( + this.application.actionsManager!.extensionsInContextOfItem(this.note) + .length > 0 + ); } /** @@ -455,52 +473,50 @@ class EditorViewCtrl extends PureViewCtrl { closeAfterSync = false ) { if (document.hidden) { - this.application.alertService!.alert( - STRING_SAVING_WHILE_DOCUMENT_HIDDEN - ); + this.application.alertService!.alert(STRING_SAVING_WHILE_DOCUMENT_HIDDEN); return; } const note = this.note; if (note.deleted) { - this.application.alertService!.alert( - STRING_DELETED_NOTE - ); + this.application.alertService!.alert(STRING_DELETED_NOTE); return; } if (this.editor.isTemplateNote) { await this.editor.insertTemplatedNote(); } const selectedTag = this.appState.selectedTag; - if (!selectedTag?.isSmartTag && !selectedTag?.hasRelationshipWithItem(note)) { - await this.application.changeItem( - selectedTag!.uuid, - (mutator) => { - mutator.addItemAsRelationship(note); - } - ); + if ( + !selectedTag?.isSmartTag && + !selectedTag?.hasRelationshipWithItem(note) + ) { + await this.application.changeItem(selectedTag!.uuid, (mutator) => { + mutator.addItemAsRelationship(note); + }); } if (!this.application.findItem(note.uuid)) { - this.application.alertService!.alert( - STRING_INVALID_NOTE - ); + this.application.alertService!.alert(STRING_INVALID_NOTE); return; } - await this.application.changeItem(note.uuid, (mutator) => { - const noteMutator = mutator as NoteMutator; - if (customMutate) { - customMutate(noteMutator); - } - noteMutator.title = this.editorValues.title!; - noteMutator.text = this.editorValues.text!; - if (!dontUpdatePreviews) { - const text = this.editorValues.text || ''; - const truncate = text.length > NOTE_PREVIEW_CHAR_LIMIT; - const substring = text.substring(0, NOTE_PREVIEW_CHAR_LIMIT); - const previewPlain = substring + (truncate ? STRING_ELLIPSES : ''); - noteMutator.preview_plain = previewPlain; - noteMutator.preview_html = undefined; - } - }, isUserModified); + await this.application.changeItem( + note.uuid, + (mutator) => { + const noteMutator = mutator as NoteMutator; + if (customMutate) { + customMutate(noteMutator); + } + noteMutator.title = this.editorValues.title!; + noteMutator.text = this.editorValues.text!; + if (!dontUpdatePreviews) { + const text = this.editorValues.text || ''; + const truncate = text.length > NOTE_PREVIEW_CHAR_LIMIT; + const substring = text.substring(0, NOTE_PREVIEW_CHAR_LIMIT); + const previewPlain = substring + (truncate ? STRING_ELLIPSES : ''); + noteMutator.preview_plain = previewPlain; + noteMutator.preview_html = undefined; + } + }, + isUserModified + ); if (this.saveTimeout) { this.$timeout.cancel(this.saveTimeout); } @@ -517,16 +533,13 @@ class EditorViewCtrl extends PureViewCtrl { } showSavingStatus() { - this.setStatus( - { message: "Saving…" }, - false - ); + this.setStatus({ message: 'Saving…' }, false); } showAllChangesSavedStatus() { this.setState({ saveError: false, - syncTakingTooLong: false + syncTakingTooLong: false, }); this.setStatus({ message: 'All changes saved', @@ -536,13 +549,13 @@ class EditorViewCtrl extends PureViewCtrl { showErrorStatus(error?: any) { if (!error) { error = { - message: "Sync Unreachable", - desc: "Changes saved offline" + message: 'Sync Unreachable', + desc: 'Changes saved offline', }; } this.setState({ saveError: true, - syncTakingTooLong: false + syncTakingTooLong: false, }); this.setStatus(error); } @@ -554,12 +567,12 @@ class EditorViewCtrl extends PureViewCtrl { if (wait) { this.statusTimeout = this.$timeout(() => { this.setState({ - noteStatus: status + noteStatus: status, }); }, MINIMUM_STATUS_DURATION); } else { this.setState({ - noteStatus: status + noteStatus: status, }); } } @@ -571,10 +584,7 @@ class EditorViewCtrl extends PureViewCtrl { } contentChanged() { - this.saveNote( - false, - true - ); + this.saveNote(false, true); } onTitleEnter($event: Event) { @@ -584,11 +594,7 @@ class EditorViewCtrl extends PureViewCtrl { } onTitleChange() { - this.saveNote( - false, - true, - true, - ); + this.saveNote(false, true, true); } focusEditor() { @@ -608,17 +614,15 @@ class EditorViewCtrl extends PureViewCtrl { } // eslint-disable-next-line @typescript-eslint/no-empty-function - onTitleFocus() { - - } + onTitleFocus() {} // eslint-disable-next-line @typescript-eslint/no-empty-function - onTitleBlur() { - - } + onTitleBlur() {} onContentFocus() { - this.application.getAppState().editorDidFocus(this.lastEditorFocusEventSource!); + this.application + .getAppState() + .editorDidFocus(this.lastEditorFocusEventSource!); this.lastEditorFocusEventSource = undefined; } @@ -630,39 +634,29 @@ class EditorViewCtrl extends PureViewCtrl { async deleteNote(permanently: boolean) { if (this.editor.isTemplateNote) { - this.application.alertService!.alert( - STRING_DELETE_PLACEHOLDER_ATTEMPT - ); + this.application.alertService!.alert(STRING_DELETE_PLACEHOLDER_ATTEMPT); return; } if (this.note.locked) { - this.application.alertService!.alert( - STRING_DELETE_LOCKED_ATTEMPT - ); + this.application.alertService!.alert(STRING_DELETE_LOCKED_ATTEMPT); return; } const title = this.note.safeTitle().length ? `'${this.note.title}'` - : "this note"; - const text = StringDeleteNote( - title, - permanently - ); - if (await confirmDialog({ - text, - confirmButtonStyle: 'danger' - })) { + : 'this note'; + const text = StringDeleteNote(title, permanently); + if ( + await confirmDialog({ + text, + confirmButtonStyle: 'danger', + }) + ) { if (permanently) { this.performNoteDeletion(this.note); } else { - this.saveNote( - true, - false, - true, - (mutator) => { - mutator.trashed = true; - } - ); + this.saveNote(true, false, true, (mutator) => { + mutator.trashed = true; + }); } } } @@ -693,35 +687,27 @@ class EditorViewCtrl extends PureViewCtrl { async emptyTrash() { const count = this.getTrashCount(); - if (await confirmDialog({ - text: StringEmptyTrash(count), - confirmButtonStyle: 'danger' - })) { + if ( + await confirmDialog({ + text: StringEmptyTrash(count), + confirmButtonStyle: 'danger', + }) + ) { this.application.emptyTrash(); this.application.sync(); } } togglePin() { - this.saveNote( - true, - false, - true, - (mutator) => { - mutator.pinned = !this.note.pinned; - } - ); + this.saveNote(true, false, true, (mutator) => { + mutator.pinned = !this.note.pinned; + }); } toggleLockNote() { - this.saveNote( - true, - false, - true, - (mutator) => { - mutator.locked = !this.note.locked; - } - ); + this.saveNote(true, false, true, (mutator) => { + mutator.locked = !this.note.locked; + }); } async toggleProtectNote() { @@ -731,29 +717,24 @@ class EditorViewCtrl extends PureViewCtrl { const note = await this.application.protectNote(this.note); if (note?.protected && !this.application.hasProtectionSources()) { this.setState({ - showProtectedWarning: true + showProtectedWarning: true, }); } } } toggleNotePreview() { - this.saveNote( - true, - false, - true, - (mutator) => { - mutator.hidePreview = !this.note.hidePreview; - } - ); + this.saveNote(true, false, true, (mutator) => { + mutator.hidePreview = !this.note.hidePreview; + }); } toggleArchiveNote() { if (this.note.locked) { alertDialog({ - text: this.note.archived ? - STRING_UNARCHIVE_LOCKED_ATTEMPT : - STRING_ARCHIVE_LOCKED_ATTEMPT, + text: this.note.archived + ? STRING_UNARCHIVE_LOCKED_ATTEMPT + : STRING_ARCHIVE_LOCKED_ATTEMPT, }); return; } @@ -781,10 +762,7 @@ class EditorViewCtrl extends PureViewCtrl { for (let i = 0; i < tags.length; i++) { const localTag = this.tags[i]; const tag = tags[i]; - if ( - tag.title !== localTag.title || - tag.uuid !== localTag.uuid - ) { + if (tag.title !== localTag.title || tag.uuid !== localTag.uuid) { this.reloadTagsString(tags); break; } @@ -810,11 +788,13 @@ class EditorViewCtrl extends PureViewCtrl { removeTag(tag: SNTag) { const tags = this.appState.getNoteTags(this.note); - const strings = tags.map((currentTag) => { - return currentTag.title; - }).filter((title) => { - return title !== tag.title; - }); + const strings = tags + .map((currentTag) => { + return currentTag.title; + }) + .filter((title) => { + return title !== tag.title; + }); this.saveTagsFromStrings(strings); } @@ -825,14 +805,14 @@ class EditorViewCtrl extends PureViewCtrl { public async saveTagsFromStrings(strings?: string[]) { if ( - !strings - && this.editorValues.tagsInputValue === this.state.tagsAsStrings + !strings && + this.editorValues.tagsInputValue === this.state.tagsAsStrings ) { return; } if (!strings) { - strings = this.editorValues.tagsInputValue! - .split('#') + strings = this.editorValues + .tagsInputValue!.split('#') .filter((string) => { return string.length > 0; }) @@ -855,23 +835,15 @@ class EditorViewCtrl extends PureViewCtrl { } const newRelationships: SNTag[] = []; for (const title of strings) { - const existingRelationship = find( - currentTags, - { title: title } - ); + const existingRelationship = find(currentTags, { title: title }); if (!existingRelationship) { - newRelationships.push( - await this.application.findOrCreateTag(title) - ); + newRelationships.push(await this.application.findOrCreateTag(title)); } } if (newRelationships.length > 0) { - await this.application.changeItems( - Uuids(newRelationships), - (mutator) => { - mutator.addItemAsRelationship(note); - } - ); + await this.application.changeItems(Uuids(newRelationships), (mutator) => { + mutator.addItemAsRelationship(note); + }); } this.application.sync(); this.reloadTags(); @@ -879,24 +851,15 @@ class EditorViewCtrl extends PureViewCtrl { async onPanelResizeFinish(width: number, left: number, isMaxWidth: boolean) { if (isMaxWidth) { - await this.application.setPreference( - PrefKey.EditorWidth, - null - ); + await this.application.setPreference(PrefKey.EditorWidth, null); } else { if (width !== undefined && width !== null) { - await this.application.setPreference( - PrefKey.EditorWidth, - width - ); + await this.application.setPreference(PrefKey.EditorWidth, width); this.leftPanelPuppet!.setWidth!(width); } } if (left !== undefined && left !== null) { - await this.application.setPreference( - PrefKey.EditorLeft, - left - ); + await this.application.setPreference(PrefKey.EditorLeft, left); this.rightPanelPuppet!.setLeft!(left); } this.application.sync(); @@ -918,7 +881,7 @@ class EditorViewCtrl extends PureViewCtrl { await this.setState({ monospaceFont, spellcheck, - marginResizersEnabled + marginResizersEnabled, }); if (!document.getElementById(ElementIds.EditorContent)) { @@ -933,18 +896,12 @@ class EditorViewCtrl extends PureViewCtrl { this.leftPanelPuppet?.ready && this.rightPanelPuppet?.ready ) { - const width = this.application.getPreference( - PrefKey.EditorWidth, - null - ); + const width = this.application.getPreference(PrefKey.EditorWidth, null); if (width != null) { this.leftPanelPuppet!.setWidth!(width); this.rightPanelPuppet!.setWidth!(width); } - const left = this.application.getPreference( - PrefKey.EditorLeft, - null - ); + const left = this.application.getPreference(PrefKey.EditorLeft, null); if (left != null) { this.leftPanelPuppet!.setLeft!(left); this.rightPanelPuppet!.setLeft!(left); @@ -956,10 +913,7 @@ class EditorViewCtrl extends PureViewCtrl { const root = document.querySelector(':root') as HTMLElement; const propertyName = '--sn-stylekit-editor-font-family'; if (this.state.monospaceFont) { - root.style.setProperty( - propertyName, - 'var(--sn-stylekit-monospace-font)' - ); + root.style.setProperty(propertyName, 'var(--sn-stylekit-monospace-font)'); } else { root.style.setProperty( propertyName, @@ -970,12 +924,9 @@ class EditorViewCtrl extends PureViewCtrl { async toggleWebPrefKey(key: PrefKey) { const currentValue = (this.state as any)[key]; - await this.application.setPreference( - key, - !currentValue, - ); + await this.application.setPreference(key, !currentValue); await this.setState({ - [key]: !currentValue + [key]: !currentValue, }); this.reloadFont(); @@ -984,7 +935,10 @@ class EditorViewCtrl extends PureViewCtrl { await this.setState({ textareaUnloading: true }); await this.setState({ textareaUnloading: false }); this.reloadFont(); - } else if (key === PrefKey.EditorResizersEnabled && this.state[key] === true) { + } else if ( + key === PrefKey.EditorResizersEnabled && + this.state[key] === true + ) { this.$timeout(() => { this.leftPanelPuppet!.flash!(); this.rightPanelPuppet!.flash!(); @@ -995,99 +949,106 @@ class EditorViewCtrl extends PureViewCtrl { /** @components */ registerComponentHandler() { - this.unregisterComponent = this.application.componentManager!.registerHandler({ - identifier: 'editor', - areas: [ - ComponentArea.NoteTags, - ComponentArea.EditorStack, - ComponentArea.Editor - ], - contextRequestHandler: (componentUuid) => { - const currentEditor = this.state.editorComponent; - if ( - componentUuid === currentEditor?.uuid || - componentUuid === this.state.tagsComponent?.uuid || - Uuids(this.state.stackComponents).includes(componentUuid) - ) { - return this.note; - } - }, - focusHandler: (component, focused) => { - if (component.isEditor() && focused) { - this.closeAllMenus(); - } - }, - actionHandler: (component, action, data) => { - if (action === ComponentAction.SetSize) { - const setSize = ( - element: HTMLElement, - size: { width: string | number, height: string | number } - ) => { - const widthString = typeof size.width === 'string' - ? size.width - : `${data.width}px`; - const heightString = typeof size.height === 'string' - ? size.height - : `${data.height}px`; - element.setAttribute( - 'style', - `width: ${widthString}; height: ${heightString};` - ); - }; - if (data.type === 'container') { - if (component.area === ComponentArea.NoteTags) { - const container = document.getElementById( - ElementIds.NoteTagsComponentContainer - ); - setSize(container!, { width: data.width!, height: data.height! }); - } + this.unregisterComponent = this.application.componentManager!.registerHandler( + { + identifier: 'editor', + areas: [ + ComponentArea.NoteTags, + ComponentArea.EditorStack, + ComponentArea.Editor, + ], + contextRequestHandler: (componentUuid) => { + const currentEditor = this.state.editorComponent; + if ( + componentUuid === currentEditor?.uuid || + componentUuid === this.state.tagsComponent?.uuid || + Uuids(this.state.stackComponents).includes(componentUuid) + ) { + return this.note; } - } - else if (action === ComponentAction.AssociateItem) { - if (data.item!.content_type === ContentType.Tag) { + }, + focusHandler: (component, focused) => { + if (component.isEditor() && focused) { + this.closeAllMenus(); + } + }, + actionHandler: (component, action, data) => { + if (action === ComponentAction.SetSize) { + const setSize = ( + element: HTMLElement, + size: { width: string | number; height: string | number } + ) => { + const widthString = + typeof size.width === 'string' ? size.width : `${data.width}px`; + const heightString = + typeof size.height === 'string' + ? size.height + : `${data.height}px`; + element.setAttribute( + 'style', + `width: ${widthString}; height: ${heightString};` + ); + }; + if (data.type === 'container') { + if (component.area === ComponentArea.NoteTags) { + const container = document.getElementById( + ElementIds.NoteTagsComponentContainer + ); + setSize(container!, { + width: data.width!, + height: data.height!, + }); + } + } + } else if (action === ComponentAction.AssociateItem) { + if (data.item!.content_type === ContentType.Tag) { + const tag = this.application.findItem(data.item!.uuid) as SNTag; + this.addTag(tag); + } + } else if (action === ComponentAction.DeassociateItem) { const tag = this.application.findItem(data.item!.uuid) as SNTag; - this.addTag(tag); - } - } - else if (action === ComponentAction.DeassociateItem) { - const tag = this.application.findItem(data.item!.uuid) as SNTag; - this.removeTag(tag); - } else if ( - action === ComponentAction.SaveSuccess - ) { - const savedUuid = data.item ? data.item.uuid : data.items![0].uuid; - if (savedUuid === this.note.uuid) { - const selectedTag = this.appState.selectedTag; - if ( - !selectedTag?.isSmartTag && - !selectedTag?.hasRelationshipWithItem(this.note) - ) { - this.application.changeAndSaveItem( - selectedTag!.uuid, - (mutator) => { - mutator.addItemAsRelationship(this.note); - } - ); + this.removeTag(tag); + } else if (action === ComponentAction.SaveSuccess) { + const savedUuid = data.item ? data.item.uuid : data.items![0].uuid; + if (savedUuid === this.note.uuid) { + const selectedTag = this.appState.selectedTag; + if ( + !selectedTag?.isSmartTag && + !selectedTag?.hasRelationshipWithItem(this.note) + ) { + this.application.changeAndSaveItem( + selectedTag!.uuid, + (mutator) => { + mutator.addItemAsRelationship(this.note); + } + ); + } } } - } + }, } - }); + ); } async reloadNoteTagsComponent() { - const [tagsComponent] = - this.application.componentManager!.componentsForArea(ComponentArea.NoteTags); + const [ + tagsComponent, + ] = this.application.componentManager!.componentsForArea( + ComponentArea.NoteTags + ); await this.setState({ - tagsComponent: tagsComponent?.active ? tagsComponent : undefined + tagsComponent: tagsComponent?.active ? tagsComponent : undefined, }); - this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.NoteTags); + this.application.componentManager!.contextItemDidChangeInArea( + ComponentArea.NoteTags + ); } async reloadStackComponents() { const stackComponents = sortAlphabetically( - this.application.componentManager!.componentsForArea(ComponentArea.EditorStack) - .filter(component => component.active) + this.application + .componentManager!.componentsForArea(ComponentArea.EditorStack) + .filter((component) => component.active) ); if (this.note) { for (const component of stackComponents) { @@ -1100,7 +1061,9 @@ class EditorViewCtrl extends PureViewCtrl { } } await this.setState({ stackComponents }); - this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack); + this.application.componentManager!.contextItemDidChangeInArea( + ComponentArea.EditorStack + ); } stackComponentHidden(component: SNComponent) { @@ -1108,11 +1071,15 @@ class EditorViewCtrl extends PureViewCtrl { } async toggleStackComponentForCurrentItem(component: SNComponent) { - const hidden = this.application.componentManager!.isComponentHidden(component); + const hidden = this.application.componentManager!.isComponentHidden( + component + ); if (hidden || !component.active) { this.application.componentManager!.setComponentHidden(component, false); await this.associateComponentWithCurrentNote(component); - this.application.componentManager!.contextItemDidChangeInArea(ComponentArea.EditorStack); + this.application.componentManager!.contextItemDidChangeInArea( + ComponentArea.EditorStack + ); } else { this.application.componentManager!.setComponentHidden(component, true); await this.disassociateComponentWithCurrentNote(component); @@ -1139,33 +1106,32 @@ class EditorViewCtrl extends PureViewCtrl { } registerKeyboardShortcuts() { - this.removeAltKeyObserver = this.application.getKeyboardService().addKeyObserver({ - modifiers: [ - KeyboardModifier.Alt - ], - onKeyDown: () => { - this.setState({ - altKeyDown: true - }); - }, - onKeyUp: () => { - this.setState({ - altKeyDown: false - }); - } - }); + this.removeAltKeyObserver = this.application + .getKeyboardService() + .addKeyObserver({ + modifiers: [KeyboardModifier.Alt], + onKeyDown: () => { + this.setState({ + altKeyDown: true, + }); + }, + onKeyUp: () => { + this.setState({ + altKeyDown: false, + }); + }, + }); - this.removeTrashKeyObserver = this.application.getKeyboardService().addKeyObserver({ - key: KeyboardKey.Backspace, - notElementIds: [ - ElementIds.NoteTextEditor, - ElementIds.NoteTitleEditor - ], - modifiers: [KeyboardModifier.Meta], - onKeyDown: () => { - this.deleteNote(false); - }, - }); + this.removeTrashKeyObserver = this.application + .getKeyboardService() + .addKeyObserver({ + key: KeyboardKey.Backspace, + notElementIds: [ElementIds.NoteTextEditor, ElementIds.NoteTitleEditor], + modifiers: [KeyboardModifier.Meta], + onKeyDown: () => { + this.deleteNote(false); + }, + }); } onSystemEditorLoad() { @@ -1177,37 +1143,43 @@ class EditorViewCtrl extends PureViewCtrl { * only used when inside of the text editor. * If the shift key is pressed first, this event is * not fired. - */ - const editor = document.getElementById(ElementIds.NoteTextEditor)! as HTMLInputElement; - this.removeTabObserver = this.application.getKeyboardService().addKeyObserver({ - element: editor, - key: KeyboardKey.Tab, - onKeyDown: (event) => { - if (document.hidden || this.note.locked || event.shiftKey) { - return; - } - event.preventDefault(); - /** Using document.execCommand gives us undo support */ - const insertSuccessful = document.execCommand( - 'insertText', - false, - '\t' - ); - if (!insertSuccessful) { - /** document.execCommand works great on Chrome/Safari but not Firefox */ - const start = editor.selectionStart!; - const end = editor.selectionEnd!; - const spaces = ' '; - /** Insert 4 spaces */ - editor.value = editor.value.substring(0, start) - + spaces + editor.value.substring(end); - /** Place cursor 4 spaces away from where the tab key was pressed */ - editor.selectionStart = editor.selectionEnd = start + 4; - } - this.editorValues.text = editor.value; - this.saveNote(true); - }, - }); + */ + const editor = document.getElementById( + ElementIds.NoteTextEditor + )! as HTMLInputElement; + this.removeTabObserver = this.application + .getKeyboardService() + .addKeyObserver({ + element: editor, + key: KeyboardKey.Tab, + onKeyDown: (event) => { + if (document.hidden || this.note.locked || event.shiftKey) { + return; + } + event.preventDefault(); + /** Using document.execCommand gives us undo support */ + const insertSuccessful = document.execCommand( + 'insertText', + false, + '\t' + ); + if (!insertSuccessful) { + /** document.execCommand works great on Chrome/Safari but not Firefox */ + const start = editor.selectionStart!; + const end = editor.selectionEnd!; + const spaces = ' '; + /** Insert 4 spaces */ + editor.value = + editor.value.substring(0, start) + + spaces + + editor.value.substring(end); + /** Place cursor 4 spaces away from where the tab key was pressed */ + editor.selectionStart = editor.selectionEnd = start + 4; + } + this.editorValues.text = editor.value; + this.saveNote(true); + }, + }); /** * Handles when the editor is destroyed, @@ -1226,7 +1198,7 @@ export class EditorView extends WebDirective { this.restrict = 'E'; this.scope = { editor: '=', - application: '=' + application: '=', }; this.template = template; this.replace = true; From 232d01795ddc074d1ad677576a2d0d14c50db249 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Mon, 22 Mar 2021 18:34:27 +0100 Subject: [PATCH 10/18] refactor: remove unused import --- app/assets/javascripts/views/editor/editor_view.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/assets/javascripts/views/editor/editor_view.ts b/app/assets/javascripts/views/editor/editor_view.ts index 692b36c63..c99bb0991 100644 --- a/app/assets/javascripts/views/editor/editor_view.ts +++ b/app/assets/javascripts/views/editor/editor_view.ts @@ -1,5 +1,4 @@ import { - Strings, STRING_ARCHIVE_LOCKED_ATTEMPT, STRING_SAVING_WHILE_DOCUMENT_HIDDEN, STRING_UNARCHIVE_LOCKED_ATTEMPT, From cf76e1b42aacb5e83a7e988c146c931b7a3ca254 Mon Sep 17 00:00:00 2001 From: Mo Bitar Date: Mon, 22 Mar 2021 12:42:26 -0500 Subject: [PATCH 11/18] fix: reload when firefox pinned tab becomes visible (#535) Co-authored-by: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> --- app/assets/javascripts/app.ts | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts index 396efb323..f93fd2414 100644 --- a/app/assets/javascripts/app.ts +++ b/app/assets/javascripts/app.ts @@ -58,7 +58,6 @@ import { SessionsModalDirective } from './components/SessionsModal'; import { NoAccountWarningDirective } from './components/NoAccountWarning'; import { NoProtectionsdNoteWarningDirective } from './components/NoProtectionsNoteWarning'; - function reloadHiddenFirefoxTab(): boolean { /** * For Firefox pinned tab issue: @@ -67,14 +66,15 @@ function reloadHiddenFirefoxTab(): boolean { */ if ( document.hidden && - navigator.userAgent.toLowerCase().includes('firefox') && - !localStorage.getItem('reloading') + navigator.userAgent.toLowerCase().includes('firefox') ) { - localStorage.setItem('reloading', 'true'); - location.reload(); + document.addEventListener('visibilitychange', () => { + if (!document.hidden) { + location.reload(); + } + }); return true; } else { - localStorage.removeItem('reloading'); return false; } } @@ -170,7 +170,10 @@ const startApplication: StartApplication = async function startApplication( }; if (__WEB__) { - startApplication((window as any)._default_sync_server, new BrowserBridge(__VERSION__)); + startApplication( + (window as any)._default_sync_server, + new BrowserBridge(__VERSION__) + ); } else { (window as any).startApplication = startApplication; } From 52e8e8220bf4990d21bfaa254dfa8e99485878e7 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Tue, 23 Mar 2021 15:41:11 +0100 Subject: [PATCH 12/18] chore(deps): update SNJS --- app/assets/javascripts/directives/views/accountMenu.ts | 2 +- package.json | 2 +- yarn.lock | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/directives/views/accountMenu.ts b/app/assets/javascripts/directives/views/accountMenu.ts index 6012d5fbe..10c35da52 100644 --- a/app/assets/javascripts/directives/views/accountMenu.ts +++ b/app/assets/javascripts/directives/views/accountMenu.ts @@ -533,7 +533,7 @@ class AccountMenuCtrl extends PureViewCtrl { if (this.application!.hasPasscode()) { await this.application!.changePasscode(passcode); } else { - await this.application!.setPasscode(passcode); + await this.application!.addPasscode(passcode); } } ); diff --git a/package.json b/package.json index daeda2096..ccbbd6d7d 100644 --- a/package.json +++ b/package.json @@ -68,7 +68,7 @@ "@reach/alert-dialog": "^0.13.0", "@reach/dialog": "^0.13.0", "@standardnotes/sncrypto-web": "^1.2.10", - "@standardnotes/snjs": "^2.0.69", + "@standardnotes/snjs": "^2.0.70", "mobx": "^6.1.6", "preact": "^10.5.12" } diff --git a/yarn.lock b/yarn.lock index 1f4e36486..f90c27fc2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1850,10 +1850,10 @@ "@standardnotes/sncrypto-common" "^1.2.7" libsodium-wrappers "^0.7.8" -"@standardnotes/snjs@^2.0.69": - version "2.0.69" - resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.0.69.tgz#8bb5184547673442555bd07a33b998b85117885c" - integrity sha512-S+7ozn+Xi2BAKZE1yM0wWHPLXOR4wAqUomZRU0jP1SK8XJwb2XMUKhM84wSK2AOfFDTvONzeqC5/lAK9ZXT+Sw== +"@standardnotes/snjs@^2.0.70": + version "2.0.70" + resolved "https://registry.yarnpkg.com/@standardnotes/snjs/-/snjs-2.0.70.tgz#259a4fadc4f9b360f35a399b674b921179bd5768" + integrity sha512-D11E+sCeoram2+NhQuFmn333JoHr1kGjVZrkRmZlfhGi+dYXJqZuDDDHbRn5WEJQneDg43Z8DjjAlxL+Mqhp6w== dependencies: "@standardnotes/auth" "^2.0.0" "@standardnotes/sncrypto-common" "^1.2.9" From 257c0f6cab12ee86d9495845542fb47437007ba2 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Tue, 23 Mar 2021 18:52:11 +0100 Subject: [PATCH 13/18] feat: add onSignOut bridge hook --- app/assets/javascripts/services/bridge.ts | 1 + app/assets/javascripts/services/browserBridge.ts | 1 + app/assets/javascripts/ui_models/application.ts | 6 ++++-- 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/services/bridge.ts b/app/assets/javascripts/services/bridge.ts index 7b0da9931..5cf08d83a 100644 --- a/app/assets/javascripts/services/bridge.ts +++ b/app/assets/javascripts/services/bridge.ts @@ -17,6 +17,7 @@ export interface Bridge { syncComponents(payloads: unknown[]): void; onMajorDataChange(): void; onInitialDataLoad(): void; + onSignOut(): void; onSearch(text?: string): void; downloadBackup(): void | Promise; } diff --git a/app/assets/javascripts/services/browserBridge.ts b/app/assets/javascripts/services/browserBridge.ts index d0408ffa6..29796ec80 100644 --- a/app/assets/javascripts/services/browserBridge.ts +++ b/app/assets/javascripts/services/browserBridge.ts @@ -30,4 +30,5 @@ export class BrowserBridge implements Bridge { onInitialDataLoad(): void {} onSearch(): void {} downloadBackup(): void {} + onSignOut(): void {} } diff --git a/app/assets/javascripts/ui_models/application.ts b/app/assets/javascripts/ui_models/application.ts index d47790a9f..131c3055b 100644 --- a/app/assets/javascripts/ui_models/application.ts +++ b/app/assets/javascripts/ui_models/application.ts @@ -6,13 +6,12 @@ import { InputModalScope } from '@/directives/views/inputModal'; import { PasswordWizardType, PasswordWizardScope } from '@/types'; import { SNApplication, - platformFromString, SNComponent, PermissionDialog, DeinitSource, } from '@standardnotes/snjs'; import angular from 'angular'; -import { getPlatform, getPlatformString } from '@/utils'; +import { getPlatform } from '@/utils'; import { AlertService } from '@/services/alertService'; import { WebDeviceInterface } from '@/web_device_interface'; import { @@ -92,6 +91,9 @@ export class WebApplication extends SNApplication { this.scope = undefined; (this.openModalComponent as any) = undefined; (this.presentPermissionsDialog as any) = undefined; + if (source === DeinitSource.SignOut) { + this.bridge.onSignOut(); + } /** Allow our Angular directives to be destroyed and any pending digest cycles * to complete before destroying the global application instance and all its services */ setTimeout(() => { From b1cf0bd515c812e00f23c13f115e307645aace75 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Tue, 23 Mar 2021 18:52:46 +0100 Subject: [PATCH 14/18] fix: use more widely compatible css for sign in/register button margins --- app/assets/templates/directives/account-menu.pug | 16 ++++++++++------ package.json | 2 +- yarn.lock | 4 ++-- 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/app/assets/templates/directives/account-menu.pug b/app/assets/templates/directives/account-menu.pug index 1f797c0ad..65433ea0e 100644 --- a/app/assets/templates/directives/account-menu.pug +++ b/app/assets/templates/directives/account-menu.pug @@ -12,11 +12,15 @@ ) .sk-panel-row .sk-h1 Sign in or register to enable sync and end-to-end encryption. - .flex.gap-3.my-1 - button.sn-button.info.flex-grow.text-base.py-3(ng-click='self.state.formData.showLogin = true') - | Sign In - button.sn-button.info.flex-grow.text-base.py-3(ng-click='self.showRegister()') - | Register + .flex.my-1 + button( + class="sn-button info flex-grow text-base py-3 mr-1.5" + ng-click='self.state.formData.showLogin = true' + ) Sign In + button( + class="sn-button info flex-grow text-base py-3 ml-1.5" + ng-click='self.showRegister()' + ) Register .sk-panel-row.sk-p | Standard Notes is free on every platform, and comes | standard with sync and encryption. @@ -269,7 +273,7 @@ type='file' ) | Import Backup - span(ng-if='self.isDesktopApplication()') + p.mt-5(ng-if='self.isDesktopApplication()') | Backups are automatically created on desktop and can be managed | via the "Backups" top-level menu. .sk-panel-row diff --git a/package.json b/package.json index ccbbd6d7d..29b07be6e 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pug-loader": "^2.4.0", "sass-loader": "^8.0.2", "serve-static": "^1.14.1", - "sn-stylekit": "github:standardnotes/StyleKit#e3bfad37d29168bcc15e96399734ffaae1e618ba", + "sn-stylekit": "github:standardnotes/StyleKit#cc162112a38ea52419ac41cbd375517bd7b8be86", "ts-loader": "^8.0.17", "typescript": "^4.1.5", "typescript-eslint": "0.0.1-alpha.0", diff --git a/yarn.lock b/yarn.lock index f90c27fc2..aea982667 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7808,9 +7808,9 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -"sn-stylekit@github:standardnotes/StyleKit#e3bfad37d29168bcc15e96399734ffaae1e618ba": +"sn-stylekit@github:standardnotes/StyleKit#cc162112a38ea52419ac41cbd375517bd7b8be86": version "3.0.0" - resolved "https://codeload.github.com/standardnotes/StyleKit/tar.gz/e3bfad37d29168bcc15e96399734ffaae1e618ba" + resolved "https://codeload.github.com/standardnotes/StyleKit/tar.gz/cc162112a38ea52419ac41cbd375517bd7b8be86" snapdragon-node@^2.0.1: version "2.1.1" From 7c9b684c834c56f1ab61680792212d1c7b61434a Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Wed, 24 Mar 2021 10:22:55 +0100 Subject: [PATCH 15/18] fix: move onSignOut bridge hook call later in the deinit lifecycle --- app/assets/javascripts/ui_models/application.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/ui_models/application.ts b/app/assets/javascripts/ui_models/application.ts index 131c3055b..07256a10e 100644 --- a/app/assets/javascripts/ui_models/application.ts +++ b/app/assets/javascripts/ui_models/application.ts @@ -91,13 +91,13 @@ export class WebApplication extends SNApplication { this.scope = undefined; (this.openModalComponent as any) = undefined; (this.presentPermissionsDialog as any) = undefined; - if (source === DeinitSource.SignOut) { - this.bridge.onSignOut(); - } /** Allow our Angular directives to be destroyed and any pending digest cycles * to complete before destroying the global application instance and all its services */ setTimeout(() => { super.deinit(source); + if (source === DeinitSource.SignOut) { + this.bridge.onSignOut(); + } }, 0); } From 3111dc4c0be78b1f2b1c5c4140051737cab39c1e Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Wed, 24 Mar 2021 11:53:29 +0100 Subject: [PATCH 16/18] fix: export decrypted backup for desktop in some cases Mainly, when a backup is requested and no protection sources are available. --- .../javascripts/services/desktopManager.ts | 64 +++++++++---------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/app/assets/javascripts/services/desktopManager.ts b/app/assets/javascripts/services/desktopManager.ts index 3587b174c..671663f22 100644 --- a/app/assets/javascripts/services/desktopManager.ts +++ b/app/assets/javascripts/services/desktopManager.ts @@ -7,6 +7,7 @@ import { ApplicationService, ApplicationEvent, removeFromArray, + BackupFile, } from '@standardnotes/snjs'; /* eslint-disable camelcase */ import { WebApplication } from '@/ui_models/application'; @@ -14,33 +15,32 @@ import { WebApplication } from '@/ui_models/application'; import { isDesktopApplication } from '@/utils'; import { Bridge } from './bridge'; -type UpdateObserverCallback = (component: SNComponent) => void -type ComponentActivationCallback = (payload: PurePayload) => void +type UpdateObserverCallback = (component: SNComponent) => void; +type ComponentActivationCallback = (payload: PurePayload) => void; type ComponentActivationObserver = { id: string; callback: ComponentActivationCallback; -} +}; export class DesktopManager extends ApplicationService { - - $rootScope: ng.IRootScopeService - $timeout: ng.ITimeoutService - componentActivationObservers: ComponentActivationObserver[] = [] + $rootScope: ng.IRootScopeService; + $timeout: ng.ITimeoutService; + componentActivationObservers: ComponentActivationObserver[] = []; updateObservers: { callback: UpdateObserverCallback; }[] = []; isDesktop = isDesktopApplication(); - dataLoaded = false - lastSearchedText?: string + dataLoaded = false; + lastSearchedText?: string; private removeComponentObserver?: () => void; constructor( $rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService, application: WebApplication, - private bridge: Bridge, + private bridge: Bridge ) { super(application); this.$rootScope = $rootScope; @@ -74,10 +74,7 @@ export class DesktopManager extends ApplicationService { } getExtServerHost() { - console.assert( - !!this.bridge.extensionsServerHost, - 'extServerHost is null' - ); + console.assert(!!this.bridge.extensionsServerHost, 'extServerHost is null'); return this.bridge.extensionsServerHost; } @@ -97,12 +94,14 @@ export class DesktopManager extends ApplicationService { if (!this.isDesktop) { return; } - Promise.all(components.map((component) => { - return this.convertComponentForTransmission(component); - })).then((payloads) => { + Promise.all( + components.map((component) => { + return this.convertComponentForTransmission(component); + }) + ).then((payloads) => { this.bridge.syncComponents( - payloads.filter(payload => - !payload.errorDecrypting && !payload.waitingForKey + payloads.filter( + (payload) => !payload.errorDecrypting && !payload.waitingForKey ) ); }); @@ -110,7 +109,7 @@ export class DesktopManager extends ApplicationService { registerUpdateObserver(callback: UpdateObserverCallback) { const observer = { - callback: callback + callback: callback, }; this.updateObservers.push(observer); return () => { @@ -153,19 +152,14 @@ export class DesktopManager extends ApplicationService { (m) => { const mutator = m as ComponentMutator; if (error) { - mutator.setAppDataItem( - AppDataField.ComponentInstallError, - error - ); + mutator.setAppDataItem(AppDataField.ComponentInstallError, error); } else { mutator.local_url = componentData.content.local_url; mutator.package_info = componentData.content.package_info; - mutator.setAppDataItem( - AppDataField.ComponentInstallError, - undefined - ); + mutator.setAppDataItem(AppDataField.ComponentInstallError, undefined); } - }); + } + ); this.$timeout(() => { for (const observer of this.updateObservers) { @@ -174,13 +168,17 @@ export class DesktopManager extends ApplicationService { }); } - desktop_registerComponentActivationObserver(callback: ComponentActivationCallback) { + desktop_registerComponentActivationObserver( + callback: ComponentActivationCallback + ) { const observer = { id: `${Math.random}`, callback: callback }; this.componentActivationObservers.push(observer); return observer; } - desktop_deregisterComponentActivationObserver(observer: ComponentActivationObserver) { + desktop_deregisterComponentActivationObserver( + observer: ComponentActivationObserver + ) { removeFromArray(this.componentActivationObservers, observer); } @@ -198,7 +196,9 @@ export class DesktopManager extends ApplicationService { async desktop_requestBackupFile() { const data = await this.application!.createBackupFile( - EncryptionIntent.FileEncrypted + this.application.hasProtectionSources() + ? EncryptionIntent.FileEncrypted + : EncryptionIntent.FileDecrypted ); if (data) { return JSON.stringify(data, null, 2); From fd610d1bf439375daf798e8a8d6a6dc7e0c20c05 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Wed, 24 Mar 2021 17:09:20 +0100 Subject: [PATCH 17/18] chore(deps): update StyleKit --- package.json | 2 +- yarn.lock | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package.json b/package.json index 29b07be6e..80cda2500 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,7 @@ "pug-loader": "^2.4.0", "sass-loader": "^8.0.2", "serve-static": "^1.14.1", - "sn-stylekit": "github:standardnotes/StyleKit#cc162112a38ea52419ac41cbd375517bd7b8be86", + "sn-stylekit": "github:standardnotes/StyleKit#1ec13454cc6d8cf97651263a039de8872be527b8", "ts-loader": "^8.0.17", "typescript": "^4.1.5", "typescript-eslint": "0.0.1-alpha.0", diff --git a/yarn.lock b/yarn.lock index aea982667..b2ccc02d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7808,9 +7808,9 @@ slice-ansi@^4.0.0: astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -"sn-stylekit@github:standardnotes/StyleKit#cc162112a38ea52419ac41cbd375517bd7b8be86": - version "3.0.0" - resolved "https://codeload.github.com/standardnotes/StyleKit/tar.gz/cc162112a38ea52419ac41cbd375517bd7b8be86" +"sn-stylekit@github:standardnotes/StyleKit#1ec13454cc6d8cf97651263a039de8872be527b8": + version "3.0.1" + resolved "https://codeload.github.com/standardnotes/StyleKit/tar.gz/1ec13454cc6d8cf97651263a039de8872be527b8" snapdragon-node@^2.0.1: version "2.1.1" From 07504290af9b7223b0f5b7d9e3a980a56cdc67d1 Mon Sep 17 00:00:00 2001 From: Baptiste Grob <60621355+baptiste-grob@users.noreply.github.com> Date: Thu, 25 Mar 2021 11:04:36 +0100 Subject: [PATCH 18/18] chore(version): 3.6.3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 80cda2500..d2339387d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "standard-notes-web", - "version": "3.6.2", + "version": "3.6.3", "license": "AGPL-3.0-or-later", "repository": { "type": "git",