This commit is contained in:
Mo Bitar
2020-02-08 12:11:04 -06:00
parent 13dd41b9ab
commit f6ef4a39e2
26 changed files with 10885 additions and 2044 deletions

View File

@@ -4,7 +4,7 @@
"rules": { "rules": {
"standard/no-callback-literal": 0, // Disable this as we have too many callbacks relying on literals "standard/no-callback-literal": 0, // Disable this as we have too many callbacks relying on literals
"no-throw-literal": 0, "no-throw-literal": 0,
"no-console": "error", // "no-console": "error",
"semi": 1 "semi": 1
}, },
"env": { "env": {

View File

@@ -54,24 +54,13 @@ import {
import { trusted } from './filters'; import { trusted } from './filters';
import { import {
ActionsManager,
ArchiveManager, ArchiveManager,
AuthManager,
ComponentManager,
DatabaseManager, DatabaseManager,
DesktopManager, DesktopManager,
HttpManager,
KeyboardManager, KeyboardManager,
MigrationManager,
ModelManager,
NativeExtManager, NativeExtManager,
LockManager, LockManager,
PrivilegesManager,
SessionHistory,
SingletonManager,
StatusManager, StatusManager,
StorageManager,
SyncManager,
ThemeManager, ThemeManager,
AlertManager, AlertManager,
PreferencesManager PreferencesManager
@@ -148,23 +137,13 @@ angular
.service('application', Application) .service('application', Application)
.service('appState', AppState) .service('appState', AppState)
.service('preferencesManager', PreferencesManager) .service('preferencesManager', PreferencesManager)
.service('actionsManager', ActionsManager)
.service('archiveManager', ArchiveManager) .service('archiveManager', ArchiveManager)
.service('authManager', AuthManager)
.service('componentManager', ComponentManager)
.service('databaseManager', DatabaseManager) .service('databaseManager', DatabaseManager)
.service('desktopManager', DesktopManager) .service('desktopManager', DesktopManager)
.service('httpManager', HttpManager)
.service('keyboardManager', KeyboardManager) .service('keyboardManager', KeyboardManager)
.service('migrationManager', MigrationManager)
.service('modelManager', ModelManager)
.service('nativeExtManager', NativeExtManager) .service('nativeExtManager', NativeExtManager)
.service('lockManager', LockManager) .service('lockManager', LockManager)
.service('privilegesManager', PrivilegesManager)
.service('sessionHistory', SessionHistory)
.service('singletonManager', SingletonManager)
.service('statusManager', StatusManager) .service('statusManager', StatusManager)
.service('storageManager', StorageManager) .service('storageManager', StorageManager)
.service('syncManager', SyncManager)
.service('alertManager', AlertManager) .service('alertManager', AlertManager)
.service('themeManager', ThemeManager); .service('themeManager', ThemeManager);

View File

@@ -1,11 +1,10 @@
import { import {
SNApplication, SNApplication,
SNAlertManager SNAlertManager,
Platforms, Platforms
Environments
} from 'snjs'; } from 'snjs';
import angular from 'angular'; import angular from 'angular';
import { AlertManager } from '@/services/alertManager' import { AlertManager } from '@/services/alertManager';
import { WebDeviceInterface } from '@/web_device_interface'; import { WebDeviceInterface } from '@/web_device_interface';

View File

@@ -2,37 +2,24 @@ import angular from 'angular';
import { import {
ApplicationEvents, ApplicationEvents,
isPayloadSourceRetrieved, isPayloadSourceRetrieved,
CONTENT_TYPE_NOTE, ContentTypes,
CONTENT_TYPE_TAG,
CONTENT_TYPE_COMPONENT,
ProtectedActions ProtectedActions
} from 'snjs'; } from 'snjs';
import find from 'lodash/find';
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import { KeyboardManager } from '@/services/keyboardManager';
import template from '%/editor.pug'; import template from '%/editor.pug';
import { PureCtrl } from '@Controllers'; import { PureCtrl } from '@Controllers';
import { import { AppStateEvents, EventSources } from '@/state';
APP_STATE_EVENT_NOTE_CHANGED,
APP_STATE_EVENT_PREFERENCES_CHANGED,
EVENT_SOURCE_SCRIPT
} from '@/state';
import { import {
STRING_DELETED_NOTE, STRING_DELETED_NOTE,
STRING_INVALID_NOTE, STRING_INVALID_NOTE,
STRING_ELLIPSES, STRING_ELLIPSES,
STRING_GENERIC_SAVE_ERROR,
STRING_DELETE_PLACEHOLDER_ATTEMPT, STRING_DELETE_PLACEHOLDER_ATTEMPT,
STRING_DELETE_LOCKED_ATTEMPT, STRING_DELETE_LOCKED_ATTEMPT,
StringDeleteNote, StringDeleteNote,
StringEmptyTrash StringEmptyTrash
} from '@/strings'; } from '@/strings';
import { import { PrefKeys } from '@/services/preferencesManager';
PREF_EDITOR_WIDTH,
PREF_EDITOR_LEFT,
PREF_EDITOR_MONOSPACE_ENABLED,
PREF_EDITOR_SPELLCHECK,
PREF_EDITOR_RESIZERS_ENABLED
} from '@/services/preferencesManager';
const NOTE_PREVIEW_CHAR_LIMIT = 80; const NOTE_PREVIEW_CHAR_LIMIT = 80;
const MINIMUM_STATUS_DURATION = 400; const MINIMUM_STATUS_DURATION = 400;
@@ -40,19 +27,23 @@ const SAVE_TIMEOUT_DEBOUNCE = 350;
const SAVE_TIMEOUT_NO_DEBOUNCE = 100; const SAVE_TIMEOUT_NO_DEBOUNCE = 100;
const EDITOR_DEBOUNCE = 200; const EDITOR_DEBOUNCE = 200;
const APP_DATA_KEY_PINNED = 'pinned'; const AppDataKeys = {
const APP_DATA_KEY_LOCKED = 'locked'; Pinned: 'pinned',
const APP_DATA_KEY_ARCHIVED = 'archived'; Locked: 'locked',
const APP_DATA_KEY_PREFERS_PLAIN_EDITOR = 'prefersPlainEditor'; Archived: 'archived',
PrefersPlainEditor: 'prefersPlainEditor'
const ELEMENT_ID_NOTE_TEXT_EDITOR = 'note-text-editor'; };
const ELEMENT_ID_NOTE_TITLE_EDITOR = 'note-title-editor'; const ElementIds = {
const ELEMENT_ID_EDITOR_CONTENT = 'editor-content'; NoteTextEditor: 'note-text-editor',
const ELEMENT_ID_NOTE_TAGS_COMPONENT_CONTAINER = 'note-tags-component-container'; NoteTitleEditor: 'note-title-editor',
EditorContent: 'editor-content',
const DESKTOP_MONOSPACE_FAMILY = `Menlo,Consolas,'DejaVu Sans Mono',monospace`; NoteTagsComponentContainer: 'note-tags-component-container'
const WEB_MONOSPACE_FAMILY = `monospace`; };
const SANS_SERIF_FAMILY = `inherit`; const Fonts = {
DesktopMonospaceFamily: `Menlo,Consolas,'DejaVu Sans Mono',monospace`,
WebMonospaceFamily: `monospace`,
SansSerifFamily: `inherit`
};
class EditorCtrl extends PureCtrl { class EditorCtrl extends PureCtrl {
/* @ngInject */ /* @ngInject */
@@ -61,17 +52,14 @@ class EditorCtrl extends PureCtrl {
$rootScope, $rootScope,
appState, appState,
application, application,
actionsManager,
desktopManager, desktopManager,
keyboardManager, keyboardManager,
preferencesManager, preferencesManager,
sessionHistory /** Unused below, required to load globally */
) { ) {
super($timeout); super($timeout);
this.$rootScope = $rootScope; this.$rootScope = $rootScope;
this.application = application; this.application = application;
this.appState = appState; this.appState = appState;
this.actionsManager = actionsManager;
this.desktopManager = desktopManager; this.desktopManager = desktopManager;
this.keyboardManager = keyboardManager; this.keyboardManager = keyboardManager;
this.preferencesManager = preferencesManager; this.preferencesManager = preferencesManager;
@@ -97,19 +85,19 @@ class EditorCtrl extends PureCtrl {
this.registerKeyboardShortcuts(); this.registerKeyboardShortcuts();
/** Used by .pug template */ /** Used by .pug template */
this.prefKeyMonospace = PREF_EDITOR_MONOSPACE_ENABLED; this.prefKeyMonospace = PrefKeys.EditorMonospaceEnabled;
this.prefKeySpellcheck = PREF_EDITOR_SPELLCHECK; this.prefKeySpellcheck = PrefKeys.EditorSpellcheck;
this.prefKeyMarginResizers = PREF_EDITOR_RESIZERS_ENABLED; this.prefKeyMarginResizers = PrefKeys.EditorResizersEnabled;
} }
addAppStateObserver() { addAppStateObserver() {
this.appState.addObserver((eventName, data) => { this.appState.addObserver((eventName, data) => {
if (eventName === APP_STATE_EVENT_NOTE_CHANGED) { if (eventName === AppStateEvents.NoteChanged) {
this.handleNoteSelectionChange( this.handleNoteSelectionChange(
this.appState.getSelectedNote(), this.appState.getSelectedNote(),
data.previousNote data.previousNote
); );
} else if (eventName === APP_STATE_EVENT_PREFERENCES_CHANGED) { } else if (eventName === AppStateEvents.PreferencesChanged) {
this.loadPreferences(); this.loadPreferences();
} }
}); });
@@ -117,7 +105,7 @@ class EditorCtrl extends PureCtrl {
streamItems() { streamItems() {
this.application.streamItems({ this.application.streamItems({
contentType: CONTENT_TYPE_NOTE, contentType: ContentTypes.Note,
stream: async ({ items, source }) => { stream: async ({ items, source }) => {
if (!this.state.note) { if (!this.state.note) {
return; return;
@@ -139,7 +127,7 @@ class EditorCtrl extends PureCtrl {
}); });
this.application.streamItems({ this.application.streamItems({
contentType: CONTENT_TYPE_TAG, contentType: ContentTypes.Tag,
stream: async ({ items, source }) => { stream: async ({ items, source }) => {
if (!this.state.note) { if (!this.state.note) {
return; return;
@@ -158,7 +146,7 @@ class EditorCtrl extends PureCtrl {
}); });
this.application.streamItems({ this.application.streamItems({
contentType: CONTENT_TYPE_COMPONENT, contentType: ContentTypes.Component,
stream: async ({ items, source }) => { stream: async ({ items, source }) => {
if (!this.state.note) { if (!this.state.note) {
return; return;
@@ -267,7 +255,7 @@ class EditorCtrl extends PureCtrl {
addSyncStatusObserver() { addSyncStatusObserver() {
/** @todo */ /** @todo */
// this.syncStatusObserver = this.syncManager. // this.syncStatusObserver = syncManager.
// registerSyncStatusObserver((status) => { // registerSyncStatusObserver((status) => {
// if (status.localError) { // if (status.localError) {
// this.$timeout(() => { // this.$timeout(() => {
@@ -321,11 +309,11 @@ class EditorCtrl extends PureCtrl {
} }
if (editor) { if (editor) {
const prefersPlain = this.state.note.getAppDataItem( const prefersPlain = this.state.note.getAppDataItem(
APP_DATA_KEY_PREFERS_PLAIN_EDITOR AppDataKeys.PrefersPlainEditor
) === true; ) === true;
if (prefersPlain) { if (prefersPlain) {
this.state.note.setAppDataItem( this.state.note.setAppDataItem(
APP_DATA_KEY_PREFERS_PLAIN_EDITOR, AppDataKeys.PrefersPlainEditor,
false false
); );
this.application.setItemNeedsSync({ item: this.state.note }); this.application.setItemNeedsSync({ item: this.state.note });
@@ -333,9 +321,9 @@ class EditorCtrl extends PureCtrl {
this.associateComponentWithCurrentNote(editor); this.associateComponentWithCurrentNote(editor);
} else { } else {
/** Note prefers plain editor */ /** Note prefers plain editor */
if (!this.state.note.getAppDataItem(APP_DATA_KEY_PREFERS_PLAIN_EDITOR)) { if (!this.state.note.getAppDataItem(AppDataKeys.PrefersPlainEditor)) {
this.state.note.setAppDataItem( this.state.note.setAppDataItem(
APP_DATA_KEY_PREFERS_PLAIN_EDITOR, AppDataKeys.PrefersPlainEditor,
true true
); );
this.application.setItemNeedsSync({ item: this.state.note }); this.application.setItemNeedsSync({ item: this.state.note });
@@ -356,7 +344,7 @@ class EditorCtrl extends PureCtrl {
} }
hasAvailableExtensions() { hasAvailableExtensions() {
return this.actionsManager.extensionsInContextOfItem(this.state.note).length > 0; return this.application.actionsManager.extensionsInContextOfItem(this.state.note).length > 0;
} }
performFirefoxPinnedTabFix() { performFirefoxPinnedTabFix() {
@@ -494,15 +482,15 @@ class EditorCtrl extends PureCtrl {
} }
focusEditor() { focusEditor() {
const element = document.getElementById(ELEMENT_ID_NOTE_TEXT_EDITOR); const element = document.getElementById(ElementIds.NoteTextEditor);
if (element) { if (element) {
this.lastEditorFocusEventSource = EVENT_SOURCE_SCRIPT; this.lastEditorFocusEventSource = EventSources.Script;
element.focus(); element.focus();
} }
} }
focusTitle() { focusTitle() {
document.getElementById(ELEMENT_ID_NOTE_TITLE_EDITOR).focus(); document.getElementById(ElementIds.NoteTitleEditor).focus();
} }
clickedTextArea() { clickedTextArea() {
@@ -627,7 +615,7 @@ class EditorCtrl extends PureCtrl {
togglePin() { togglePin() {
this.state.note.setAppDataItem( this.state.note.setAppDataItem(
APP_DATA_KEY_PINNED, AppDataKeys.Pinned,
!this.state.note.pinned !this.state.note.pinned
); );
this.saveNote({ this.saveNote({
@@ -638,7 +626,7 @@ class EditorCtrl extends PureCtrl {
toggleLockNote() { toggleLockNote() {
this.state.note.setAppDataItem( this.state.note.setAppDataItem(
APP_DATA_KEY_LOCKED, AppDataKeys.Locked,
!this.state.note.locked !this.state.note.locked
); );
this.saveNote({ this.saveNote({
@@ -674,7 +662,7 @@ class EditorCtrl extends PureCtrl {
toggleArchiveNote() { toggleArchiveNote() {
this.state.note.setAppDataItem( this.state.note.setAppDataItem(
APP_DATA_KEY_ARCHIVED, AppDataKeys.Archived,
!this.state.note.archived !this.state.note.archived
); );
this.saveNote({ this.saveNote({
@@ -734,7 +722,7 @@ class EditorCtrl extends PureCtrl {
this.application.setItemsNeedsSync({ items: toRemove }); this.application.setItemsNeedsSync({ items: toRemove });
const tags = []; const tags = [];
for (const tagString of strings) { for (const tagString of strings) {
const existingRelationship = _.find( const existingRelationship = find(
this.state.note.tags, this.state.note.tags,
{ title: tagString } { title: tagString }
); );
@@ -754,13 +742,13 @@ class EditorCtrl extends PureCtrl {
onPanelResizeFinish = (width, left, isMaxWidth) => { onPanelResizeFinish = (width, left, isMaxWidth) => {
if (isMaxWidth) { if (isMaxWidth) {
this.preferencesManager.setUserPrefValue( this.preferencesManager.setUserPrefValue(
PREF_EDITOR_WIDTH, PrefKeys.EditorWidth,
null null
); );
} else { } else {
if (width !== undefined && width !== null) { if (width !== undefined && width !== null) {
this.preferencesManager.setUserPrefValue( this.preferencesManager.setUserPrefValue(
PREF_EDITOR_WIDTH, PrefKeys.EditorWidth,
width width
); );
this.leftResizeControl.setWidth(width); this.leftResizeControl.setWidth(width);
@@ -768,7 +756,7 @@ class EditorCtrl extends PureCtrl {
} }
if (left !== undefined && left !== null) { if (left !== undefined && left !== null) {
this.preferencesManager.setUserPrefValue( this.preferencesManager.setUserPrefValue(
PREF_EDITOR_LEFT, PrefKeys.EditorLeft,
left left
); );
this.rightResizeControl.setLeft(left); this.rightResizeControl.setLeft(left);
@@ -778,15 +766,15 @@ class EditorCtrl extends PureCtrl {
loadPreferences() { loadPreferences() {
const monospaceEnabled = this.preferencesManager.getValue( const monospaceEnabled = this.preferencesManager.getValue(
PREF_EDITOR_MONOSPACE_ENABLED, PrefKeys.EditorMonospaceEnabled,
true true
); );
const spellcheck = this.preferencesManager.getValue( const spellcheck = this.preferencesManager.getValue(
PREF_EDITOR_SPELLCHECK, PrefKeys.EditorSpellcheck,
true true
); );
const marginResizersEnabled = this.preferencesManager.getValue( const marginResizersEnabled = this.preferencesManager.getValue(
PREF_EDITOR_RESIZERS_ENABLED, PrefKeys.EditorResizersEnabled,
true true
); );
this.setState({ this.setState({
@@ -795,7 +783,7 @@ class EditorCtrl extends PureCtrl {
marginResizersEnabled marginResizersEnabled
}); });
if (!document.getElementById(ELEMENT_ID_EDITOR_CONTENT)) { if (!document.getElementById(ElementIds.EditorContent)) {
/** Elements have not yet loaded due to ng-if around wrapper */ /** Elements have not yet loaded due to ng-if around wrapper */
return; return;
} }
@@ -804,7 +792,7 @@ class EditorCtrl extends PureCtrl {
if (this.state.marginResizersEnabled) { if (this.state.marginResizersEnabled) {
const width = this.preferencesManager.getValue( const width = this.preferencesManager.getValue(
PREF_EDITOR_WIDTH, PrefKeys.EditorWidth,
null null
); );
if (width != null) { if (width != null) {
@@ -812,7 +800,7 @@ class EditorCtrl extends PureCtrl {
this.rightResizeControl.setWidth(width); this.rightResizeControl.setWidth(width);
} }
const left = this.preferencesManager.getValue( const left = this.preferencesManager.getValue(
PREF_EDITOR_LEFT, PrefKeys.EditorLeft,
null null
); );
if (left != null) { if (left != null) {
@@ -824,19 +812,19 @@ class EditorCtrl extends PureCtrl {
reloadFont() { reloadFont() {
const editor = document.getElementById( const editor = document.getElementById(
ELEMENT_ID_NOTE_TEXT_EDITOR ElementIds.NoteTextEditor
); );
if (!editor) { if (!editor) {
return; return;
} }
if (this.state.monospaceEnabled) { if (this.state.monospaceEnabled) {
if (this.state.isDesktop) { if (this.state.isDesktop) {
editor.style.fontFamily = DESKTOP_MONOSPACE_FAMILY; editor.style.fontFamily = Fonts.DesktopMonospaceFamily;
} else { } else {
editor.style.fontFamily = WEB_MONOSPACE_FAMILY; editor.style.fontFamily = Fonts.WebMonospaceFamily;
} }
} else { } else {
editor.style.fontFamily = SANS_SERIF_FAMILY; editor.style.fontFamily = Fonts.SansSerifFamily;
} }
} }
@@ -849,7 +837,7 @@ class EditorCtrl extends PureCtrl {
); );
this.reloadFont(); this.reloadFont();
if (key === PREF_EDITOR_SPELLCHECK) { if (key === PrefKeys.EditorSpellcheck) {
/** Allows textarea to reload */ /** Allows textarea to reload */
await this.setState({ await this.setState({
noteReady: false noteReady: false
@@ -858,7 +846,7 @@ class EditorCtrl extends PureCtrl {
noteReady: true noteReady: true
}); });
this.reloadFont(); this.reloadFont();
} else if (key === PREF_EDITOR_RESIZERS_ENABLED && this[key] === true) { } else if (key === PrefKeys.EditorResizersEnabled && this[key] === true) {
this.$timeout(() => { this.$timeout(() => {
this.leftResizeControl.flash(); this.leftResizeControl.flash();
this.rightResizeControl.flash(); this.rightResizeControl.flash();
@@ -956,7 +944,7 @@ class EditorCtrl extends PureCtrl {
if (data.type === 'container') { if (data.type === 'container') {
if (component.area === 'note-tags') { if (component.area === 'note-tags') {
const container = document.getElementById( const container = document.getElementById(
ELEMENT_ID_NOTE_TAGS_COMPONENT_CONTAINER ElementIds.NoteTagsComponentContainer
); );
setSize(container, data); setSize(container, data);
} }
@@ -1055,7 +1043,7 @@ class EditorCtrl extends PureCtrl {
registerKeyboardShortcuts() { registerKeyboardShortcuts() {
this.altKeyObserver = this.keyboardManager.addKeyObserver({ this.altKeyObserver = this.keyboardManager.addKeyObserver({
modifiers: [ modifiers: [
KeyboardManager.KeyModifierAlt KeyboardModifiers.Alt
], ],
onKeyDown: () => { onKeyDown: () => {
this.setState({ this.setState({
@@ -1070,23 +1058,23 @@ class EditorCtrl extends PureCtrl {
}); });
this.trashKeyObserver = this.keyboardManager.addKeyObserver({ this.trashKeyObserver = this.keyboardManager.addKeyObserver({
key: KeyboardManager.KeyBackspace, key: KeyboardKeys.Backspace,
notElementIds: [ notElementIds: [
ELEMENT_ID_NOTE_TEXT_EDITOR, ElementIds.NoteTextEditor,
ELEMENT_ID_NOTE_TITLE_EDITOR ElementIds.NoteTitleEditor
], ],
modifiers: [KeyboardManager.KeyModifierMeta], modifiers: [KeyboardModifiers.Meta],
onKeyDown: () => { onKeyDown: () => {
this.deleteNote(); this.deleteNote();
}, },
}); });
this.deleteKeyObserver = this.keyboardManager.addKeyObserver({ this.deleteKeyObserver = this.keyboardManager.addKeyObserver({
key: KeyboardManager.KeyBackspace, key: KeyboardKeys.Backspace,
modifiers: [ modifiers: [
KeyboardManager.KeyModifierMeta, KeyboardModifiers.Meta,
KeyboardManager.KeyModifierShift, KeyboardModifiers.Shift,
KeyboardManager.KeyModifierAlt KeyboardModifiers.Alt
], ],
onKeyDown: (event) => { onKeyDown: (event) => {
event.preventDefault(); event.preventDefault();
@@ -1107,11 +1095,11 @@ class EditorCtrl extends PureCtrl {
* not fired. * not fired.
*/ */
const editor = document.getElementById( const editor = document.getElementById(
ELEMENT_ID_NOTE_TEXT_EDITOR ElementIds.NoteTextEditor
); );
this.tabObserver = this.keyboardManager.addKeyObserver({ this.tabObserver = this.keyboardManager.addKeyObserver({
element: editor, element: editor,
key: KeyboardManager.KeyTab, key: KeyboardKeys.Tab,
onKeyDown: (event) => { onKeyDown: (event) => {
if (this.state.note.locked || event.shiftKey) { if (this.state.note.locked || event.shiftKey) {
return; return;

View File

@@ -2,15 +2,11 @@ import { dateToLocalizedString } from '@/utils';
import { import {
ApplicationEvents, ApplicationEvents,
TIMING_STRATEGY_FORCE_SPAWN_NEW, TIMING_STRATEGY_FORCE_SPAWN_NEW,
ProtectedActions ProtectedActions,
ContentTypes
} from 'snjs'; } from 'snjs';
import template from '%/footer.pug'; import template from '%/footer.pug';
import { import { AppStateEvents, EventSources } from '@/state';
APP_STATE_EVENT_EDITOR_FOCUSED,
APP_STATE_EVENT_BEGAN_BACKUP_DOWNLOAD,
APP_STATE_EVENT_ENDED_BACKUP_DOWNLOAD,
EVENT_SOURCE_USER_INTERACTION
} from '@/state';
import { import {
STRING_GENERIC_SYNC_ERROR, STRING_GENERIC_SYNC_ERROR,
STRING_NEW_UPDATE_READY STRING_NEW_UPDATE_READY
@@ -74,16 +70,16 @@ class FooterCtrl {
addAppStateObserver() { addAppStateObserver() {
this.appState.addObserver((eventName, data) => { this.appState.addObserver((eventName, data) => {
if(eventName === APP_STATE_EVENT_EDITOR_FOCUSED) { if(eventName === AppStateEvents.EditorFocused) {
if (data.eventSource === EVENT_SOURCE_USER_INTERACTION) { if (data.eventSource === EventSources.UserInteraction) {
this.closeAllRooms(); this.closeAllRooms();
this.closeAccountMenu(); this.closeAccountMenu();
} }
} else if(eventName === APP_STATE_EVENT_BEGAN_BACKUP_DOWNLOAD) { } else if(eventName === AppStateEvents.BeganBackupDownload) {
this.backupStatus = this.statusManager.addStatusFromString( this.backupStatus = this.statusManager.addStatusFromString(
"Saving local backup..." "Saving local backup..."
); );
} else if(eventName === APP_STATE_EVENT_ENDED_BACKUP_DOWNLOAD) { } else if(eventName === AppStateEvents.EndedBackupDownload) {
if(data.success) { if(data.success) {
this.backupStatus = this.statusManager.replaceStatusWithString( this.backupStatus = this.statusManager.replaceStatusWithString(
this.backupStatus, this.backupStatus,
@@ -125,10 +121,10 @@ class FooterCtrl {
streamItems() { streamItems() {
this.application.streamItems({ this.application.streamItems({
contentType: CONTENT_TYPE_COMPONENT, contentType: ContentTypes.Component,
stream: async () => { stream: async () => {
this.rooms = this.application.getItems({ this.rooms = this.application.getItems({
contentType: CONTENT_TYPE_COMPONENT contentType: ContentTypes.Component
}).filter((candidate) => { }).filter((candidate) => {
return candidate.area === 'rooms' && !candidate.deleted; return candidate.area === 'rooms' && !candidate.deleted;
}); });
@@ -143,7 +139,7 @@ class FooterCtrl {
contentType: 'SN|Theme', contentType: 'SN|Theme',
stream: async () => { stream: async () => {
const themes = this.application.getDisplayableItems({ const themes = this.application.getDisplayableItems({
contentType: CONTENT_TYPE_THEME contentType: ContentTypes.Theme
}).filter((candidate) => { }).filter((candidate) => {
return ( return (
!candidate.deleted && !candidate.deleted &&
@@ -159,7 +155,7 @@ class FooterCtrl {
this.reloadDockShortcuts(); this.reloadDockShortcuts();
} }
} }
); });
} }
registerComponentHandler() { registerComponentHandler() {

View File

@@ -1,21 +1,16 @@
import template from '%/lock-screen.pug'; import template from '%/lock-screen.pug';
import { import { AppStateEvents } from '@/state';
APP_STATE_EVENT_WINDOW_DID_FOCUS
} from '@/state';
const ELEMENT_ID_PASSCODE_INPUT = 'passcode-input'; const ELEMENT_ID_PASSCODE_INPUT = 'passcode-input';
class LockScreenCtrl { class LockScreenCtrl {
/* @ngInject */ /* @ngInject */
constructor( constructor(
$scope, $scope,
alertManager,
application, application,
appState appState
) { ) {
this.$scope = $scope; this.$scope = $scope;
this.alertManager = alertManager;
this.application = application; this.application = application;
this.appState = appState; this.appState = appState;
this.formData = {}; this.formData = {};
@@ -37,7 +32,7 @@ class LockScreenCtrl {
addVisibilityObserver() { addVisibilityObserver() {
this.unregisterObserver = this.appState.addObserver((eventName, data) => { this.unregisterObserver = this.appState.addObserver((eventName, data) => {
if (eventName === APP_STATE_EVENT_WINDOW_DID_FOCUS) { if (eventName === AppStateEvents.WindowDidFocus) {
const input = this.passcodeInput; const input = this.passcodeInput;
if(input) { if(input) {
input.focus(); input.focus();
@@ -56,7 +51,7 @@ class LockScreenCtrl {
this.passcodeInput.blur(); this.passcodeInput.blur();
const success = await this.onValue()(this.formData.passcode); const success = await this.onValue()(this.formData.passcode);
if(!success) { if(!success) {
this.alertManager.alert({ this.application.alertManager.alert({
text: "Invalid passcode. Please try again.", text: "Invalid passcode. Please try again.",
onClose: () => { onClose: () => {
this.passcodeInput.focus(); this.passcodeInput.focus();
@@ -70,7 +65,7 @@ class LockScreenCtrl {
} }
beginDeleteData() { beginDeleteData() {
this.alertManager.confirm({ this.application.alertManager.confirm({
text: "Are you sure you want to clear all local data?", text: "Are you sure you want to clear all local data?",
destructive: true, destructive: true,
onConfirm: async () => { onConfirm: async () => {

View File

@@ -1,24 +1,11 @@
import _ from 'lodash'; import _ from 'lodash';
import angular from 'angular'; import angular from 'angular';
import template from '%/notes.pug'; import template from '%/notes.pug';
import { ApplicationEvents, CONTENT_TYPE_NOTE, CONTENT_TYPE_TAG } from 'snjs'; import { ApplicationEvents, ContentTypes } from 'snjs';
import { KeyboardManager } from '@/services/keyboardManager';
import { PureCtrl } from '@Controllers'; import { PureCtrl } from '@Controllers';
import { AppStateEvents } from '@/state';
import { import {
APP_STATE_EVENT_NOTE_CHANGED, PrefKeys
APP_STATE_EVENT_TAG_CHANGED,
APP_STATE_EVENT_PREFERENCES_CHANGED,
APP_STATE_EVENT_EDITOR_FOCUSED
} from '@/state';
import {
PREF_NOTES_PANEL_WIDTH,
PREF_SORT_NOTES_BY,
PREF_SORT_NOTES_REVERSE,
PREF_NOTES_SHOW_ARCHIVED,
PREF_NOTES_HIDE_PINNED,
PREF_NOTES_HIDE_NOTE_PREVIEW,
PREF_NOTES_HIDE_DATE,
PREF_NOTES_HIDE_TAGS
} from '@/services/preferencesManager'; } from '@/services/preferencesManager';
import { import {
PANEL_NAME_NOTES PANEL_NAME_NOTES
@@ -37,8 +24,6 @@ import {
*/ */
const MIN_NOTE_CELL_HEIGHT = 51.0; const MIN_NOTE_CELL_HEIGHT = 51.0;
const DEFAULT_LIST_NUM_NOTES = 20; const DEFAULT_LIST_NUM_NOTES = 20;
const ELEMENT_ID_SEARCH_BAR = 'search-bar'; const ELEMENT_ID_SEARCH_BAR = 'search-bar';
const ELEMENT_ID_SCROLL_CONTAINER = 'notes-scrollable'; const ELEMENT_ID_SCROLL_CONTAINER = 'notes-scrollable';
@@ -96,14 +81,14 @@ class NotesCtrl extends PureCtrl {
addAppStateObserver() { addAppStateObserver() {
this.appState.addObserver((eventName, data) => { this.appState.addObserver((eventName, data) => {
if (eventName === APP_STATE_EVENT_TAG_CHANGED) { if (eventName === AppStateEvents.TagChanged) {
this.handleTagChange(this.appState.getSelectedTag(), data.previousTag); this.handleTagChange(this.appState.getSelectedTag(), data.previousTag);
} else if (eventName === APP_STATE_EVENT_NOTE_CHANGED) { } else if (eventName === AppStateEvents.NoteChanged) {
this.handleNoteSelection(this.appState.getSelectedNote()); this.handleNoteSelection(this.appState.getSelectedNote());
} else if (eventName === APP_STATE_EVENT_PREFERENCES_CHANGED) { } else if (eventName === AppStateEvents.PreferencesChanged) {
this.reloadPreferences(); this.reloadPreferences();
this.reloadNotes(); this.reloadNotes();
} else if (eventName === APP_STATE_EVENT_EDITOR_FOCUSED) { } else if (eventName === AppStateEvents.EditorFocused) {
this.setShowMenuFalse(); this.setShowMenuFalse();
} }
}); });
@@ -140,7 +125,7 @@ class NotesCtrl extends PureCtrl {
streamNotesAndTags() { streamNotesAndTags() {
this.application.streamItems({ this.application.streamItems({
contentType: [CONTENT_TYPE_NOTE, CONTENT_TYPE_TAG], contentType: [ContentTypes.Note, ContentTypes.Tag],
stream: async ({ items }) => { stream: async ({ items }) => {
await this.reloadNotes(); await this.reloadNotes();
const selectedNote = this.state.selectedNote; const selectedNote = this.state.selectedNote;
@@ -155,7 +140,7 @@ class NotesCtrl extends PureCtrl {
} }
/** Note has changed values, reset its flags */ /** Note has changed values, reset its flags */
const notes = items.filter((item) => item.content_type === CONTENT_TYPE_NOTE); const notes = items.filter((item) => item.content_type === ContentTypes.Note);
for (const note of notes) { for (const note of notes) {
this.loadFlagsForNote(note); this.loadFlagsForNote(note);
note.cachedCreatedAtString = note.createdAtString(); note.cachedCreatedAtString = note.createdAtString();
@@ -290,7 +275,7 @@ class NotesCtrl extends PureCtrl {
const viewOptions = {}; const viewOptions = {};
const prevSortValue = this.state.sortBy; const prevSortValue = this.state.sortBy;
let sortBy = this.preferencesManager.getValue( let sortBy = this.preferencesManager.getValue(
PREF_SORT_NOTES_BY, PrefKeys.SortNotesBy,
SORT_KEY_CREATED_AT SORT_KEY_CREATED_AT
); );
if (sortBy === SORT_KEY_UPDATED_AT) { if (sortBy === SORT_KEY_UPDATED_AT) {
@@ -299,27 +284,27 @@ class NotesCtrl extends PureCtrl {
} }
viewOptions.sortBy = sortBy; viewOptions.sortBy = sortBy;
viewOptions.sortReverse = this.preferencesManager.getValue( viewOptions.sortReverse = this.preferencesManager.getValue(
PREF_SORT_NOTES_REVERSE, PrefKeys.SortNotesReverse,
false false
); );
viewOptions.showArchived = this.preferencesManager.getValue( viewOptions.showArchived = this.preferencesManager.getValue(
PREF_NOTES_SHOW_ARCHIVED, PrefKeys.NotesShowArchived,
false false
); );
viewOptions.hidePinned = this.preferencesManager.getValue( viewOptions.hidePinned = this.preferencesManager.getValue(
PREF_NOTES_HIDE_PINNED, PrefKeys.NotesHidePinned,
false false
); );
viewOptions.hideNotePreview = this.preferencesManager.getValue( viewOptions.hideNotePreview = this.preferencesManager.getValue(
PREF_NOTES_HIDE_NOTE_PREVIEW, PrefKeys.NotesHideNotePreview,
false false
); );
viewOptions.hideDate = this.preferencesManager.getValue( viewOptions.hideDate = this.preferencesManager.getValue(
PREF_NOTES_HIDE_DATE, PrefKeys.NotesHideDate,
false false
); );
viewOptions.hideTags = this.preferencesManager.getValue( viewOptions.hideTags = this.preferencesManager.getValue(
PREF_NOTES_HIDE_TAGS, PrefKeys.NotesHideTags,
false false
); );
this.setState({ this.setState({
@@ -329,7 +314,7 @@ class NotesCtrl extends PureCtrl {
this.selectFirstNote(); this.selectFirstNote();
} }
const width = this.preferencesManager.getValue( const width = this.preferencesManager.getValue(
PREF_NOTES_PANEL_WIDTH PrefKeys.NotesPanelWidth
); );
if (width) { if (width) {
this.panelController.setWidth(width); this.panelController.setWidth(width);
@@ -344,7 +329,7 @@ class NotesCtrl extends PureCtrl {
onPanelResize = (newWidth, lastLeft, isAtMaxWidth, isCollapsed) => { onPanelResize = (newWidth, lastLeft, isAtMaxWidth, isCollapsed) => {
this.preferencesManager.setUserPrefValue( this.preferencesManager.setUserPrefValue(
PREF_NOTES_PANEL_WIDTH, PrefKeys.NotesPanelWidth,
newWidth newWidth
); );
this.preferencesManager.syncUserPreferences(); this.preferencesManager.syncUserPreferences();
@@ -523,7 +508,7 @@ class NotesCtrl extends PureCtrl {
} }
const title = "Note" + (this.state.notes ? (" " + (this.state.notes.length + 1)) : ""); const title = "Note" + (this.state.notes ? (" " + (this.state.notes.length + 1)) : "");
const newNote = this.application.createItem({ const newNote = this.application.createItem({
contentType: CONTENT_TYPE_NOTE, contentType: ContentTypes.Note,
content: { content: {
text: '', text: '',
title: title title: title
@@ -605,7 +590,7 @@ class NotesCtrl extends PureCtrl {
toggleReverseSort() { toggleReverseSort() {
this.selectedMenuItem(); this.selectedMenuItem();
this.preferencesManager.setUserPrefValue( this.preferencesManager.setUserPrefValue(
PREF_SORT_NOTES_REVERSE, PrefKeys.SortNotesReverse,
!this.state.sortReverse !this.state.sortReverse
); );
this.preferencesManager.syncUserPreferences(); this.preferencesManager.syncUserPreferences();
@@ -613,7 +598,7 @@ class NotesCtrl extends PureCtrl {
setSortBy(type) { setSortBy(type) {
this.preferencesManager.setUserPrefValue( this.preferencesManager.setUserPrefValue(
PREF_SORT_NOTES_BY, PrefKeys.SortNotesBy,
type type
); );
this.preferencesManager.syncUserPreferences(); this.preferencesManager.syncUserPreferences();
@@ -649,8 +634,8 @@ class NotesCtrl extends PureCtrl {
this.newNoteKeyObserver = this.keyboardManager.addKeyObserver({ this.newNoteKeyObserver = this.keyboardManager.addKeyObserver({
key: 'n', key: 'n',
modifiers: [ modifiers: [
KeyboardManager.KeyModifierMeta, KeyboardModifiers.Meta,
KeyboardManager.KeyModifierCtrl KeyboardModifiers.Ctrl
], ],
onKeyDown: (event) => { onKeyDown: (event) => {
event.preventDefault(); event.preventDefault();
@@ -659,7 +644,7 @@ class NotesCtrl extends PureCtrl {
}); });
this.nextNoteKeyObserver = this.keyboardManager.addKeyObserver({ this.nextNoteKeyObserver = this.keyboardManager.addKeyObserver({
key: KeyboardManager.KeyDown, key: KeyboardKeys.Down,
elements: [ elements: [
document.body, document.body,
this.getSearchBar() this.getSearchBar()
@@ -674,7 +659,7 @@ class NotesCtrl extends PureCtrl {
}); });
this.nextNoteKeyObserver = this.keyboardManager.addKeyObserver({ this.nextNoteKeyObserver = this.keyboardManager.addKeyObserver({
key: KeyboardManager.KeyUp, key: KeyboardKeys.Up,
element: document.body, element: document.body,
onKeyDown: (event) => { onKeyDown: (event) => {
this.selectPreviousNote(); this.selectPreviousNote();
@@ -684,8 +669,8 @@ class NotesCtrl extends PureCtrl {
this.searchKeyObserver = this.keyboardManager.addKeyObserver({ this.searchKeyObserver = this.keyboardManager.addKeyObserver({
key: "f", key: "f",
modifiers: [ modifiers: [
KeyboardManager.KeyModifierMeta, KeyboardModifiers.Meta,
KeyboardManager.KeyModifierShift KeyboardModifiers.Shift
], ],
onKeyDown: (event) => { onKeyDown: (event) => {
const searchBar = this.getSearchBar(); const searchBar = this.getSearchBar();

View File

@@ -2,10 +2,7 @@ import _ from 'lodash';
import { Challenges } from 'snjs'; import { Challenges } from 'snjs';
import { getPlatformString } from '@/utils'; import { getPlatformString } from '@/utils';
import template from '%/root.pug'; import template from '%/root.pug';
import { import { AppStateEvents } from '@/state';
APP_STATE_EVENT_PANEL_RESIZED,
APP_STATE_EVENT_WINDOW_DID_FOCUS
} from '@/state';
import { import {
PANEL_NAME_NOTES, PANEL_NAME_NOTES,
PANEL_NAME_TAGS PANEL_NAME_TAGS
@@ -15,6 +12,7 @@ import {
STRING_DEFAULT_FILE_ERROR, STRING_DEFAULT_FILE_ERROR,
StringSyncException StringSyncException
} from '@/strings'; } from '@/strings';
import { PureCtrl } from './abstract/pure_ctrl';
class RootCtrl extends PureCtrl { class RootCtrl extends PureCtrl {
/* @ngInject */ /* @ngInject */
@@ -45,7 +43,6 @@ class RootCtrl extends PureCtrl {
needsUnlock: false, needsUnlock: false,
appClass: '' appClass: ''
}; };
this.loadApplication(); this.loadApplication();
this.handleAutoSignInFromParams(); this.handleAutoSignInFromParams();
this.addAppStateObserver(); this.addAppStateObserver();
@@ -53,7 +50,7 @@ class RootCtrl extends PureCtrl {
} }
async loadApplication() { async loadApplication() {
this.application.prepareForLaunch({ await this.application.prepareForLaunch({
callbacks: { callbacks: {
authChallengeResponses: async (challenges) => { authChallengeResponses: async (challenges) => {
if (challenges.includes(Challenges.LocalPasscode)) { if (challenges.includes(Challenges.LocalPasscode)) {
@@ -65,7 +62,7 @@ class RootCtrl extends PureCtrl {
await this.application.launch(); await this.application.launch();
this.setState({ needsUnlock: false }); this.setState({ needsUnlock: false });
await this.openDatabase(); await this.openDatabase();
this.preferencesManager.load(); await this.preferencesManager.initialize();
this.addSyncStatusObserver(); this.addSyncStatusObserver();
this.addSyncEventHandler(); this.addSyncEventHandler();
} }
@@ -76,7 +73,7 @@ class RootCtrl extends PureCtrl {
addAppStateObserver() { addAppStateObserver() {
this.appState.addObserver(async (eventName, data) => { this.appState.addObserver(async (eventName, data) => {
if (eventName === APP_STATE_EVENT_PANEL_RESIZED) { if (eventName === AppStateEvents.PanelResized) {
if (data.panel === PANEL_NAME_NOTES) { if (data.panel === PANEL_NAME_NOTES) {
this.notesCollapsed = data.collapsed; this.notesCollapsed = data.collapsed;
} }
@@ -87,7 +84,7 @@ class RootCtrl extends PureCtrl {
if (this.notesCollapsed) { appClass += "collapsed-notes"; } if (this.notesCollapsed) { appClass += "collapsed-notes"; }
if (this.tagsCollapsed) { appClass += " collapsed-tags"; } if (this.tagsCollapsed) { appClass += " collapsed-tags"; }
this.setState({ appClass }); this.setState({ appClass });
} else if (eventName === APP_STATE_EVENT_WINDOW_DID_FOCUS) { } else if (eventName === AppStateEvents.WindowDidFocus) {
if (!(await this.application.isPasscodeLocked())) { if (!(await this.application.isPasscodeLocked())) {
this.application.sync(); this.application.sync();
} }
@@ -110,7 +107,7 @@ class RootCtrl extends PureCtrl {
} }
// addSyncStatusObserver() { // addSyncStatusObserver() {
// this.syncStatusObserver = this.syncManager.registerSyncStatusObserver((status) => { // this.syncStatusObserver = syncManager.registerSyncStatusObserver((status) => {
// if (status.retrievedCount > 20) { // if (status.retrievedCount > 20) {
// const text = `Downloading ${status.retrievedCount} items. Keep app open.`; // const text = `Downloading ${status.retrievedCount} items. Keep app open.`;
// this.syncStatus = this.statusManager.replaceStatusWithString( // this.syncStatus = this.statusManager.replaceStatusWithString(
@@ -143,7 +140,7 @@ class RootCtrl extends PureCtrl {
// addSyncEventHandler() { // addSyncEventHandler() {
// let lastShownDate; // let lastShownDate;
// this.syncManager.addEventHandler((syncEvent, data) => { // syncManager.addEventHandler((syncEvent, data) => {
// this.$rootScope.$broadcast( // this.$rootScope.$broadcast(
// syncEvent, // syncEvent,
// data || {} // data || {}
@@ -183,14 +180,14 @@ class RootCtrl extends PureCtrl {
// status // status
// ); // );
// }; // };
// this.syncManager.loadLocalItems({ incrementalCallback }).then(() => { // syncManager.loadLocalItems({ incrementalCallback }).then(() => {
// this.$timeout(() => { // this.$timeout(() => {
// this.$rootScope.$broadcast("initial-data-loaded"); // this.$rootScope.$broadcast("initial-data-loaded");
// this.syncStatus = this.statusManager.replaceStatusWithString( // this.syncStatus = this.statusManager.replaceStatusWithString(
// this.syncStatus, // this.syncStatus,
// "Syncing..." // "Syncing..."
// ); // );
// this.syncManager.sync({ // syncManager.sync({
// checkIntegrity: true // checkIntegrity: true
// }).then(() => { // }).then(() => {
// this.syncStatus = this.statusManager.removeStatus(this.syncStatus); // this.syncStatus = this.statusManager.removeStatus(this.syncStatus);

View File

@@ -1,11 +1,8 @@
import { SNNote, SNSmartTag, CONTENT_TYPE_TAG, CONTENT_TYPE_SMART_TAG } from 'snjs'; import { SNNote, SNSmartTag, ContentTypes } from 'snjs';
import template from '%/tags.pug'; import template from '%/tags.pug';
import { import { AppStateEvents } from '@/state';
APP_STATE_EVENT_PREFERENCES_CHANGED,
APP_STATE_EVENT_TAG_CHANGED
} from '@/state';
import { PANEL_NAME_TAGS } from '@/controllers/constants'; import { PANEL_NAME_TAGS } from '@/controllers/constants';
import { PREF_TAGS_PANEL_WIDTH } from '@/services/preferencesManager'; import { PrefKeys } from '@/services/preferencesManager';
import { STRING_DELETE_TAG } from '@/strings'; import { STRING_DELETE_TAG } from '@/strings';
import { PureCtrl } from '@Controllers'; import { PureCtrl } from '@Controllers';
@@ -40,11 +37,11 @@ class TagsPanelCtrl extends PureCtrl {
beginStreamingItems() { beginStreamingItems() {
this.application.streamItems({ this.application.streamItems({
contentType: CONTENT_TYPE_TAG, contentType: ContentTypes.Tag,
stream: async ({ items }) => { stream: async ({ items }) => {
await this.setState({ await this.setState({
tags: this.application.getItems({contentType: CONTENT_TYPE_TAG}), tags: this.application.getItems({ contentType: ContentTypes.Tag }),
smartTags: this.application.getItems({ contentType: CONTENT_TYPE_SMART_TAG }), smartTags: this.application.getItems({ contentType: ContentTypes.SmartTag }),
}); });
this.reloadNoteCounts(); this.reloadNoteCounts();
if (this.state.selectedTag) { if (this.state.selectedTag) {
@@ -62,9 +59,9 @@ class TagsPanelCtrl extends PureCtrl {
addAppStateObserver() { addAppStateObserver() {
this.appState.addObserver((eventName, data) => { this.appState.addObserver((eventName, data) => {
if (eventName === APP_STATE_EVENT_PREFERENCES_CHANGED) { if (eventName === AppStateEvents.PreferencesChanged) {
this.loadPreferences(); this.loadPreferences();
} else if (eventName === APP_STATE_EVENT_TAG_CHANGED) { } else if (eventName === AppStateEvents.TagChanged) {
this.setState({ this.setState({
selectedTag: this.appState.getSelectedTag() selectedTag: this.appState.getSelectedTag()
}); });
@@ -93,7 +90,7 @@ class TagsPanelCtrl extends PureCtrl {
} }
loadPreferences() { loadPreferences() {
const width = this.preferencesManager.getValue(PREF_TAGS_PANEL_WIDTH); const width = this.preferencesManager.getValue(PrefKeys.TagsPanelWidth);
if (width) { if (width) {
this.panelController.setWidth(width); this.panelController.setWidth(width);
if (this.panelController.isCollapsed()) { if (this.panelController.isCollapsed()) {
@@ -107,7 +104,7 @@ class TagsPanelCtrl extends PureCtrl {
onPanelResize = (newWidth, lastLeft, isAtMaxWidth, isCollapsed) => { onPanelResize = (newWidth, lastLeft, isAtMaxWidth, isCollapsed) => {
this.preferencesManager.setUserPrefValue( this.preferencesManager.setUserPrefValue(
PREF_TAGS_PANEL_WIDTH, PrefKeys.TagsPanelWidth,
newWidth, newWidth,
true true
); );
@@ -167,7 +164,7 @@ class TagsPanelCtrl extends PureCtrl {
return; return;
} }
const newTag = this.application.createItem({ const newTag = this.application.createItem({
contentType: CONTENT_TYPE_TAG contentType: ContentTypes.Tag
}); });
this.setState({ this.setState({
previousTag: this.state.selectedTag, previousTag: this.state.selectedTag,

View File

@@ -4,7 +4,6 @@ import { PureCtrl } from '@Controllers';
class ActionsMenuCtrl extends PureCtrl { class ActionsMenuCtrl extends PureCtrl {
/* @ngInject */ /* @ngInject */
constructor( constructor(
$scope,
$timeout, $timeout,
actionsManager, actionsManager,
godService godService

View File

@@ -2,22 +2,25 @@ import angular from 'angular';
import template from '%/directives/panel-resizer.pug'; import template from '%/directives/panel-resizer.pug';
import { debounce } from '@/utils'; import { debounce } from '@/utils';
const PANEL_SIDE_RIGHT = 'right'; const PanelSides = {
const PANEL_SIDE_LEFT = 'left'; Right: 'right',
Left: 'left'
const MOUSE_EVENT_MOVE = 'mousemove'; };
const MOUSE_EVENT_DOWN = 'mousedown'; const MouseEvents = {
const MOUSE_EVENT_UP = 'mouseup'; Move: 'mousemove',
Down: 'mousedown',
Up: 'mouseup'
};
const CssClasses = {
Hoverable: 'hoverable',
AlwaysVisible: 'always-visible',
Dragging: 'dragging',
NoSelection: 'no-selection',
Collapsed: 'collapsed',
AnimateOpacity: 'animate-opacity',
};
const WINDOW_EVENT_RESIZE = 'resize'; const WINDOW_EVENT_RESIZE = 'resize';
const PANEL_CSS_CLASS_HOVERABLE = 'hoverable';
const PANEL_CSS_CLASS_ALWAYS_VISIBLE = 'always-visible';
const PANEL_CSS_CLASS_DRAGGING = 'dragging';
const PANEL_CSS_CLASS_NO_SELECTION = 'no-selection';
const PANEL_CSS_CLASS_COLLAPSED = 'collapsed';
const PANEL_CSS_CLASS_ANIMATE_OPACITY = 'animate-opacity';
class PanelResizerCtrl { class PanelResizerCtrl {
/* @ngInject */ /* @ngInject */
constructor( constructor(
@@ -78,14 +81,14 @@ class PanelResizerCtrl {
this.appFrame = null; this.appFrame = null;
this.widthBeforeLastDblClick = 0; this.widthBeforeLastDblClick = 0;
if (this.property === PANEL_SIDE_RIGHT) { if (this.property === PanelSides.Right) {
this.configureRightPanel(); this.configureRightPanel();
} }
if (this.alwaysVisible) { if (this.alwaysVisible) {
this.resizerColumn.classList.add(PANEL_CSS_CLASS_ALWAYS_VISIBLE); this.resizerColumn.classList.add(CssClasses.AlwaysVisible);
} }
if (this.hoverable) { if (this.hoverable) {
this.resizerColumn.classList.add(PANEL_CSS_CLASS_HOVERABLE); this.resizerColumn.classList.add(CssClasses.Hoverable);
} }
} }
@@ -140,26 +143,26 @@ class PanelResizerCtrl {
} }
addMouseDownListener() { addMouseDownListener() {
this.resizerColumn.addEventListener(MOUSE_EVENT_DOWN, (event) => { this.resizerColumn.addEventListener(MouseEvents.Down, (event) => {
this.addInvisibleOverlay(); this.addInvisibleOverlay();
this.pressed = true; this.pressed = true;
this.lastDownX = event.clientX; this.lastDownX = event.clientX;
this.startWidth = this.panel.scrollWidth; this.startWidth = this.panel.scrollWidth;
this.startLeft = this.panel.offsetLeft; this.startLeft = this.panel.offsetLeft;
this.panel.classList.add(PANEL_CSS_CLASS_NO_SELECTION); this.panel.classList.add(CssClasses.NoSelection);
if (this.hoverable) { if (this.hoverable) {
this.resizerColumn.classList.add(PANEL_CSS_CLASS_DRAGGING); this.resizerColumn.classList.add(CssClasses.Dragging);
} }
}); });
} }
addMouseMoveListener() { addMouseMoveListener() {
document.addEventListener(MOUSE_EVENT_MOVE, (event) => { document.addEventListener(MouseEvents.Move, (event) => {
if (!this.pressed) { if (!this.pressed) {
return; return;
} }
event.preventDefault(); event.preventDefault();
if (this.property && this.property === PANEL_SIDE_LEFT) { if (this.property && this.property === PanelSides.Left) {
this.handleLeftEvent(event); this.handleLeftEvent(event);
} else { } else {
this.handleWidthEvent(event); this.handleWidthEvent(event);
@@ -210,12 +213,12 @@ class PanelResizerCtrl {
} }
addMouseUpListener() { addMouseUpListener() {
document.addEventListener(MOUSE_EVENT_UP, event => { document.addEventListener(MouseEvents.Up, event => {
this.removeInvisibleOverlay(); this.removeInvisibleOverlay();
if (this.pressed) { if (this.pressed) {
this.pressed = false; this.pressed = false;
this.resizerColumn.classList.remove(PANEL_CSS_CLASS_DRAGGING); this.resizerColumn.classList.remove(CssClasses.Dragging);
this.panel.classList.remove(PANEL_CSS_CLASS_NO_SELECTION); this.panel.classList.remove(CssClasses.NoSelection);
const isMaxWidth = this.isAtMaxWidth(); const isMaxWidth = this.isAtMaxWidth();
if (this.onResizeFinish) { if (this.onResizeFinish) {
this.onResizeFinish()( this.onResizeFinish()(
@@ -279,9 +282,9 @@ class PanelResizerCtrl {
this.collapsed = this.isCollapsed(); this.collapsed = this.isCollapsed();
if (this.collapsed) { if (this.collapsed) {
this.resizerColumn.classList.add(PANEL_CSS_CLASS_COLLAPSED); this.resizerColumn.classList.add(CssClasses.Collapsed);
} else { } else {
this.resizerColumn.classList.remove(PANEL_CSS_CLASS_COLLAPSED); this.resizerColumn.classList.remove(CssClasses.Collapsed);
} }
} }
@@ -308,9 +311,9 @@ class PanelResizerCtrl {
flash() { flash() {
const FLASH_DURATION = 3000; const FLASH_DURATION = 3000;
this.resizerColumn.classList.add(PANEL_CSS_CLASS_ANIMATE_OPACITY); this.resizerColumn.classList.add(CssClasses.AnimateOpacity);
this.$timeout(() => { this.$timeout(() => {
this.resizerColumn.classList.remove(PANEL_CSS_CLASS_ANIMATE_OPACITY); this.resizerColumn.classList.remove(CssClasses.AnimateOpacity);
}, FLASH_DURATION); }, FLASH_DURATION);
} }
} }

View File

@@ -1,5 +1,5 @@
import { PrivilegesManager } from '@/services/privilegesManager';
import template from '%/directives/privileges-management-modal.pug'; import template from '%/directives/privileges-management-modal.pug';
import { PrivilegeCredentials } from 'snjs';
class PrivilegesManagementModalCtrl { class PrivilegesManagementModalCtrl {
/* @ngInject */ /* @ngInject */
@@ -18,9 +18,9 @@ class PrivilegesManagementModalCtrl {
displayInfoForCredential(credential) { displayInfoForCredential(credential) {
const info = this.application.privilegesManager.displayInfoForCredential(credential); const info = this.application.privilegesManager.displayInfoForCredential(credential);
if (credential === PrivilegesManager.CredentialLocalPasscode) { if (credential === PrivilegeCredentials.LocalPasscode) {
info.availability = this.hasPasscode; info.availability = this.hasPasscode;
} else if (credential === PrivilegesManager.CredentialAccountPassword) { } else if (credential === PrivilegeCredentials.AccountPassword) {
info.availability = this.hasAccount; info.availability = this.hasAccount;
} else { } else {
info.availability = true; info.availability = true;

View File

@@ -1,7 +1,6 @@
import { import {
PAYLOAD_SOURCE_REMOTE_ACTION_RETRIEVED, PAYLOAD_SOURCE_REMOTE_ACTION_RETRIEVED,
CONTENT_TYPE_NOTE, ContentTypes
CONTENT_TYPE_COMPONENT
} from 'snjs'; } from 'snjs';
import template from '%/directives/revision-preview-modal.pug'; import template from '%/directives/revision-preview-modal.pug';
@@ -25,7 +24,7 @@ class RevisionPreviewModalCtrl {
async configure() { async configure() {
this.note = await this.application.createItem({ this.note = await this.application.createItem({
contentType: CONTENT_TYPE_NOTE, contentType: ContentTypes.Note,
content: this.content content: this.content
}); });
@@ -43,7 +42,7 @@ class RevisionPreviewModalCtrl {
* editor object has non-copyable properties like .window, which cannot be transfered * editor object has non-copyable properties like .window, which cannot be transfered
*/ */
const editorCopy = await this.application.createItem({ const editorCopy = await this.application.createItem({
contentType: CONTENT_TYPE_COMPONENT, contentType: ContentTypes.Component,
content: editorForNote.content content: editorForNote.content
}); });
editorCopy.readonly = true; editorCopy.readonly = true;

View File

@@ -1,48 +1,46 @@
import { PrivilegesManager } from '@/services/privilegesManager'; import { EncryptionIntents, ProtectedActions } from 'snjs';
export class ArchiveManager { export class ArchiveManager {
/* @ngInject */ /* @ngInject */
constructor(lockManager, authManager, modelManager, privilegesManager) { constructor(lockManager, application, authManager, modelManager, privilegesManager) {
this.lockManager = lockManager; this.lockManager = lockManager;
this.authManager = authManager; this.authManager = authManager;
this.modelManager = modelManager; modelManager = modelManager;
this.privilegesManager = privilegesManager; this.privilegesManager = privilegesManager;
this.application = application;
} }
/* /*
Public Public
*/ */
/** @public */
async downloadBackup(encrypted) { async downloadBackup(encrypted) {
return this.downloadBackupOfItems(this.modelManager.allItems, encrypted); return this.downloadBackupOfItems(modelManager.allItems, encrypted);
} }
/** @public */
async downloadBackupOfItems(items, encrypted) { async downloadBackupOfItems(items, encrypted) {
const run = async () => { const run = async () => {
// download in Standard Notes format // download in Standard Notes format
let keys, authParams; const intent = encrypted
if(encrypted) { ? EncryptionIntents.FileEncrypted
if(this.authManager.offline() && this.lockManager.hasPasscode()) { : EncryptionIntents.FileDecrypted;
keys = this.lockManager.keys(); this.itemsData(items, intent).then((data) => {
authParams = this.lockManager.passcodeAuthParams();
} else {
keys = await this.authManager.keys();
authParams = await this.authManager.getAuthParams();
}
}
this.__itemsData(items, keys, authParams).then((data) => {
const modifier = encrypted ? "Encrypted" : "Decrypted"; const modifier = encrypted ? "Encrypted" : "Decrypted";
this.__downloadData(data, `Standard Notes ${modifier} Backup - ${this.__formattedDate()}.txt`); this.downloadData(
data,
`Standard Notes ${modifier} Backup - ${this.formattedDate()}.txt`
);
// download as zipped plain text files // download as zipped plain text files
if(!keys) { if (!encrypted) {
this.__downloadZippedItems(items); this.downloadZippedItems(items);
} }
}); });
}; };
if(await this.privilegesManager.actionRequiresPrivilege(PrivilegesManager.ActionManageBackups)) { if (await this.privilegesManager.actionRequiresPrivilege(ProtectedActions.ManageBackups)) {
this.godService.presentPrivilegesModal(PrivilegesManager.ActionManageBackups, () => { this.godService.presentPrivilegesModal(ProtectedActions.ManageBackups, () => {
run(); run();
}); });
} else { } else {
@@ -50,11 +48,8 @@ export class ArchiveManager {
} }
} }
/* /** @private */
Private formattedDate() {
*/
__formattedDate() {
var string = `${new Date()}`; var string = `${new Date()}`;
// Match up to the first parenthesis, i.e do not include '(Central Standard Time)' // Match up to the first parenthesis, i.e do not include '(Central Standard Time)'
var matches = string.match(/^(.*?) \(/); var matches = string.match(/^(.*?) \(/);
@@ -64,15 +59,19 @@ export class ArchiveManager {
return string; return string;
} }
async __itemsData(items, keys, authParams) { /** @private */
const data = await this.modelManager.getJSONDataForItems(items, keys, authParams); async itemsData(items, intent) {
const data = await this.application.protocolService.createBackupFile({
subItems: items,
intent: intent
});
const blobData = new Blob([data], { type: 'text/json' }); const blobData = new Blob([data], { type: 'text/json' });
return blobData; return blobData;
} }
__loadZip(callback) { /** @private */
async loadZip() {
if (window.zip) { if (window.zip) {
callback();
return; return;
} }
@@ -81,14 +80,17 @@ export class ArchiveManager {
scriptTag.async = false; scriptTag.async = false;
var headTag = document.getElementsByTagName('head')[0]; var headTag = document.getElementsByTagName('head')[0];
headTag.appendChild(scriptTag); headTag.appendChild(scriptTag);
return new Promise((resolve, reject) => {
scriptTag.onload = function () { scriptTag.onload = function () {
zip.workerScriptsPath = "assets/zip/"; zip.workerScriptsPath = "assets/zip/";
callback(); resolve();
}; };
});
} }
__downloadZippedItems(items) { /** @private */
this.__loadZip(() => { async downloadZippedItems(items) {
await this.loadZip();
zip.createWriter(new zip.BlobWriter("application/zip"), (zipWriter) => { zip.createWriter(new zip.BlobWriter("application/zip"), (zipWriter) => {
var index = 0; var index = 0;
@@ -120,7 +122,7 @@ export class ArchiveManager {
nextFile(); nextFile();
} else { } else {
zipWriter.close((blob) => { zipWriter.close((blob) => {
this.__downloadData(blob, `Standard Notes Backup - ${this.__formattedDate()}.zip`); this.downloadData(blob, `Standard Notes Backup - ${this.formattedDate()}.zip`);
zipWriter = null; zipWriter = null;
}); });
} }
@@ -129,27 +131,26 @@ export class ArchiveManager {
nextFile(); nextFile();
}, onerror); }, onerror);
});
} }
__hrefForData(data) { /** @private */
hrefForData(data) {
// If we are replacing a previously generated file we need to // If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks. // manually revoke the object URL to avoid memory leaks.
if (this.textFile !== null) { if (this.textFile !== null) {
window.URL.revokeObjectURL(this.textFile); window.URL.revokeObjectURL(this.textFile);
} }
this.textFile = window.URL.createObjectURL(data); this.textFile = window.URL.createObjectURL(data);
// returns a URL you can use as a href // returns a URL you can use as a href
return this.textFile; return this.textFile;
} }
__downloadData(data, fileName) { /** @private */
downloadData(data, fileName) {
var link = document.createElement('a'); var link = document.createElement('a');
link.setAttribute('download', fileName); link.setAttribute('download', fileName);
link.href = this.__hrefForData(data); link.href = this.hrefForData(data);
document.body.appendChild(link); document.body.appendChild(link);
link.click(); link.click();
link.remove(); link.remove();

View File

@@ -1,7 +1,8 @@
/* eslint-disable camelcase */
// An interface used by the Desktop app to interact with SN // An interface used by the Desktop app to interact with SN
import _ from 'lodash'; import pull from 'lodash/pull';
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import { SFItemParams, SFModelManager } from 'snjs'; import { EncryptionIntents } from 'snjs';
const COMPONENT_DATA_KEY_INSTALL_ERROR = 'installError'; const COMPONENT_DATA_KEY_INSTALL_ERROR = 'installError';
const COMPONENT_CONTENT_KEY_PACKAGE_INFO = 'package_info'; const COMPONENT_CONTENT_KEY_PACKAGE_INFO = 'package_info';
@@ -12,32 +13,25 @@ export class DesktopManager {
constructor( constructor(
$rootScope, $rootScope,
$timeout, $timeout,
modelManager, application,
syncManager, appState,
authManager,
lockManager,
appState
) { ) {
this.lockManager = lockManager;
this.modelManager = modelManager;
this.authManager = authManager;
this.syncManager = syncManager;
this.$rootScope = $rootScope; this.$rootScope = $rootScope;
this.$timeout = $timeout;
this.appState = appState; this.appState = appState;
this.timeout = $timeout; this.application = application;
this.updateObservers = [];
this.componentActivationObservers = []; this.componentActivationObservers = [];
this.updateObservers = [];
this.isDesktop = isDesktopApplication(); this.isDesktop = isDesktopApplication();
$rootScope.$on("initial-data-loaded", () => { $rootScope.$on('initial-data-loaded', () => {
this.dataLoaded = true; this.dataLoaded = true;
if (this.dataLoadHandler) { if (this.dataLoadHandler) {
this.dataLoadHandler(); this.dataLoadHandler();
} }
}); });
$rootScope.$on("major-data-change", () => { $rootScope.$on('major-data-change', () => {
if (this.majorDataChangeHandler) { if (this.majorDataChangeHandler) {
this.majorDataChangeHandler(); this.majorDataChangeHandler();
} }
@@ -56,12 +50,15 @@ export class DesktopManager {
return this.extServerHost; return this.extServerHost;
} }
/* /**
Sending a component in its raw state is really slow for the desktop app * Sending a component in its raw state is really slow for the desktop app
Keys are not passed into ItemParams, so the result is not encrypted * Keys are not passed into ItemParams, so the result is not encrypted
*/ */
async convertComponentForTransmission(component) { async convertComponentForTransmission(component) {
return new SFItemParams(component).paramsForExportFile(true); return this.application.protocolService.payloadByEncryptingPayload({
payload: component.payloadRepresentation(),
intent: EncryptionIntents.FileDecrypted
});
} }
// All `components` should be installed // All `components` should be installed
@@ -105,7 +102,7 @@ export class DesktopManager {
} }
deregisterUpdateObserver(observer) { deregisterUpdateObserver(observer) {
_.pull(this.updateObservers, observer); pull(this.updateObservers, observer);
} }
// Pass null to cancel search // Pass null to cancel search
@@ -114,15 +111,15 @@ export class DesktopManager {
} }
desktop_windowGainedFocus() { desktop_windowGainedFocus() {
this.$rootScope.$broadcast("window-gained-focus"); this.$rootScope.$broadcast('window-gained-focus');
} }
desktop_windowLostFocus() { desktop_windowLostFocus() {
this.$rootScope.$broadcast("window-lost-focus"); this.$rootScope.$broadcast('window-lost-focus');
} }
desktop_onComponentInstallationComplete(componentData, error) { async desktop_onComponentInstallationComplete(componentData, error) {
const component = this.modelManager.findItem(componentData.uuid); const component = await this.application.findItem({ uuid: componentData.uuid });
if (!component) { if (!component) {
return; return;
} }
@@ -139,18 +136,13 @@ export class DesktopManager {
for (const key of permissableKeys) { for (const key of permissableKeys) {
component[key] = componentData.content[key]; component[key] = componentData.content[key];
} }
this.modelManager.notifySyncObserversOfModels(
[component],
SFModelManager.MappingSourceDesktopInstalled
);
component.setAppDataItem( component.setAppDataItem(
COMPONENT_DATA_KEY_INSTALL_ERROR, COMPONENT_DATA_KEY_INSTALL_ERROR,
null null
); );
} }
this.modelManager.setItemDirty(component); this.application.saveItem({ item: component });
this.syncManager.sync(); this.$timeout(() => {
this.timeout(() => {
for (const observer of this.updateObservers) { for (const observer of this.updateObservers) {
observer.callback(component); observer.callback(component);
} }
@@ -164,7 +156,7 @@ export class DesktopManager {
} }
desktop_deregisterComponentActivationObserver(observer) { desktop_deregisterComponentActivationObserver(observer) {
_.pull(this.componentActivationObservers, observer); pull(this.componentActivationObservers, observer);
} }
/* Notify observers that a component has been registered/activated */ /* Notify observers that a component has been registered/activated */
@@ -172,14 +164,14 @@ export class DesktopManager {
const serializedComponent = await this.convertComponentForTransmission( const serializedComponent = await this.convertComponentForTransmission(
component component
); );
this.timeout(() => { this.$timeout(() => {
for (const observer of this.componentActivationObservers) { for (const observer of this.componentActivationObservers) {
observer.callback(serializedComponent); observer.callback(serializedComponent);
} }
}); });
} }
/* Used to resolve "sn://" */ /* Used to resolve 'sn://' */
desktop_setExtServerHost(host) { desktop_setExtServerHost(host) {
this.extServerHost = host; this.extServerHost = host;
this.appState.desktopExtensionsReady(); this.appState.desktopExtensionsReady();
@@ -201,22 +193,10 @@ export class DesktopManager {
} }
async desktop_requestBackupFile(callback) { async desktop_requestBackupFile(callback) {
let keys, authParams; const data = await this.application.protocolService.createBackupFile({
if(this.authManager.offline() && this.lockManager.hasPasscode()) { returnIfEmpty: true
keys = this.lockManager.keys();
authParams = this.lockManager.passcodeAuthParams();
} else {
keys = await this.authManager.keys();
authParams = await this.authManager.getAuthParams();
}
const nullOnEmpty = true;
this.modelManager.getAllItemsJSONData(
keys,
authParams,
nullOnEmpty
).then((data) => {
callback(data);
}); });
callback(data);
} }
desktop_setMajorDataChangeHandler(handler) { desktop_setMajorDataChangeHandler(handler) {

View File

@@ -1,21 +1,10 @@
export { ActionsManager } from './actionsManager';
export { ArchiveManager } from './archiveManager'; export { ArchiveManager } from './archiveManager';
export { AuthManager } from './authManager';
export { ComponentManager } from './componentManager';
export { DatabaseManager } from './databaseManager'; export { DatabaseManager } from './databaseManager';
export { DesktopManager } from './desktopManager'; export { DesktopManager } from './desktopManager';
export { HttpManager } from './httpManager';
export { KeyboardManager } from './keyboardManager'; export { KeyboardManager } from './keyboardManager';
export { MigrationManager } from './migrationManager';
export { ModelManager } from './modelManager';
export { NativeExtManager } from './nativeExtManager'; export { NativeExtManager } from './nativeExtManager';
export { LockManager } from './lockManager'; export { LockManager } from './lockManager';
export { PrivilegesManager } from './privilegesManager';
export { SessionHistory } from './sessionHistory';
export { SingletonManager } from './singletonManager';
export { StatusManager } from './statusManager'; export { StatusManager } from './statusManager';
export { StorageManager } from './storageManager';
export { SyncManager } from './syncManager';
export { ThemeManager } from './themeManager'; export { ThemeManager } from './themeManager';
export { AlertManager } from './alertManager'; export { AlertManager } from './alertManager';
export { PreferencesManager } from './preferencesManager'; export { PreferencesManager } from './preferencesManager';

View File

@@ -1,42 +1,41 @@
export class KeyboardManager { /** @public */
export const KeyboardKeys = {
Tab: "Tab",
Backspace: "Backspace",
Up: "ArrowUp",
Down: "ArrowDown",
};
/** @public */
export const KeyboardModifiers = {
Shift: "Shift",
Ctrl: "Control",
/** ⌘ key on Mac, ⊞ key on Windows */
Meta: "Meta",
Alt: "Alt",
};
/** @private */
const KeyboardKeyEvents = {
Down: "KeyEventDown",
Up: "KeyEventUp"
};
export class KeyboardManager {
constructor() { constructor() {
this.observers = []; this.observers = [];
KeyboardManager.KeyTab = "Tab";
KeyboardManager.KeyBackspace = "Backspace";
KeyboardManager.KeyUp = "ArrowUp";
KeyboardManager.KeyDown = "ArrowDown";
KeyboardManager.KeyModifierShift = "Shift";
KeyboardManager.KeyModifierCtrl = "Control";
// ⌘ key on Mac, ⊞ key on Windows
KeyboardManager.KeyModifierMeta = "Meta";
KeyboardManager.KeyModifierAlt = "Alt";
KeyboardManager.KeyEventDown = "KeyEventDown";
KeyboardManager.KeyEventUp = "KeyEventUp";
KeyboardManager.AllModifiers = [
KeyboardManager.KeyModifierShift,
KeyboardManager.KeyModifierCtrl,
KeyboardManager.KeyModifierMeta,
KeyboardManager.KeyModifierAlt
];
window.addEventListener('keydown', this.handleKeyDown.bind(this)); window.addEventListener('keydown', this.handleKeyDown.bind(this));
window.addEventListener('keyup', this.handleKeyUp.bind(this)); window.addEventListener('keyup', this.handleKeyUp.bind(this));
} }
modifiersForEvent(event) { modifiersForEvent(event) {
const eventModifiers = KeyboardManager.AllModifiers.filter((modifier) => { const allModifiers = Object.keys(KeyboardModifiers).map((key) => KeyboardModifiers[key]);
const eventModifiers = allModifiers.filter((modifier) => {
// For a modifier like ctrlKey, must check both event.ctrlKey and event.key. // For a modifier like ctrlKey, must check both event.ctrlKey and event.key.
// That's because on keyup, event.ctrlKey would be false, but event.key == Control would be true. // That's because on keyup, event.ctrlKey would be false, but event.key == Control would be true.
const matches = ( const matches = (
((event.ctrlKey || event.key == KeyboardManager.KeyModifierCtrl) && modifier === KeyboardManager.KeyModifierCtrl) || ((event.ctrlKey || event.key === KeyboardModifiers.Ctrl) && modifier === KeyboardModifiers.Ctrl) ||
((event.metaKey || event.key == KeyboardManager.KeyModifierMeta) && modifier === KeyboardManager.KeyModifierMeta) || ((event.metaKey || event.key === KeyboardModifiers.Meta) && modifier === KeyboardModifiers.Meta) ||
((event.altKey || event.key == KeyboardManager.KeyModifierAlt) && modifier === KeyboardManager.KeyModifierAlt) || ((event.altKey || event.key === KeyboardModifiers.Alt) && modifier === KeyboardModifiers.Alt) ||
((event.shiftKey || event.key == KeyboardManager.KeyModifierShift) && modifier === KeyboardManager.KeyModifierShift) ((event.shiftKey || event.key === KeyboardModifiers.Shift) && modifier === KeyboardModifiers.Shift)
); );
return matches; return matches;
@@ -48,7 +47,7 @@ export class KeyboardManager {
eventMatchesKeyAndModifiers(event, key, modifiers = []) { eventMatchesKeyAndModifiers(event, key, modifiers = []) {
const eventModifiers = this.modifiersForEvent(event); const eventModifiers = this.modifiersForEvent(event);
if(eventModifiers.length != modifiers.length) { if (eventModifiers.length !== modifiers.length) {
return false; return false;
} }
@@ -65,12 +64,12 @@ export class KeyboardManager {
// In the browser, shift + f results in key 'f', but in Electron, shift + f results in 'F' // In the browser, shift + f results in key 'f', but in Electron, shift + f results in 'F'
// In our case we don't differentiate between the two. // In our case we don't differentiate between the two.
return key.toLowerCase() == event.key.toLowerCase(); return key.toLowerCase() === event.key.toLowerCase();
} }
notifyObserver(event, keyEventType) { notifyObserver(event, keyEventType) {
for (const observer of this.observers) { for (const observer of this.observers) {
if(observer.element && event.target != observer.element) { if (observer.element && event.target !== observer.element) {
continue; continue;
} }
@@ -78,7 +77,7 @@ export class KeyboardManager {
continue; continue;
} }
if(observer.notElement && observer.notElement == event.target) { if (observer.notElement && observer.notElement === event.target) {
continue; continue;
} }
@@ -87,7 +86,7 @@ export class KeyboardManager {
} }
if (this.eventMatchesKeyAndModifiers(event, observer.key, observer.modifiers)) { if (this.eventMatchesKeyAndModifiers(event, observer.key, observer.modifiers)) {
const callback = keyEventType == KeyboardManager.KeyEventDown ? observer.onKeyDown : observer.onKeyUp; const callback = keyEventType === KeyboardKeyEvents.Down ? observer.onKeyDown : observer.onKeyUp;
if (callback) { if (callback) {
callback(event); callback(event);
} }
@@ -96,11 +95,11 @@ export class KeyboardManager {
} }
handleKeyDown(event) { handleKeyDown(event) {
this.notifyObserver(event, KeyboardManager.KeyEventDown); this.notifyObserver(event, KeyboardKeyEvents.Down);
} }
handleKeyUp(event) { handleKeyUp(event) {
this.notifyObserver(event, KeyboardManager.KeyEventUp); this.notifyObserver(event, KeyboardKeyEvents.Up);
} }
addKeyObserver({ key, modifiers, onKeyDown, onKeyUp, element, elements, notElement, notElementIds }) { addKeyObserver({ key, modifiers, onKeyDown, onKeyUp, element, elements, notElement, notElementIds }) {

View File

@@ -1,9 +1,5 @@
import _ from 'lodash';
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import { import { AppStateEvents } from '../state';
APP_STATE_EVENT_WINDOW_DID_BLUR,
APP_STATE_EVENT_WINDOW_DID_FOCUS
} from '../state';
const MILLISECONDS_PER_SECOND = 1000; const MILLISECONDS_PER_SECOND = 1000;
const FOCUS_POLL_INTERVAL = 1 * MILLISECONDS_PER_SECOND; const FOCUS_POLL_INTERVAL = 1 * MILLISECONDS_PER_SECOND;
@@ -26,9 +22,9 @@ export class LockManager {
observeVisibility() { observeVisibility() {
this.appState.addObserver((eventName, data) => { this.appState.addObserver((eventName, data) => {
if(eventName === APP_STATE_EVENT_WINDOW_DID_BLUR) { if(eventName === AppStateEvents.WindowDidBlur) {
this.documentVisibilityChanged(false); this.documentVisibilityChanged(false);
} else if(eventName === APP_STATE_EVENT_WINDOW_DID_FOCUS) { } else if(eventName === AppStateEvents.WindowDidFocus) {
this.documentVisibilityChanged(true); this.documentVisibilityChanged(true);
} }
}); });

View File

@@ -1,183 +1,177 @@
/* A class for handling installation of system extensions */ import { isDesktopApplication, dictToArray } from '@/utils';
import { SFPredicate, ContentTypes, CreateMaxPayloadFromAnyObject } from 'snjs';
import { AppStateEvents } from '@/state';
import { isDesktopApplication } from '@/utils'; const STREAM_ITEMS_PERMISSION = 'stream-items';
import { SFPredicate } from 'snjs';
/** A class for handling installation of system extensions */
export class NativeExtManager { export class NativeExtManager {
/* @ngInject */ /* @ngInject */
constructor(modelManager, syncManager, singletonManager) { constructor(application, appState) {
this.modelManager = modelManager; this.application = application;
this.syncManager = syncManager; this.extManagerId = 'org.standardnotes.extensions-manager';
this.singletonManager = singletonManager; this.batchManagerId = 'org.standardnotes.batch-manager';
this.extManagerId = "org.standardnotes.extensions-manager";
this.batchManagerId = "org.standardnotes.batch-manager";
this.systemExtensions = []; this.systemExtensions = [];
this.resolveExtensionsManager(); this.resolveExtensionsManager();
this.resolveBatchManager(); this.resolveBatchManager();
appState.addObserver(async (eventName) => {
if (eventName === AppStateEvents.ApplicationReady) {
await this.initialize();
}
});
} }
isSystemExtension(extension) { isSystemExtension(extension) {
return this.systemExtensions.includes(extension.uuid); return this.systemExtensions.includes(extension.uuid);
} }
resolveExtensionsManager() { async initialize() {
this.resolveExtensionsManager();
const contentTypePredicate = new SFPredicate("content_type", "=", "SN|Component"); this.resolveBatchManager();
const packagePredicate = new SFPredicate("package_info.identifier", "=", this.extManagerId);
this.singletonManager.registerSingleton([contentTypePredicate, packagePredicate], (resolvedSingleton) => {
// Resolved Singleton
this.systemExtensions.push(resolvedSingleton.uuid);
var needsSync = false;
if(isDesktopApplication()) {
if(!resolvedSingleton.local_url) {
resolvedSingleton.local_url = window._extensions_manager_location;
needsSync = true;
}
} else {
if(!resolvedSingleton.hosted_url) {
resolvedSingleton.hosted_url = window._extensions_manager_location;
needsSync = true;
}
} }
// Handle addition of SN|ExtensionRepo permission extensionsManagerTemplatePayload() {
const permission = resolvedSingleton.content.permissions.find((p) => p.name == "stream-items");
if(!permission.content_types.includes("SN|ExtensionRepo")) {
permission.content_types.push("SN|ExtensionRepo");
needsSync = true;
}
if(needsSync) {
this.modelManager.setItemDirty(resolvedSingleton, true);
this.syncManager.sync();
}
}, (valueCallback) => {
// Safe to create. Create and return object.
const url = window._extensions_manager_location; const url = window._extensions_manager_location;
if (!url) { if (!url) {
console.error("window._extensions_manager_location must be set."); console.error('window._extensions_manager_location must be set.');
return; return;
} }
const packageInfo = { const packageInfo = {
name: "Extensions", name: 'Extensions',
identifier: this.extManagerId identifier: this.extManagerId
}; };
const content = {
var item = {
content_type: "SN|Component",
content: {
name: packageInfo.name, name: packageInfo.name,
area: "rooms", area: 'rooms',
package_info: packageInfo, package_info: packageInfo,
permissions: [ permissions: [
{ {
name: "stream-items", name: STREAM_ITEMS_PERMISSION,
content_types: [ content_types: [
"SN|Component", "SN|Theme", "SF|Extension", ContentTypes.Component,
"Extension", "SF|MFA", "SN|Editor", "SN|ExtensionRepo" ContentTypes.Theme,
ContentTypes.ServerExtension,
ContentTypes.ActionsExtension,
ContentTypes.Mfa,
ContentTypes.Editor,
ContentTypes.ExtensionRepo
] ]
} }
] ]
}
}; };
if (isDesktopApplication()) { if (isDesktopApplication()) {
item.content.local_url = window._extensions_manager_location; content.local_url = window._extensions_manager_location;
} else { } else {
item.content.hosted_url = window._extensions_manager_location; content.hosted_url = window._extensions_manager_location;
}
const payload = CreateMaxPayloadFromAnyObject({
object: {
content_type: ContentTypes.Component,
content: content
} }
var component = this.modelManager.createItem(item);
this.modelManager.addItem(component);
this.modelManager.setItemDirty(component, true);
this.syncManager.sync();
this.systemExtensions.push(component.uuid);
valueCallback(component);
}); });
return payload;
} }
resolveBatchManager() { async resolveExtensionsManager() {
const contentTypePredicate = new SFPredicate('content_type', '=', ContentTypes.Component);
const contentTypePredicate = new SFPredicate("content_type", "=", "SN|Component"); const packagePredicate = new SFPredicate('package_info.identifier', '=', this.extManagerId);
const packagePredicate = new SFPredicate("package_info.identifier", "=", this.batchManagerId); const predicate = SFPredicate.CompoundPredicate([contentTypePredicate, packagePredicate]);
const extensionsManager = await this.application.singletonManager.findOrCreateSingleton({
this.singletonManager.registerSingleton([contentTypePredicate, packagePredicate], (resolvedSingleton) => { predicate: predicate,
// Resolved Singleton createPayload: this.extensionsManagerTemplatePayload()
this.systemExtensions.push(resolvedSingleton.uuid); });
this.systemExtensions.push(extensionsManager.uuid);
var needsSync = false; let needsSync = false;
if (isDesktopApplication()) { if (isDesktopApplication()) {
if(!resolvedSingleton.local_url) { if (!extensionsManager.local_url) {
resolvedSingleton.local_url = window._batch_manager_location; extensionsManager.local_url = window._extensions_manager_location;
needsSync = true; needsSync = true;
} }
} else { } else {
if(!resolvedSingleton.hosted_url) { if (!extensionsManager.hosted_url) {
resolvedSingleton.hosted_url = window._batch_manager_location; extensionsManager.hosted_url = window._extensions_manager_location;
needsSync = true; needsSync = true;
} }
} }
// Handle addition of SN|ExtensionRepo permission
if(needsSync) { const permission = extensionsManager.content.permissions.find((p) => p.name === STREAM_ITEMS_PERMISSION);
this.modelManager.setItemDirty(resolvedSingleton, true); if (!permission.content_types.includes(ContentTypes.ExtensionRepo)) {
this.syncManager.sync(); permission.content_types.push(ContentTypes.ExtensionRepo);
needsSync = true;
} }
}, (valueCallback) => { if (needsSync) {
// Safe to create. Create and return object. this.application.saveItem({ item: extensionsManager });
}
}
batchManagerTemplatePayload() {
const url = window._batch_manager_location; const url = window._batch_manager_location;
if (!url) { if (!url) {
console.error("window._batch_manager_location must be set."); console.error('window._batch_manager_location must be set.');
return; return;
} }
const packageInfo = { const packageInfo = {
name: "Batch Manager", name: 'Batch Manager',
identifier: this.batchManagerId identifier: this.batchManagerId
}; };
const allContentTypes = dictToArray(ContentTypes);
var item = { const content = {
content_type: "SN|Component",
content: {
name: packageInfo.name, name: packageInfo.name,
area: "modal", area: 'modal',
package_info: packageInfo, package_info: packageInfo,
permissions: [ permissions: [
{ {
name: "stream-items", name: STREAM_ITEMS_PERMISSION,
content_types: [ content_types: allContentTypes
"Note", "Tag", "SN|SmartTag",
"SN|Component", "SN|Theme", "SN|UserPreferences",
"SF|Extension", "Extension", "SF|MFA", "SN|Editor",
"SN|FileSafe|Credentials", "SN|FileSafe|FileMetadata", "SN|FileSafe|Integration"
]
} }
] ]
}
}; };
if (isDesktopApplication()) { if (isDesktopApplication()) {
item.content.local_url = window._batch_manager_location; content.local_url = window._batch_manager_location;
} else { } else {
item.content.hosted_url = window._batch_manager_location; content.hosted_url = window._batch_manager_location;
}
const payload = CreateMaxPayloadFromAnyObject({
object: {
content_type: ContentTypes.Component,
content: content
} }
var component = this.modelManager.createItem(item);
this.modelManager.addItem(component);
this.modelManager.setItemDirty(component, true);
this.syncManager.sync();
this.systemExtensions.push(component.uuid);
valueCallback(component);
}); });
return payload;
}
async resolveBatchManager() {
const contentTypePredicate = new SFPredicate('content_type', '=', ContentTypes.Component);
const packagePredicate = new SFPredicate('package_info.identifier', '=', this.batchManagerId);
const predicate = SFPredicate.CompoundPredicate([contentTypePredicate, packagePredicate]);
const batchManager = await this.application.singletonManager.findOrCreateSingleton({
predicate: predicate,
createPayload: this.batchManagerTemplatePayload()
});
this.systemExtensions.push(batchManager.uuid);
let needsSync = false;
if (isDesktopApplication()) {
if (!batchManager.local_url) {
batchManager.local_url = window._batch_manager_location;
needsSync = true;
}
} else {
if (!batchManager.hosted_url) {
batchManager.hosted_url = window._batch_manager_location;
needsSync = true;
}
}
// Handle addition of SN|ExtensionRepo permission
const permission = batchManager.content.permissions.find((p) => p.name === STREAM_ITEMS_PERMISSION);
if (!permission.content_types.includes(ContentTypes.ExtensionRepo)) {
permission.content_types.push(ContentTypes.ExtensionRepo);
needsSync = true;
}
if (needsSync) {
this.application.saveItem({ item: batchManager });
}
} }
} }

View File

@@ -1,63 +1,63 @@
import { SFPredicate, SFItem } from 'snjs'; import { SFPredicate, CreateMaxPayloadFromAnyObject } from 'snjs';
import { AppStateEvents } from '../state';
export const PREF_TAGS_PANEL_WIDTH = 'tagsPanelWidth'; export const PrefKeys = {
export const PREF_NOTES_PANEL_WIDTH = 'notesPanelWidth'; TagsPanelWidth: 'tagsPanelWidth',
export const PREF_EDITOR_WIDTH = 'editorWidth'; NotesPanelWidth: 'notesPanelWidth',
export const PREF_EDITOR_LEFT = 'editorLeft'; EditorWidth: 'editorWidth',
export const PREF_EDITOR_MONOSPACE_ENABLED = 'monospaceFont'; EditorLeft: 'editorLeft',
export const PREF_EDITOR_SPELLCHECK = 'spellcheck'; EditorMonospaceEnabled: 'monospaceFont',
export const PREF_EDITOR_RESIZERS_ENABLED = 'marginResizersEnabled'; EditorSpellcheck: 'spellcheck',
export const PREF_SORT_NOTES_BY = 'sortBy'; EditorResizersEnabled: 'marginResizersEnabled',
export const PREF_SORT_NOTES_REVERSE = 'sortReverse'; SortNotesBy: 'sortBy',
export const PREF_NOTES_SHOW_ARCHIVED = 'showArchived'; SortNotesReverse: 'sortReverse',
export const PREF_NOTES_HIDE_PINNED = 'hidePinned'; NotesShowArchived: 'showArchived',
export const PREF_NOTES_HIDE_NOTE_PREVIEW = 'hideNotePreview'; NotesHidePinned: 'hidePinned',
export const PREF_NOTES_HIDE_DATE = 'hideDate'; NotesHideNotePreview: 'hideNotePreview',
export const PREF_NOTES_HIDE_TAGS = 'hideTags'; NotesHideDate: 'hideDate',
NotesHideTags: 'hideTags'
};
export class PreferencesManager { export class PreferencesManager {
/* @ngInject */ /* @ngInject */
constructor( constructor(
modelManager,
singletonManager,
appState, appState,
syncManager application
) { ) {
this.singletonManager = singletonManager; this.application = application;
this.modelManager = modelManager;
this.syncManager = syncManager;
this.appState = appState; this.appState = appState;
appState.addObserver(async (eventName) => {
if (eventName === AppStateEvents.ApplicationReady) {
await this.initialize();
}
});
}
this.modelManager.addItemSyncObserver( async initialize() {
'user-prefs', this.streamPreferences();
'SN|UserPreferences', await this.loadSingleton();
(allItems, validItems, deletedItems, source, sourceKey) => { }
streamPreferences() {
this.application.streamItems({
contentType: 'SN|UserPreferences',
stream: () => {
this.preferencesDidChange(); this.preferencesDidChange();
} }
); });
} }
load() { async loadSingleton() {
const prefsContentType = 'SN|UserPreferences'; const contentType = 'SN|UserPreferences';
const contentTypePredicate = new SFPredicate( const predicate = new SFPredicate('content_type', '=', contentType);
'content_type', this.userPreferences = await this.application.singletonManager.findOrCreateSingleton({
'=', predicate: predicate,
prefsContentType createPayload: CreateMaxPayloadFromAnyObject({
); object: {
this.singletonManager.registerSingleton( content_type: contentType
[contentTypePredicate],
(resolvedSingleton) => {
this.userPreferences = resolvedSingleton;
},
(valueCallback) => {
// Safe to create. Create and return object.
const prefs = new SFItem({content_type: prefsContentType});
this.modelManager.addItem(prefs);
this.modelManager.setItemDirty(prefs);
this.syncManager.sync();
valueCallback(prefs);
} }
); })
});
} }
preferencesDidChange() { preferencesDidChange() {
@@ -66,8 +66,7 @@ export class PreferencesManager {
syncUserPreferences() { syncUserPreferences() {
if (this.userPreferences) { if (this.userPreferences) {
this.modelManager.setItemDirty(this.userPreferences); this.application.saveItem({item: this.userPreferences});
this.syncManager.sync();
} }
} }

View File

@@ -1,42 +1,28 @@
import _ from 'lodash'; import _ from 'lodash';
import angular from 'angular'; import { SNTheme, StorageValueModes, EncryptionIntents } from 'snjs';
import { SNTheme, SFItemParams } from 'snjs'; import { AppStateEvents } from '@/state';
import { StorageManager } from './storageManager';
import { const CACHED_THEMES_KEY = 'cachedThemes';
APP_STATE_EVENT_DESKTOP_EXTS_READY
} from '@/state';
export class ThemeManager { export class ThemeManager {
/* @ngInject */ /* @ngInject */
constructor( constructor(
componentManager, application,
appState,
desktopManager, desktopManager,
storageManager,
lockManager,
appState
) { ) {
this.componentManager = componentManager; this.application = application;
this.storageManager = storageManager; this.appState = appState;
this.desktopManager = desktopManager; this.desktopManager = desktopManager;
this.activeThemes = []; this.activeThemes = [];
ThemeManager.CachedThemesKey = "cachedThemes";
this.registerObservers(); this.registerObservers();
if (!desktopManager.isDesktop) {
if (desktopManager.isDesktop) {
appState.addObserver((eventName, data) => {
if (eventName === APP_STATE_EVENT_DESKTOP_EXTS_READY) {
this.activateCachedThemes();
}
});
} else {
this.activateCachedThemes(); this.activateCachedThemes();
} }
} }
activateCachedThemes() { async activateCachedThemes() {
const cachedThemes = this.getCachedThemes(); const cachedThemes = await this.getCachedThemes();
const writeToCache = false; const writeToCache = false;
for (const theme of cachedThemes) { for (const theme of cachedThemes) {
this.activateTheme(theme, writeToCache); this.activateTheme(theme, writeToCache);
@@ -44,6 +30,11 @@ export class ThemeManager {
} }
registerObservers() { registerObservers() {
this.appState.addObserver((eventName, data) => {
if (eventName === AppStateEvents.DesktopExtsReady) {
this.activateCachedThemes();
}
});
this.desktopManager.registerUpdateObserver((component) => { this.desktopManager.registerUpdateObserver((component) => {
// Reload theme if active // Reload theme if active
if (component.active && component.isTheme()) { if (component.active && component.isTheme()) {
@@ -54,9 +45,9 @@ export class ThemeManager {
} }
}); });
this.componentManager.registerHandler({ this.application.componentManager.registerHandler({
identifier: "themeManager", identifier: 'themeManager',
areas: ["themes"], areas: ['themes'],
activationHandler: (component) => { activationHandler: (component) => {
if (component.active) { if (component.active) {
this.activateTheme(component); this.activateTheme(component);
@@ -68,14 +59,14 @@ export class ThemeManager {
} }
hasActiveTheme() { hasActiveTheme() {
return this.componentManager.getActiveThemes().length > 0; return this.application.componentManager.getActiveThemes().length > 0;
} }
deactivateAllThemes() { deactivateAllThemes() {
var activeThemes = this.componentManager.getActiveThemes(); var activeThemes = this.application.componentManager.getActiveThemes();
for (var theme of activeThemes) { for (var theme of activeThemes) {
if (theme) { if (theme) {
this.componentManager.deactivateComponent(theme); this.application.componentManager.deactivateComponent(theme);
} }
} }
@@ -86,25 +77,22 @@ export class ThemeManager {
if (_.find(this.activeThemes, { uuid: theme.uuid })) { if (_.find(this.activeThemes, { uuid: theme.uuid })) {
return; return;
} }
this.activeThemes.push(theme); this.activeThemes.push(theme);
const url = this.application.componentManager.urlForComponent(theme);
var url = this.componentManager.urlForComponent(theme); const link = document.createElement('link');
var link = document.createElement("link");
link.href = url; link.href = url;
link.type = "text/css"; link.type = 'text/css';
link.rel = "stylesheet"; link.rel = 'stylesheet';
link.media = "screen,print"; link.media = 'screen,print';
link.id = theme.uuid; link.id = theme.uuid;
document.getElementsByTagName("head")[0].appendChild(link); document.getElementsByTagName('head')[0].appendChild(link);
if (writeToCache) { if (writeToCache) {
this.cacheThemes(); this.cacheThemes();
} }
} }
deactivateTheme(theme) { deactivateTheme(theme) {
var element = document.getElementById(theme.uuid); const element = document.getElementById(theme.uuid);
if (element) { if (element) {
element.disabled = true; element.disabled = true;
element.parentNode.removeChild(element); element.parentNode.removeChild(element);
@@ -117,20 +105,33 @@ export class ThemeManager {
async cacheThemes() { async cacheThemes() {
const mapped = await Promise.all(this.activeThemes.map(async (theme) => { const mapped = await Promise.all(this.activeThemes.map(async (theme) => {
const transformer = new SFItemParams(theme); const payload = theme.payloadRepresentation();
const params = await transformer.paramsForLocalStorage(); const processedPayload = await this.application.protocolService.payloadByEncryptingPayload({
return params; payload: payload,
intent: EncryptionIntents.LocalStorageDecrypted
});
return processedPayload;
})); }));
const data = JSON.stringify(mapped); const data = JSON.stringify(mapped);
return this.storageManager.setItem(ThemeManager.CachedThemesKey, data, StorageManager.Fixed); return this.application.setValue(
CACHED_THEMES_KEY,
data,
StorageValueModes.Nonwrapped
);
} }
async decacheThemes() { async decacheThemes() {
return this.storageManager.removeItem(ThemeManager.CachedThemesKey, StorageManager.Fixed); return this.application.removeValue(
CACHED_THEMES_KEY,
StorageValueModes.Nonwrapped
);
} }
getCachedThemes() { async getCachedThemes() {
const cachedThemes = this.storageManager.getItemSync(ThemeManager.CachedThemesKey, StorageManager.Fixed); const cachedThemes = await this.application.getValue(
CACHED_THEMES_KEY,
StorageValueModes.Nonwrapped
);
if (cachedThemes) { if (cachedThemes) {
const parsed = JSON.parse(cachedThemes); const parsed = JSON.parse(cachedThemes);
return parsed.map((theme) => { return parsed.map((theme) => {

View File

@@ -1,20 +1,26 @@
import { PrivilegesManager } from '@/services/privilegesManager';
import { isDesktopApplication } from '@/utils'; import { isDesktopApplication } from '@/utils';
import pull from 'lodash/pull'; import pull from 'lodash/pull';
import { ProtectedActions } from 'snjs';
export const APP_STATE_EVENT_TAG_CHANGED = 1; export const AppStateEvents = {
export const APP_STATE_EVENT_NOTE_CHANGED = 2; TagChanged: 1,
export const APP_STATE_EVENT_PREFERENCES_CHANGED = 3; NoteChanged: 2,
export const APP_STATE_EVENT_PANEL_RESIZED = 4; PreferencesChanged: 3,
export const APP_STATE_EVENT_EDITOR_FOCUSED = 5; PanelResized: 4,
export const APP_STATE_EVENT_BEGAN_BACKUP_DOWNLOAD = 6; EditorFocused: 5,
export const APP_STATE_EVENT_ENDED_BACKUP_DOWNLOAD = 7; BeganBackupDownload: 6,
export const APP_STATE_EVENT_DESKTOP_EXTS_READY = 8; EndedBackupDownload: 7,
export const APP_STATE_EVENT_WINDOW_DID_FOCUS = 9; DesktopExtsReady: 8,
export const APP_STATE_EVENT_WINDOW_DID_BLUR = 10; WindowDidFocus: 9,
WindowDidBlur: 10,
/** Register observers and streamers on this event */
ApplicationReady: 11
};
export const EVENT_SOURCE_USER_INTERACTION = 1; export const EventSources = {
export const EVENT_SOURCE_SCRIPT = 2; UserInteraction: 1,
Script: 2
};
export class AppState { export class AppState {
@@ -22,11 +28,12 @@ export class AppState {
constructor( constructor(
$timeout, $timeout,
$rootScope, $rootScope,
privilegesManager application,
) { ) {
this.$timeout = $timeout; this.$timeout = $timeout;
this.$rootScope = $rootScope; this.$rootScope = $rootScope;
this.privilegesManager = privilegesManager; this.application = application;
this.observers = []; this.observers = [];
this.registerVisibilityObservers(); this.registerVisibilityObservers();
} }
@@ -34,18 +41,18 @@ export class AppState {
registerVisibilityObservers() { registerVisibilityObservers() {
if (isDesktopApplication()) { if (isDesktopApplication()) {
this.$rootScope.$on('window-lost-focus', () => { this.$rootScope.$on('window-lost-focus', () => {
this.notifyEvent(APP_STATE_EVENT_WINDOW_DID_BLUR); this.notifyEvent(AppStateEvents.WindowDidBlur);
}); });
this.$rootScope.$on('window-gained-focus', () => { this.$rootScope.$on('window-gained-focus', () => {
this.notifyEvent(APP_STATE_EVENT_WINDOW_DID_FOCUS); this.notifyEvent(AppStateEvents.WindowDidFocus);
}); });
} else { } else {
/* Tab visibility listener, web only */ /* Tab visibility listener, web only */
document.addEventListener('visibilitychange', (e) => { document.addEventListener('visibilitychange', (e) => {
const visible = document.visibilityState === "visible"; const visible = document.visibilityState === "visible";
const event = visible const event = visible
? APP_STATE_EVENT_WINDOW_DID_FOCUS ? AppStateEvents.WindowDidFocus
: APP_STATE_EVENT_WINDOW_DID_BLUR; : AppStateEvents.WindowDidBlur;
this.notifyEvent(event); this.notifyEvent(event);
}); });
} }
@@ -81,7 +88,7 @@ export class AppState {
const previousTag = this.selectedTag; const previousTag = this.selectedTag;
this.selectedTag = tag; this.selectedTag = tag;
this.notifyEvent( this.notifyEvent(
APP_STATE_EVENT_TAG_CHANGED, AppStateEvents.TagChanged,
{ previousTag: previousTag } { previousTag: previousTag }
); );
} }
@@ -91,16 +98,16 @@ export class AppState {
const previousNote = this.selectedNote; const previousNote = this.selectedNote;
this.selectedNote = note; this.selectedNote = note;
await this.notifyEvent( await this.notifyEvent(
APP_STATE_EVENT_NOTE_CHANGED, AppStateEvents.NoteChanged,
{ previousNote: previousNote } { previousNote: previousNote }
); );
}; };
if (note && note.content.protected && if (note && note.content.protected &&
await this.privilegesManager.actionRequiresPrivilege( await this.application.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionViewProtectedNotes ProtectedActions.ViewProtectedNotes
)) { )) {
this.godService.presentPrivilegesModal( this.godService.presentPrivilegesModal(
PrivilegesManager.ActionViewProtectedNotes, ProtectedActions.ViewProtectedNotes,
run run
); );
} else { } else {
@@ -119,13 +126,13 @@ export class AppState {
setUserPreferences(preferences) { setUserPreferences(preferences) {
this.userPreferences = preferences; this.userPreferences = preferences;
this.notifyEvent( this.notifyEvent(
APP_STATE_EVENT_PREFERENCES_CHANGED AppStateEvents.PreferencesChanged
); );
} }
panelDidResize({ name, collapsed }) { panelDidResize({ name, collapsed }) {
this.notifyEvent( this.notifyEvent(
APP_STATE_EVENT_PANEL_RESIZED, AppStateEvents.PanelResized,
{ {
panel: name, panel: name,
collapsed: collapsed collapsed: collapsed
@@ -135,20 +142,20 @@ export class AppState {
editorDidFocus(eventSource) { editorDidFocus(eventSource) {
this.notifyEvent( this.notifyEvent(
APP_STATE_EVENT_EDITOR_FOCUSED, AppStateEvents.EditorFocused,
{ eventSource: eventSource } { eventSource: eventSource }
); );
} }
beganBackupDownload() { beganBackupDownload() {
this.notifyEvent( this.notifyEvent(
APP_STATE_EVENT_BEGAN_BACKUP_DOWNLOAD AppStateEvents.BeganBackupDownload
); );
} }
endedBackupDownload({ success }) { endedBackupDownload({ success }) {
this.notifyEvent( this.notifyEvent(
APP_STATE_EVENT_ENDED_BACKUP_DOWNLOAD, AppStateEvents.EndedBackupDownload,
{ success: success } { success: success }
); );
} }
@@ -158,7 +165,7 @@ export class AppState {
*/ */
desktopExtensionsReady() { desktopExtensionsReady() {
this.notifyEvent( this.notifyEvent(
APP_STATE_EVENT_DESKTOP_EXTS_READY AppStateEvents.DesktopExtsReady
); );
} }

View File

@@ -20,6 +20,10 @@ export function isNullOrUndefined(value) {
return value === null || value === undefined; return value === null || value === undefined;
} }
export function dictToArray(dict) {
return Object.keys(dict).map((key) => dict[key]);
}
export function getPlatformString() { export function getPlatformString() {
try { try {
const platform = navigator.platform.toLowerCase(); const platform = navigator.platform.toLowerCase();

11212
dist/javascripts/app.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long