ApplicationManager and better memory management
This commit is contained in:
@@ -1,34 +1,38 @@
|
||||
import { ApplicationService } from 'snjs';
|
||||
import { ApplicationEvents } from 'snjs';
|
||||
|
||||
export class PureCtrl extends ApplicationService {
|
||||
export class PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$timeout,
|
||||
application,
|
||||
appState
|
||||
) {
|
||||
if (!$scope || !$timeout || !application || !appState) {
|
||||
throw 'Invalid PureCtrl construction.';
|
||||
constructor($timeout) {
|
||||
if(!$timeout) {
|
||||
throw Error('$timeout must not be null');
|
||||
}
|
||||
super(application);
|
||||
this.$scope = $scope;
|
||||
this.$timeout = $timeout;
|
||||
this.appState = appState;
|
||||
this.props = {};
|
||||
this.state = {};
|
||||
/* Allow caller constructor to finish setting instance variables */
|
||||
setImmediate(() => {
|
||||
this.state = this.getInitialState();
|
||||
});
|
||||
$scope.$on('$destroy', () => {
|
||||
this.unsubState();
|
||||
this.deinit();
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.addAppEventObserver();
|
||||
this.addAppStateObserver();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.addAppStateObserver();
|
||||
deinit() {
|
||||
this.unsubApp();
|
||||
this.unsubState();
|
||||
this.unsubApp = null;
|
||||
this.unsubState = null;
|
||||
this.application = null;
|
||||
if (this.stateTimeout) {
|
||||
this.$timeout.cancel(this.stateTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.deinit();
|
||||
}
|
||||
|
||||
/** @private */
|
||||
@@ -43,8 +47,11 @@ export class PureCtrl extends ApplicationService {
|
||||
}
|
||||
|
||||
async setState(state) {
|
||||
if(!this.$timeout) {
|
||||
return;
|
||||
}
|
||||
return new Promise((resolve) => {
|
||||
this.$timeout(() => {
|
||||
this.stateTimeout = this.$timeout(() => {
|
||||
this.state = Object.freeze(Object.assign({}, this.state, state));
|
||||
resolve();
|
||||
});
|
||||
@@ -59,7 +66,7 @@ export class PureCtrl extends ApplicationService {
|
||||
}
|
||||
|
||||
addAppStateObserver() {
|
||||
this.unsubState = this.appState.addObserver((eventName, data) => {
|
||||
this.unsubState = this.application.getAppState().addObserver((eventName, data) => {
|
||||
this.onAppStateEvent(eventName, data);
|
||||
});
|
||||
}
|
||||
@@ -68,9 +75,46 @@ export class PureCtrl extends ApplicationService {
|
||||
/** Optional override */
|
||||
}
|
||||
|
||||
addAppEventObserver() {
|
||||
if (this.application.isStarted()) {
|
||||
this.onAppStart();
|
||||
}
|
||||
if (this.application.isLaunched()) {
|
||||
this.onAppLaunch();
|
||||
}
|
||||
this.unsubApp = this.application.addEventObserver(async (eventName) => {
|
||||
this.onAppEvent(eventName);
|
||||
if (eventName === ApplicationEvents.Started) {
|
||||
await this.onAppStart();
|
||||
} else if (eventName === ApplicationEvents.Launched) {
|
||||
await this.onAppLaunch();
|
||||
} else if (eventName === ApplicationEvents.CompletedSync) {
|
||||
this.onAppSync();
|
||||
} else if (eventName === ApplicationEvents.KeyStatusChanged) {
|
||||
this.onAppKeyChange();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
onAppEvent(eventName) {
|
||||
/** Optional override */
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async onAppStart() {
|
||||
await this.resetState();
|
||||
return super.onAppStart();
|
||||
}
|
||||
|
||||
async onAppLaunch() {
|
||||
/** Optional override */
|
||||
}
|
||||
|
||||
async onAppKeyChange() {
|
||||
/** Optional override */
|
||||
}
|
||||
|
||||
onAppSync() {
|
||||
/** Optional override */
|
||||
}
|
||||
|
||||
}
|
||||
281
app/assets/javascripts/controllers/applicationView.js
Normal file
281
app/assets/javascripts/controllers/applicationView.js
Normal file
@@ -0,0 +1,281 @@
|
||||
import { getPlatformString } from '@/utils';
|
||||
import template from '%/application-view.pug';
|
||||
import { AppStateEvents } from '@/services/state';
|
||||
import { ApplicationEvents } from 'snjs';
|
||||
import angular from 'angular';
|
||||
import {
|
||||
PANEL_NAME_NOTES,
|
||||
PANEL_NAME_TAGS
|
||||
} from '@/controllers/constants';
|
||||
import {
|
||||
STRING_SESSION_EXPIRED,
|
||||
STRING_DEFAULT_FILE_ERROR
|
||||
} from '@/strings';
|
||||
import { PureCtrl } from './abstract/pure_ctrl';
|
||||
|
||||
class ApplicationViewCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$compile,
|
||||
$location,
|
||||
$rootScope,
|
||||
$timeout
|
||||
) {
|
||||
super($timeout);
|
||||
this.$location = $location;
|
||||
this.$rootScope = $rootScope;
|
||||
this.$compile = $compile;
|
||||
this.platformString = getPlatformString();
|
||||
this.state = { appClass: '' };
|
||||
this.onDragDrop = this.onDragDrop.bind(this);
|
||||
this.onDragOver = this.onDragOver.bind(this);
|
||||
this.openModalComponent = this.openModalComponent.bind(this);
|
||||
this.presentPermissionsDialog = this.presentPermissionsDialog.bind(this);
|
||||
this.addDragDropHandlers();
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.$location = null;
|
||||
this.$rootScope = null;
|
||||
this.$compile = null;
|
||||
this.application = null;
|
||||
this.lockScreenPuppet = null;
|
||||
window.removeEventListener('dragover', this.onDragOver, true);
|
||||
window.removeEventListener('drop', this.onDragDrop, true);
|
||||
this.onDragDrop = null;
|
||||
this.onDragOver = null;
|
||||
this.openModalComponent = null;
|
||||
this.presentPermissionsDialog = null;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
this.loadApplication();
|
||||
}
|
||||
|
||||
async loadApplication() {
|
||||
await this.application.prepareForLaunch({
|
||||
callbacks: {
|
||||
receiveChallenge: async (challenge, orchestrator) => {
|
||||
this.application.promptForChallenge(challenge, orchestrator);
|
||||
}
|
||||
}
|
||||
});
|
||||
await this.application.launch();
|
||||
|
||||
}
|
||||
|
||||
onAppStart() {
|
||||
super.onAppStart();
|
||||
this.overrideComponentManagerFunctions();
|
||||
this.application.componentManager.setDesktopManager(this.application.getDesktopService());
|
||||
this.setState({
|
||||
ready: true,
|
||||
needsUnlock: this.application.hasPasscode()
|
||||
});
|
||||
}
|
||||
|
||||
onAppLaunch() {
|
||||
super.onAppLaunch();
|
||||
this.setState({ needsUnlock: false });
|
||||
this.handleAutoSignInFromParams();
|
||||
}
|
||||
|
||||
onUpdateAvailable() {
|
||||
this.$rootScope.$broadcast('new-update-available');
|
||||
};
|
||||
|
||||
/** @override */
|
||||
async onAppEvent(eventName) {
|
||||
super.onAppEvent(eventName);
|
||||
if (eventName === ApplicationEvents.LocalDataIncrementalLoad) {
|
||||
this.updateLocalDataStatus();
|
||||
} else if (eventName === ApplicationEvents.SyncStatusChanged) {
|
||||
this.updateSyncStatus();
|
||||
} else if (eventName === ApplicationEvents.LocalDataLoaded) {
|
||||
this.updateLocalDataStatus();
|
||||
} else if (eventName === ApplicationEvents.WillSync) {
|
||||
if (!this.completedInitialSync) {
|
||||
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
"Syncing..."
|
||||
);
|
||||
}
|
||||
} else if (eventName === ApplicationEvents.CompletedSync) {
|
||||
if (!this.completedInitialSync) {
|
||||
this.syncStatus = this.application.getStatusService().removeStatus(this.syncStatus);
|
||||
this.completedInitialSync = true;
|
||||
}
|
||||
} else if (eventName === ApplicationEvents.InvalidSyncSession) {
|
||||
this.showInvalidSessionAlert();
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async onAppStateEvent(eventName, data) {
|
||||
if (eventName === AppStateEvents.PanelResized) {
|
||||
if (data.panel === PANEL_NAME_NOTES) {
|
||||
this.notesCollapsed = data.collapsed;
|
||||
}
|
||||
if (data.panel === PANEL_NAME_TAGS) {
|
||||
this.tagsCollapsed = data.collapsed;
|
||||
}
|
||||
let appClass = "";
|
||||
if (this.notesCollapsed) { appClass += "collapsed-notes"; }
|
||||
if (this.tagsCollapsed) { appClass += " collapsed-tags"; }
|
||||
this.setState({ appClass });
|
||||
} else if (eventName === AppStateEvents.WindowDidFocus) {
|
||||
if (!(await this.application.isLocked())) {
|
||||
this.application.sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateLocalDataStatus() {
|
||||
const syncStatus = this.application.getSyncStatus();
|
||||
const stats = syncStatus.getStats();
|
||||
const encryption = this.application.isEncryptionAvailable();
|
||||
if (stats.localDataDone) {
|
||||
this.syncStatus = this.application.getStatusService().removeStatus(this.syncStatus);
|
||||
return;
|
||||
}
|
||||
const notesString = `${stats.localDataCurrent}/${stats.localDataTotal} items...`;
|
||||
const loadingStatus = encryption
|
||||
? `Decrypting ${notesString}`
|
||||
: `Loading ${notesString}`;
|
||||
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
loadingStatus
|
||||
);
|
||||
}
|
||||
|
||||
updateSyncStatus() {
|
||||
const syncStatus = this.application.getSyncStatus();
|
||||
const stats = syncStatus.getStats();
|
||||
if (stats.downloadCount > 20) {
|
||||
const text = `Downloading ${stats.downloadCount} items. Keep app open.`;
|
||||
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
text
|
||||
);
|
||||
this.showingDownloadStatus = true;
|
||||
} else if (this.showingDownloadStatus) {
|
||||
this.showingDownloadStatus = false;
|
||||
const text = "Download Complete.";
|
||||
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
text
|
||||
);
|
||||
setTimeout(() => {
|
||||
this.syncStatus = this.application.getStatusService().removeStatus(this.syncStatus);
|
||||
}, 2000);
|
||||
} else if (stats.uploadTotalCount > 20) {
|
||||
this.uploadSyncStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.uploadSyncStatus,
|
||||
`Syncing ${stats.uploadCompletionCount}/${stats.uploadTotalCount} items...`
|
||||
);
|
||||
} else if (this.uploadSyncStatus) {
|
||||
this.uploadSyncStatus = this.application.getStatusService().removeStatus(
|
||||
this.uploadSyncStatus
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
openModalComponent(component) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.component = component;
|
||||
const el = this.$compile("<component-modal component='component' class='sk-modal'></component-modal>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
presentPermissionsDialog(dialog) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.permissionsString = dialog.permissionsString;
|
||||
scope.component = dialog.component;
|
||||
scope.callback = dialog.callback;
|
||||
const el = this.$compile("<permissions-modal component='component' permissions-string='permissionsString' callback='callback' class='sk-modal'></permissions-modal>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
overrideComponentManagerFunctions() {
|
||||
this.application.componentManager.openModalComponent = this.openModalComponent;
|
||||
this.application.componentManager.presentPermissionsDialog = this.presentPermissionsDialog;
|
||||
}
|
||||
|
||||
showInvalidSessionAlert() {
|
||||
/** Don't show repeatedly; at most 30 seconds in between */
|
||||
const SHOW_INTERVAL = 30;
|
||||
const lastShownSeconds = (new Date() - this.lastShownDate) / 1000;
|
||||
if (!this.lastShownDate || lastShownSeconds > SHOW_INTERVAL) {
|
||||
this.lastShownDate = new Date();
|
||||
setTimeout(() => {
|
||||
this.alertService.alert({
|
||||
text: STRING_SESSION_EXPIRED
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
addDragDropHandlers() {
|
||||
/**
|
||||
* Disable dragging and dropping of files (but allow text) into main SN interface.
|
||||
* both 'dragover' and 'drop' are required to prevent dropping of files.
|
||||
* This will not prevent extensions from receiving drop events.
|
||||
*/
|
||||
window.addEventListener('dragover', this.onDragOver, true);
|
||||
window.addEventListener('drop', this.onDragDrop, true);
|
||||
}
|
||||
|
||||
onDragOver(event) {
|
||||
if (event.dataTransfer.files.length > 0) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
onDragDrop(event) {
|
||||
if (event.dataTransfer.files.length > 0) {
|
||||
event.preventDefault();
|
||||
this.application.alertService.alert({
|
||||
text: STRING_DEFAULT_FILE_ERROR
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async handleAutoSignInFromParams() {
|
||||
const params = this.$location.search();
|
||||
const server = params.server;
|
||||
const email = params.email;
|
||||
const password = params.pw;
|
||||
if (!server || !email || !password) return;
|
||||
|
||||
const user = this.application.getUser();
|
||||
if (user) {
|
||||
if (user.email === email && await this.application.getHost() === server) {
|
||||
/** Already signed in, return */
|
||||
return;
|
||||
} else {
|
||||
/** Sign out */
|
||||
await this.application.signOut();
|
||||
await this.application.restart();
|
||||
}
|
||||
}
|
||||
await this.application.setHost(server);
|
||||
this.application.signIn({
|
||||
email: email,
|
||||
password: password,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ApplicationView {
|
||||
constructor() {
|
||||
this.template = template;
|
||||
this.controller = ApplicationViewCtrl;
|
||||
this.replace = true;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import { isDesktopApplication } from '@/utils';
|
||||
import { KeyboardModifiers, KeyboardKeys } from '@/services/keyboardManager';
|
||||
import template from '%/editor.pug';
|
||||
import { PureCtrl } from '@Controllers';
|
||||
import { AppStateEvents, EventSources } from '@/state';
|
||||
import { AppStateEvents, EventSources } from '@/services/state';
|
||||
import {
|
||||
STRING_DELETED_NOTE,
|
||||
STRING_INVALID_NOTE,
|
||||
@@ -48,35 +48,34 @@ const Fonts = {
|
||||
|
||||
class EditorCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$timeout,
|
||||
$rootScope,
|
||||
application,
|
||||
appState,
|
||||
desktopManager,
|
||||
keyboardManager,
|
||||
preferencesManager,
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
this.$rootScope = $rootScope;
|
||||
this.desktopManager = desktopManager;
|
||||
this.keyboardManager = keyboardManager;
|
||||
this.preferencesManager = preferencesManager;
|
||||
constructor($timeout) {
|
||||
super($timeout);
|
||||
this.leftPanelPuppet = {
|
||||
onReady: () => this.reloadPreferences()
|
||||
};
|
||||
this.rightPanelPuppet = {
|
||||
onReady: () => this.reloadPreferences()
|
||||
};
|
||||
this.addSyncStatusObserver();
|
||||
this.registerKeyboardShortcuts();
|
||||
/** Used by .pug template */
|
||||
this.prefKeyMonospace = PrefKeys.EditorMonospaceEnabled;
|
||||
this.prefKeySpellcheck = PrefKeys.EditorSpellcheck;
|
||||
this.prefKeyMarginResizers = PrefKeys.EditorResizersEnabled;
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.removeTabObserver();
|
||||
this.leftPanelPuppet = null;
|
||||
this.rightPanelPuppet = null;
|
||||
this.onEditorLoad = null;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
this.addSyncStatusObserver();
|
||||
this.registerKeyboardShortcuts();
|
||||
}
|
||||
|
||||
/** @override */
|
||||
getInitialState() {
|
||||
return {
|
||||
@@ -100,7 +99,7 @@ class EditorCtrl extends PureCtrl {
|
||||
onAppStateEvent(eventName, data) {
|
||||
if (eventName === AppStateEvents.NoteChanged) {
|
||||
this.handleNoteSelectionChange(
|
||||
this.appState.getSelectedNote(),
|
||||
this.application.getAppState().getSelectedNote(),
|
||||
data.previousNote
|
||||
);
|
||||
} else if (eventName === AppStateEvents.PreferencesChanged) {
|
||||
@@ -209,7 +208,7 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
async handleNoteSelectionChange(note, previousNote) {
|
||||
this.setState({
|
||||
note: this.appState.getSelectedNote(),
|
||||
note: this.application.getAppState().getSelectedNote(),
|
||||
showExtensions: false,
|
||||
showOptionsMenu: false,
|
||||
altKeyDown: false,
|
||||
@@ -504,7 +503,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
onContentFocus() {
|
||||
this.appState.editorDidFocus(this.lastEditorFocusEventSource);
|
||||
this.application.getAppState().editorDidFocus(this.lastEditorFocusEventSource);
|
||||
this.lastEditorFocusEventSource = null;
|
||||
}
|
||||
|
||||
@@ -552,7 +551,7 @@ class EditorCtrl extends PureCtrl {
|
||||
dontUpdatePreviews: true
|
||||
});
|
||||
}
|
||||
this.appState.setSelectedNote(null);
|
||||
this.application.getAppState().setSelectedNote(null);
|
||||
this.setMenuState('showOptionsMenu', false);
|
||||
}
|
||||
});
|
||||
@@ -561,7 +560,7 @@ class EditorCtrl extends PureCtrl {
|
||||
ProtectedActions.DeleteNote
|
||||
);
|
||||
if (requiresPrivilege) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.DeleteNote,
|
||||
() => {
|
||||
run();
|
||||
@@ -592,7 +591,7 @@ class EditorCtrl extends PureCtrl {
|
||||
bypassDebouncer: true,
|
||||
dontUpdatePreviews: true
|
||||
});
|
||||
this.appState.setSelectedNote(null);
|
||||
this.application.getAppState().setSelectedNote(null);
|
||||
}
|
||||
|
||||
deleteNotePermanantely() {
|
||||
@@ -649,7 +648,7 @@ class EditorCtrl extends PureCtrl {
|
||||
ProtectedActions.ViewProtectedNotes
|
||||
).then((configured) => {
|
||||
if (!configured) {
|
||||
this.godService.presentPrivilegesManagementModal();
|
||||
this.application.presentPrivilegesManagementModal();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -743,13 +742,13 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
onPanelResizeFinish = (width, left, isMaxWidth) => {
|
||||
if (isMaxWidth) {
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
PrefKeys.EditorWidth,
|
||||
null
|
||||
);
|
||||
} else {
|
||||
if (width !== undefined && width !== null) {
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
PrefKeys.EditorWidth,
|
||||
width
|
||||
);
|
||||
@@ -757,25 +756,25 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
if (left !== undefined && left !== null) {
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
PrefKeys.EditorLeft,
|
||||
left
|
||||
);
|
||||
this.rightPanelPuppet.setLeft(left);
|
||||
}
|
||||
this.preferencesManager.syncUserPreferences();
|
||||
this.application.getPrefsService().syncUserPreferences();
|
||||
}
|
||||
|
||||
reloadPreferences() {
|
||||
const monospaceEnabled = this.preferencesManager.getValue(
|
||||
const monospaceEnabled = this.application.getPrefsService().getValue(
|
||||
PrefKeys.EditorMonospaceEnabled,
|
||||
true
|
||||
);
|
||||
const spellcheck = this.preferencesManager.getValue(
|
||||
const spellcheck = this.application.getPrefsService().getValue(
|
||||
PrefKeys.EditorSpellcheck,
|
||||
true
|
||||
);
|
||||
const marginResizersEnabled = this.preferencesManager.getValue(
|
||||
const marginResizersEnabled = this.application.getPrefsService().getValue(
|
||||
PrefKeys.EditorResizersEnabled,
|
||||
true
|
||||
);
|
||||
@@ -797,7 +796,7 @@ class EditorCtrl extends PureCtrl {
|
||||
this.leftPanelPuppet.ready &&
|
||||
this.rightPanelPuppet.ready
|
||||
) {
|
||||
const width = this.preferencesManager.getValue(
|
||||
const width = this.application.getPrefsService().getValue(
|
||||
PrefKeys.EditorWidth,
|
||||
null
|
||||
);
|
||||
@@ -805,7 +804,7 @@ class EditorCtrl extends PureCtrl {
|
||||
this.leftPanelPuppet.setWidth(width);
|
||||
this.rightPanelPuppet.setWidth(width);
|
||||
}
|
||||
const left = this.preferencesManager.getValue(
|
||||
const left = this.application.getPrefsService().getValue(
|
||||
PrefKeys.EditorLeft,
|
||||
null
|
||||
);
|
||||
@@ -836,7 +835,7 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
async toggleKey(key) {
|
||||
this[key] = !this[key];
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
key,
|
||||
this[key],
|
||||
true
|
||||
@@ -863,7 +862,7 @@ class EditorCtrl extends PureCtrl {
|
||||
/** @components */
|
||||
|
||||
onEditorLoad = (editor) => {
|
||||
this.desktopManager.redoSearch();
|
||||
this.application.getDesktopService().redoSearch();
|
||||
}
|
||||
|
||||
registerComponentHandler() {
|
||||
@@ -1047,7 +1046,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
registerKeyboardShortcuts() {
|
||||
this.altKeyObserver = this.keyboardManager.addKeyObserver({
|
||||
this.altKeyObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
modifiers: [
|
||||
KeyboardModifiers.Alt
|
||||
],
|
||||
@@ -1063,7 +1062,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
});
|
||||
|
||||
this.trashKeyObserver = this.keyboardManager.addKeyObserver({
|
||||
this.trashKeyObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
key: KeyboardKeys.Backspace,
|
||||
notElementIds: [
|
||||
ElementIds.NoteTextEditor,
|
||||
@@ -1075,7 +1074,7 @@ class EditorCtrl extends PureCtrl {
|
||||
},
|
||||
});
|
||||
|
||||
this.deleteKeyObserver = this.keyboardManager.addKeyObserver({
|
||||
this.deleteKeyObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
key: KeyboardKeys.Backspace,
|
||||
modifiers: [
|
||||
KeyboardModifiers.Meta,
|
||||
@@ -1090,10 +1089,9 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
onSystemEditorLoad() {
|
||||
if (this.loadedTabListener) {
|
||||
if (this.tabObserver) {
|
||||
return;
|
||||
}
|
||||
this.loadedTabListener = true;
|
||||
/**
|
||||
* Insert 4 spaces when a tab key is pressed,
|
||||
* only used when inside of the text editor.
|
||||
@@ -1103,7 +1101,7 @@ class EditorCtrl extends PureCtrl {
|
||||
const editor = document.getElementById(
|
||||
ElementIds.NoteTextEditor
|
||||
);
|
||||
this.tabObserver = this.keyboardManager.addKeyObserver({
|
||||
this.tabObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
element: editor,
|
||||
key: KeyboardKeys.Tab,
|
||||
onKeyDown: (event) => {
|
||||
@@ -1144,19 +1142,29 @@ class EditorCtrl extends PureCtrl {
|
||||
* Handles when the editor is destroyed,
|
||||
* (and not when our controller is destroyed.)
|
||||
*/
|
||||
angular.element(editor).on('$destroy', () => {
|
||||
if (this.tabObserver) {
|
||||
this.keyboardManager.removeKeyObserver(this.tabObserver);
|
||||
this.loadedTabListener = false;
|
||||
}
|
||||
angular.element(editor).one('$destroy', () => {
|
||||
this.removeTabObserver();
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
removeTabObserver() {
|
||||
if (!this.application) {
|
||||
return;
|
||||
}
|
||||
const keyboardService = this.application.getKeyboardService();
|
||||
if (this.tabObserver && keyboardService) {
|
||||
keyboardService.removeKeyObserver(this.tabObserver);
|
||||
this.tabObserver = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class EditorPanel {
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
this.scope = {};
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
this.template = template;
|
||||
this.replace = true;
|
||||
this.controller = EditorCtrl;
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
ContentTypes
|
||||
} from 'snjs';
|
||||
import template from '%/footer.pug';
|
||||
import { AppStateEvents, EventSources } from '@/state';
|
||||
import { AppStateEvents, EventSources } from '@/services/state';
|
||||
import {
|
||||
STRING_GENERIC_SYNC_ERROR,
|
||||
STRING_NEW_UPDATE_READY
|
||||
@@ -17,25 +17,32 @@ class FooterCtrl extends PureCtrl {
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$rootScope,
|
||||
$timeout,
|
||||
application,
|
||||
appState,
|
||||
nativeExtManager,
|
||||
statusManager,
|
||||
godService
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
super($timeout);
|
||||
this.$rootScope = $rootScope;
|
||||
this.nativeExtManager = nativeExtManager;
|
||||
this.statusManager = statusManager;
|
||||
this.godService = godService;
|
||||
this.rooms = [];
|
||||
this.themesWithIcons = [];
|
||||
this.showSyncResolution = false;
|
||||
this.addRootScopeListeners();
|
||||
this.statusManager.addStatusObserver((string) => {
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.rooms.length = 0;
|
||||
this.themesWithIcons.length = 0;
|
||||
this.rootScopeListener1();
|
||||
this.rootScopeListener2();
|
||||
this.rootScopeListener1 = null;
|
||||
this.rootScopeListener2 = null;
|
||||
this.closeAccountMenu = null;
|
||||
this.toggleSyncResolutionMenu = null;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
this.application.getStatusService().addStatusObserver((string) => {
|
||||
this.$timeout(() => {
|
||||
this.arbitraryStatusMessage = string;
|
||||
});
|
||||
@@ -49,7 +56,7 @@ class FooterCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
reloadUpgradeStatus() {
|
||||
this.godService.checkForSecurityUpdate().then((available) => {
|
||||
this.application.checkForSecurityUpdate().then((available) => {
|
||||
this.setState({
|
||||
dataUpgradeAvailable: available
|
||||
});
|
||||
@@ -72,10 +79,10 @@ class FooterCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
addRootScopeListeners() {
|
||||
this.$rootScope.$on("reload-ext-data", () => {
|
||||
this.rootScopeListener1 = this.$rootScope.$on("reload-ext-data", () => {
|
||||
this.reloadExtendedData();
|
||||
});
|
||||
this.$rootScope.$on("new-update-available", () => {
|
||||
this.rootScopeListener2 = this.$rootScope.$on("new-update-available", () => {
|
||||
this.$timeout(() => {
|
||||
this.onNewUpdateAvailable();
|
||||
});
|
||||
@@ -90,23 +97,23 @@ class FooterCtrl extends PureCtrl {
|
||||
this.closeAccountMenu();
|
||||
}
|
||||
} else if (eventName === AppStateEvents.BeganBackupDownload) {
|
||||
this.backupStatus = this.statusManager.addStatusFromString(
|
||||
this.backupStatus = this.application.getStatusService().addStatusFromString(
|
||||
"Saving local backup..."
|
||||
);
|
||||
} else if (eventName === AppStateEvents.EndedBackupDownload) {
|
||||
if (data.success) {
|
||||
this.backupStatus = this.statusManager.replaceStatusWithString(
|
||||
this.backupStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.backupStatus,
|
||||
"Successfully saved backup."
|
||||
);
|
||||
} else {
|
||||
this.backupStatus = this.statusManager.replaceStatusWithString(
|
||||
this.backupStatus = this.application.getStatusService().replaceStatusWithString(
|
||||
this.backupStatus,
|
||||
"Unable to save local backup."
|
||||
);
|
||||
}
|
||||
this.$timeout(() => {
|
||||
this.backupStatus = this.statusManager.removeStatus(this.backupStatus);
|
||||
this.backupStatus = this.application.getStatusService().removeStatus(this.backupStatus);
|
||||
}, 2000);
|
||||
}
|
||||
}
|
||||
@@ -205,7 +212,7 @@ class FooterCtrl extends PureCtrl {
|
||||
* then closing it after a short delay.
|
||||
*/
|
||||
const extWindow = this.rooms.find((room) => {
|
||||
return room.package_info.identifier === this.nativeExtManager.extManagerId;
|
||||
return room.package_info.identifier === this.application.getNativeExtService().extManagerId;
|
||||
});
|
||||
if (!extWindow) {
|
||||
this.queueExtReload = true;
|
||||
@@ -225,7 +232,7 @@ class FooterCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
openSecurityUpdate() {
|
||||
this.godService.performProtocolUpgrade();
|
||||
this.application.performProtocolUpgrade();
|
||||
}
|
||||
|
||||
findErrors() {
|
||||
@@ -347,7 +354,7 @@ class FooterCtrl extends PureCtrl {
|
||||
ProtectedActions.ManageExtensions
|
||||
);
|
||||
if (requiresPrivilege) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.ManageExtensions,
|
||||
run
|
||||
);
|
||||
@@ -360,7 +367,7 @@ class FooterCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
clickOutsideAccountMenu() {
|
||||
if (this.godService.authenticationInProgress()) {
|
||||
if (this.application && this.application.authenticationInProgress()) {
|
||||
return;
|
||||
}
|
||||
this.showAccountMenu = false;
|
||||
@@ -370,11 +377,12 @@ class FooterCtrl extends PureCtrl {
|
||||
export class Footer {
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
this.scope = {};
|
||||
this.template = template;
|
||||
this.controller = FooterCtrl;
|
||||
this.replace = true;
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.bindToController = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,4 +4,4 @@ export { Footer } from './footer';
|
||||
export { NotesPanel } from './notes/notes';
|
||||
export { TagsPanel } from './tags';
|
||||
export { Root } from './root';
|
||||
export { LockScreen } from './lockScreen';
|
||||
export { ApplicationView } from './applicationView';
|
||||
@@ -1,5 +1,5 @@
|
||||
import template from '%/lock-screen.pug';
|
||||
import { AppStateEvents } from '@/state';
|
||||
import { AppStateEvents } from '@/services/state';
|
||||
import { PureCtrl } from './abstract/pure_ctrl';
|
||||
|
||||
const ELEMENT_ID_PASSCODE_INPUT = 'passcode-input';
|
||||
@@ -7,12 +7,9 @@ const ELEMENT_ID_PASSCODE_INPUT = 'passcode-input';
|
||||
class LockScreenCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$timeout,
|
||||
application,
|
||||
appState
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
super($timeout);
|
||||
this.formData = {};
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ import angular from 'angular';
|
||||
import template from '%/notes.pug';
|
||||
import { ApplicationEvents, ContentTypes, removeFromArray } from 'snjs';
|
||||
import { PureCtrl } from '@Controllers';
|
||||
import { AppStateEvents } from '@/state';
|
||||
import { AppStateEvents } from '@/services/state';
|
||||
import { KeyboardModifiers, KeyboardKeys } from '@/services/keyboardManager';
|
||||
import {
|
||||
PrefKeys
|
||||
@@ -31,24 +31,10 @@ class NotesCtrl extends PureCtrl {
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$timeout,
|
||||
$rootScope,
|
||||
application,
|
||||
appState,
|
||||
desktopManager,
|
||||
keyboardManager,
|
||||
preferencesManager,
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
this.$rootScope = $rootScope;
|
||||
this.application = application;
|
||||
this.appState = appState;
|
||||
this.desktopManager = desktopManager;
|
||||
this.keyboardManager = keyboardManager;
|
||||
this.preferencesManager = preferencesManager;
|
||||
super($timeout);
|
||||
this.resetPagination();
|
||||
this.registerKeyboardShortcuts();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
@@ -59,11 +45,24 @@ class NotesCtrl extends PureCtrl {
|
||||
this.panelPuppet = {
|
||||
onReady: () => this.reloadPreferences()
|
||||
};
|
||||
window.onresize = (event) => {
|
||||
this.resetPagination({
|
||||
keepCurrentIfLarger: true
|
||||
});
|
||||
};
|
||||
this.onWindowResize = this.onWindowResize.bind(this);
|
||||
window.addEventListener('resize', this.onWindowResize, true);
|
||||
this.registerKeyboardShortcuts();
|
||||
}
|
||||
|
||||
onWindowResize() {
|
||||
this.resetPagination({
|
||||
keepCurrentIfLarger: true
|
||||
});
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.panelPuppet.onReady = null;
|
||||
this.panelPuppet = null;
|
||||
window.removeEventListener('resize', this.onWindowResize, true);
|
||||
this.onWindowResize = null;
|
||||
this.onPanelResize = null;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
getInitialState() {
|
||||
@@ -91,9 +90,9 @@ class NotesCtrl extends PureCtrl {
|
||||
/** @override */
|
||||
onAppStateEvent(eventName, data) {
|
||||
if (eventName === AppStateEvents.TagChanged) {
|
||||
this.handleTagChange(this.appState.getSelectedTag(), data.previousTag);
|
||||
this.handleTagChange(this.application.getAppState().getSelectedTag(), data.previousTag);
|
||||
} else if (eventName === AppStateEvents.NoteChanged) {
|
||||
this.handleNoteSelection(this.appState.getSelectedNote());
|
||||
this.handleNoteSelection(this.application.getAppState().getSelectedNote());
|
||||
} else if (eventName === AppStateEvents.PreferencesChanged) {
|
||||
this.reloadPreferences();
|
||||
this.reloadNotes();
|
||||
@@ -129,8 +128,8 @@ class NotesCtrl extends PureCtrl {
|
||||
* @access private
|
||||
*/
|
||||
async createPlaceholderNote() {
|
||||
const selectedTag = this.appState.getSelectedTag();
|
||||
if(selectedTag.isSmartTag() && !selectedTag.content.isAllTag) {
|
||||
const selectedTag = this.application.getAppState().getSelectedTag();
|
||||
if (selectedTag.isSmartTag() && !selectedTag.content.isAllTag) {
|
||||
return;
|
||||
}
|
||||
return this.createNewNote();
|
||||
@@ -163,11 +162,11 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
async selectNote(note) {
|
||||
this.appState.setSelectedNote(note);
|
||||
this.application.getAppState().setSelectedNote(note);
|
||||
}
|
||||
|
||||
async createNewNote() {
|
||||
const selectedTag = this.appState.getSelectedTag();
|
||||
const selectedTag = this.application.getAppState().getSelectedTag();
|
||||
if (!selectedTag) {
|
||||
throw 'Attempting to create note with no selected tag';
|
||||
}
|
||||
@@ -209,11 +208,11 @@ class NotesCtrl extends PureCtrl {
|
||||
await this.selectNote(null);
|
||||
}
|
||||
await this.setState({ tag: tag });
|
||||
|
||||
|
||||
this.resetScrollPosition();
|
||||
this.setShowMenuFalse();
|
||||
await this.setNoteFilterText('');
|
||||
this.desktopManager.searchText();
|
||||
this.application.getDesktopService().searchText();
|
||||
this.resetPagination();
|
||||
|
||||
/* Capture db load state before beginning reloadNotes, since this status may change during reload */
|
||||
@@ -307,14 +306,14 @@ class NotesCtrl extends PureCtrl {
|
||||
this.application.saveItem({ item: note });
|
||||
}
|
||||
if (this.isFiltering()) {
|
||||
this.desktopManager.searchText(this.state.noteFilter.text);
|
||||
this.application.getDesktopService().searchText(this.state.noteFilter.text);
|
||||
}
|
||||
}
|
||||
|
||||
reloadPreferences() {
|
||||
const viewOptions = {};
|
||||
const prevSortValue = this.state.sortBy;
|
||||
let sortBy = this.preferencesManager.getValue(
|
||||
let sortBy = this.application.getPrefsService().getValue(
|
||||
PrefKeys.SortNotesBy,
|
||||
SORT_KEY_CREATED_AT
|
||||
);
|
||||
@@ -323,27 +322,27 @@ class NotesCtrl extends PureCtrl {
|
||||
sortBy = SORT_KEY_CLIENT_UPDATED_AT;
|
||||
}
|
||||
viewOptions.sortBy = sortBy;
|
||||
viewOptions.sortReverse = this.preferencesManager.getValue(
|
||||
viewOptions.sortReverse = this.application.getPrefsService().getValue(
|
||||
PrefKeys.SortNotesReverse,
|
||||
false
|
||||
);
|
||||
viewOptions.showArchived = this.preferencesManager.getValue(
|
||||
viewOptions.showArchived = this.application.getPrefsService().getValue(
|
||||
PrefKeys.NotesShowArchived,
|
||||
false
|
||||
);
|
||||
viewOptions.hidePinned = this.preferencesManager.getValue(
|
||||
viewOptions.hidePinned = this.application.getPrefsService().getValue(
|
||||
PrefKeys.NotesHidePinned,
|
||||
false
|
||||
);
|
||||
viewOptions.hideNotePreview = this.preferencesManager.getValue(
|
||||
viewOptions.hideNotePreview = this.application.getPrefsService().getValue(
|
||||
PrefKeys.NotesHideNotePreview,
|
||||
false
|
||||
);
|
||||
viewOptions.hideDate = this.preferencesManager.getValue(
|
||||
viewOptions.hideDate = this.application.getPrefsService().getValue(
|
||||
PrefKeys.NotesHideDate,
|
||||
false
|
||||
);
|
||||
viewOptions.hideTags = this.preferencesManager.getValue(
|
||||
viewOptions.hideTags = this.application.getPrefsService().getValue(
|
||||
PrefKeys.NotesHideTags,
|
||||
false
|
||||
);
|
||||
@@ -353,13 +352,13 @@ class NotesCtrl extends PureCtrl {
|
||||
if (prevSortValue && prevSortValue !== sortBy) {
|
||||
this.selectFirstNote();
|
||||
}
|
||||
const width = this.preferencesManager.getValue(
|
||||
const width = this.application.getPrefsService().getValue(
|
||||
PrefKeys.NotesPanelWidth
|
||||
);
|
||||
if (width && this.panelPuppet.ready) {
|
||||
this.panelPuppet.setWidth(width);
|
||||
if (this.panelPuppet.isCollapsed()) {
|
||||
this.appState.panelDidResize({
|
||||
this.application.getAppState().panelDidResize({
|
||||
name: PANEL_NAME_NOTES,
|
||||
collapsed: this.panelPuppet.isCollapsed()
|
||||
});
|
||||
@@ -368,12 +367,12 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
onPanelResize = (newWidth, lastLeft, isAtMaxWidth, isCollapsed) => {
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
PrefKeys.NotesPanelWidth,
|
||||
newWidth
|
||||
);
|
||||
this.preferencesManager.syncUserPreferences();
|
||||
this.appState.panelDidResize({
|
||||
this.application.getPrefsService().syncUserPreferences();
|
||||
this.application.getAppState().panelDidResize({
|
||||
name: PANEL_NAME_NOTES,
|
||||
collapsed: isCollapsed
|
||||
});
|
||||
@@ -383,7 +382,7 @@ class NotesCtrl extends PureCtrl {
|
||||
this.notesToDisplay += this.pageSize;
|
||||
this.reloadNotes();
|
||||
if (this.searchSubmitted) {
|
||||
this.desktopManager.searchText(this.state.noteFilter.text);
|
||||
this.application.getDesktopService().searchText(this.state.noteFilter.text);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -584,7 +583,7 @@ class NotesCtrl extends PureCtrl {
|
||||
* enter before highlighting desktop search results.
|
||||
*/
|
||||
this.searchSubmitted = true;
|
||||
this.desktopManager.searchText(this.state.noteFilter.text);
|
||||
this.application.getDesktopService().searchText(this.state.noteFilter.text);
|
||||
}
|
||||
|
||||
selectedMenuItem() {
|
||||
@@ -592,8 +591,8 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
togglePrefKey(key) {
|
||||
this.preferencesManager.setUserPrefValue(key, !this.state[key]);
|
||||
this.preferencesManager.syncUserPreferences();
|
||||
this.application.getPrefsService().setUserPrefValue(key, !this.state[key]);
|
||||
this.application.getPrefsService().syncUserPreferences();
|
||||
}
|
||||
|
||||
selectedSortByCreated() {
|
||||
@@ -610,19 +609,19 @@ class NotesCtrl extends PureCtrl {
|
||||
|
||||
toggleReverseSort() {
|
||||
this.selectedMenuItem();
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
PrefKeys.SortNotesReverse,
|
||||
!this.state.sortReverse
|
||||
);
|
||||
this.preferencesManager.syncUserPreferences();
|
||||
this.application.getPrefsService().syncUserPreferences();
|
||||
}
|
||||
|
||||
setSortBy(type) {
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
PrefKeys.SortNotesBy,
|
||||
type
|
||||
);
|
||||
this.preferencesManager.syncUserPreferences();
|
||||
this.application.getPrefsService().syncUserPreferences();
|
||||
}
|
||||
|
||||
shouldShowTagsForNote(note) {
|
||||
@@ -652,7 +651,7 @@ class NotesCtrl extends PureCtrl {
|
||||
* use Control modifier as well. These rules don't apply to desktop, but
|
||||
* probably better to be consistent.
|
||||
*/
|
||||
this.newNoteKeyObserver = this.keyboardManager.addKeyObserver({
|
||||
this.newNoteKeyObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
key: 'n',
|
||||
modifiers: [
|
||||
KeyboardModifiers.Meta,
|
||||
@@ -664,7 +663,7 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
});
|
||||
|
||||
this.nextNoteKeyObserver = this.keyboardManager.addKeyObserver({
|
||||
this.nextNoteKeyObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
key: KeyboardKeys.Down,
|
||||
elements: [
|
||||
document.body,
|
||||
@@ -679,7 +678,7 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
});
|
||||
|
||||
this.nextNoteKeyObserver = this.keyboardManager.addKeyObserver({
|
||||
this.nextNoteKeyObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
key: KeyboardKeys.Up,
|
||||
element: document.body,
|
||||
onKeyDown: (event) => {
|
||||
@@ -687,7 +686,7 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
});
|
||||
|
||||
this.searchKeyObserver = this.keyboardManager.addKeyObserver({
|
||||
this.searchKeyObserver = this.application.getKeyboardService().addKeyObserver({
|
||||
key: "f",
|
||||
modifiers: [
|
||||
KeyboardModifiers.Meta,
|
||||
@@ -703,11 +702,13 @@ class NotesCtrl extends PureCtrl {
|
||||
|
||||
export class NotesPanel {
|
||||
constructor() {
|
||||
this.scope = {};
|
||||
this.template = template;
|
||||
this.replace = true;
|
||||
this.controller = NotesCtrl;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,258 +1,16 @@
|
||||
import { getPlatformString } from '@/utils';
|
||||
import template from '%/root.pug';
|
||||
import { AppStateEvents } from '@/state';
|
||||
import { ApplicationEvents } from 'snjs';
|
||||
import angular from 'angular';
|
||||
import {
|
||||
PANEL_NAME_NOTES,
|
||||
PANEL_NAME_TAGS
|
||||
} from '@/controllers/constants';
|
||||
import {
|
||||
STRING_SESSION_EXPIRED,
|
||||
STRING_DEFAULT_FILE_ERROR,
|
||||
} from '@/strings';
|
||||
import { PureCtrl } from './abstract/pure_ctrl';
|
||||
|
||||
class RootCtrl extends PureCtrl {
|
||||
class RootCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$compile,
|
||||
$location,
|
||||
$scope,
|
||||
$rootScope,
|
||||
$timeout,
|
||||
application,
|
||||
appState,
|
||||
desktopManager,
|
||||
godService,
|
||||
lockManager,
|
||||
preferencesManager /** Unused below, required to load globally */,
|
||||
themeManager,
|
||||
statusManager,
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
this.$location = $location;
|
||||
this.$rootScope = $rootScope;
|
||||
this.$compile = $compile;
|
||||
this.desktopManager = desktopManager;
|
||||
this.godService = godService;
|
||||
this.lockManager = lockManager;
|
||||
this.statusManager = statusManager;
|
||||
this.themeManager = themeManager;
|
||||
this.platformString = getPlatformString();
|
||||
this.state = { appClass: '' };
|
||||
this.loadApplication();
|
||||
this.addDragDropHandlers();
|
||||
this.lockScreenPuppet = {
|
||||
focusInput: () => { }
|
||||
};
|
||||
}
|
||||
|
||||
async loadApplication() {
|
||||
await this.application.prepareForLaunch({
|
||||
callbacks: {
|
||||
receiveChallenge: async (challenge, orchestrator) => {
|
||||
this.godService.promptForChallenge(challenge, orchestrator);
|
||||
}
|
||||
}
|
||||
});
|
||||
await this.application.launch();
|
||||
}
|
||||
|
||||
onAppStart() {
|
||||
super.onAppStart();
|
||||
this.overrideComponentManagerFunctions();
|
||||
this.application.componentManager.setDesktopManager(this.desktopManager);
|
||||
this.setState({
|
||||
ready: true,
|
||||
needsUnlock: this.application.hasPasscode()
|
||||
constructor(applicationManager) {
|
||||
this.applicationManager = applicationManager;
|
||||
this.applicationManager.addApplicationChangeObserver(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
|
||||
onAppLaunch() {
|
||||
super.onAppLaunch();
|
||||
this.setState({ needsUnlock: false });
|
||||
this.handleAutoSignInFromParams();
|
||||
}
|
||||
|
||||
onUpdateAvailable() {
|
||||
this.$rootScope.$broadcast('new-update-available');
|
||||
};
|
||||
|
||||
/** @override */
|
||||
async onAppEvent(eventName) {
|
||||
super.onAppEvent(eventName);
|
||||
if (eventName === ApplicationEvents.LocalDataIncrementalLoad) {
|
||||
this.updateLocalDataStatus();
|
||||
} else if (eventName === ApplicationEvents.SyncStatusChanged) {
|
||||
this.updateSyncStatus();
|
||||
} else if (eventName === ApplicationEvents.LocalDataLoaded) {
|
||||
this.updateLocalDataStatus();
|
||||
} else if (eventName === ApplicationEvents.WillSync) {
|
||||
if (!this.completedInitialSync) {
|
||||
this.syncStatus = this.statusManager.replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
"Syncing..."
|
||||
);
|
||||
}
|
||||
} else if (eventName === ApplicationEvents.CompletedSync) {
|
||||
if (!this.completedInitialSync) {
|
||||
this.syncStatus = this.statusManager.removeStatus(this.syncStatus);
|
||||
this.completedInitialSync = true;
|
||||
}
|
||||
} else if (eventName === ApplicationEvents.InvalidSyncSession) {
|
||||
this.showInvalidSessionAlert();
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async onAppStateEvent(eventName, data) {
|
||||
if (eventName === AppStateEvents.PanelResized) {
|
||||
if (data.panel === PANEL_NAME_NOTES) {
|
||||
this.notesCollapsed = data.collapsed;
|
||||
}
|
||||
if (data.panel === PANEL_NAME_TAGS) {
|
||||
this.tagsCollapsed = data.collapsed;
|
||||
}
|
||||
let appClass = "";
|
||||
if (this.notesCollapsed) { appClass += "collapsed-notes"; }
|
||||
if (this.tagsCollapsed) { appClass += " collapsed-tags"; }
|
||||
this.setState({ appClass });
|
||||
} else if (eventName === AppStateEvents.WindowDidFocus) {
|
||||
if (!(await this.application.isLocked())) {
|
||||
this.application.sync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
updateLocalDataStatus() {
|
||||
const syncStatus = this.application.getSyncStatus();
|
||||
const stats = syncStatus.getStats();
|
||||
const encryption = this.application.isEncryptionAvailable();
|
||||
if (stats.localDataDone) {
|
||||
this.syncStatus = this.statusManager.removeStatus(this.syncStatus);
|
||||
return;
|
||||
}
|
||||
const notesString = `${stats.localDataCurrent}/${stats.localDataTotal} items...`;
|
||||
const loadingStatus = encryption
|
||||
? `Decrypting ${notesString}`
|
||||
: `Loading ${notesString}`;
|
||||
this.syncStatus = this.statusManager.replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
loadingStatus
|
||||
);
|
||||
}
|
||||
|
||||
updateSyncStatus() {
|
||||
const syncStatus = this.application.getSyncStatus();
|
||||
const stats = syncStatus.getStats();
|
||||
if (stats.downloadCount > 20) {
|
||||
const text = `Downloading ${stats.downloadCount} items. Keep app open.`;
|
||||
this.syncStatus = this.statusManager.replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
text
|
||||
);
|
||||
this.showingDownloadStatus = true;
|
||||
} else if (this.showingDownloadStatus) {
|
||||
this.showingDownloadStatus = false;
|
||||
const text = "Download Complete.";
|
||||
this.syncStatus = this.statusManager.replaceStatusWithString(
|
||||
this.syncStatus,
|
||||
text
|
||||
);
|
||||
setTimeout(() => {
|
||||
this.syncStatus = this.statusManager.removeStatus(this.syncStatus);
|
||||
}, 2000);
|
||||
} else if (stats.uploadTotalCount > 20) {
|
||||
this.uploadSyncStatus = this.statusManager.replaceStatusWithString(
|
||||
this.uploadSyncStatus,
|
||||
`Syncing ${stats.uploadCompletionCount}/${stats.uploadTotalCount} items...`
|
||||
);
|
||||
} else if (this.uploadSyncStatus) {
|
||||
this.uploadSyncStatus = this.statusManager.removeStatus(
|
||||
this.uploadSyncStatus
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
overrideComponentManagerFunctions() {
|
||||
function openModalComponent(component) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.component = component;
|
||||
const el = this.$compile("<component-modal component='component' class='sk-modal'></component-modal>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
function presentPermissionsDialog(dialog) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.permissionsString = dialog.permissionsString;
|
||||
scope.component = dialog.component;
|
||||
scope.callback = dialog.callback;
|
||||
const el = this.$compile("<permissions-modal component='component' permissions-string='permissionsString' callback='callback' class='sk-modal'></permissions-modal>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
this.application.componentManager.openModalComponent = openModalComponent.bind(this);
|
||||
this.application.componentManager.presentPermissionsDialog = presentPermissionsDialog.bind(this);
|
||||
}
|
||||
|
||||
showInvalidSessionAlert() {
|
||||
/** Don't show repeatedly; at most 30 seconds in between */
|
||||
const SHOW_INTERVAL = 30;
|
||||
const lastShownSeconds = (new Date() - this.lastShownDate) / 1000;
|
||||
if (!this.lastShownDate || lastShownSeconds > SHOW_INTERVAL) {
|
||||
this.lastShownDate = new Date();
|
||||
setTimeout(() => {
|
||||
this.alertService.alert({
|
||||
text: STRING_SESSION_EXPIRED
|
||||
});
|
||||
}, 500);
|
||||
}
|
||||
}
|
||||
|
||||
addDragDropHandlers() {
|
||||
/**
|
||||
* Disable dragging and dropping of files (but allow text) into main SN interface.
|
||||
* both 'dragover' and 'drop' are required to prevent dropping of files.
|
||||
* This will not prevent extensions from receiving drop events.
|
||||
*/
|
||||
window.addEventListener('dragover', (event) => {
|
||||
if (event.dataTransfer.files.length > 0) {
|
||||
event.preventDefault();
|
||||
}
|
||||
}, false);
|
||||
|
||||
window.addEventListener('drop', (event) => {
|
||||
if (event.dataTransfer.files.length > 0) {
|
||||
event.preventDefault();
|
||||
this.application.alertService.alert({
|
||||
text: STRING_DEFAULT_FILE_ERROR
|
||||
});
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
|
||||
async handleAutoSignInFromParams() {
|
||||
const params = this.$location.search();
|
||||
const server = params.server;
|
||||
const email = params.email;
|
||||
const password = params.pw;
|
||||
if (!server || !email || !password) return;
|
||||
|
||||
const user = this.application.getUser();
|
||||
if (user) {
|
||||
if (user.email === email && await this.application.getHost() === server) {
|
||||
/** Already signed in, return */
|
||||
return;
|
||||
} else {
|
||||
/** Sign out */
|
||||
await this.application.signOut();
|
||||
await this.application.restart();
|
||||
}
|
||||
}
|
||||
await this.application.setHost(server);
|
||||
this.application.signIn({
|
||||
email: email,
|
||||
password: password,
|
||||
});
|
||||
reload() {
|
||||
this.applications = this.applicationManager.getApplications();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SNNote, SNSmartTag, ContentTypes, ApplicationEvents } from 'snjs';
|
||||
import template from '%/tags.pug';
|
||||
import { AppStateEvents } from '@/state';
|
||||
import { AppStateEvents } from '@/services/state';
|
||||
import { PANEL_NAME_TAGS } from '@/controllers/constants';
|
||||
import { PrefKeys } from '@/services/preferencesManager';
|
||||
import { STRING_DELETE_TAG } from '@/strings';
|
||||
@@ -9,16 +9,9 @@ import { PureCtrl } from '@Controllers';
|
||||
class TagsPanelCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$rootScope,
|
||||
$timeout,
|
||||
application,
|
||||
appState,
|
||||
preferencesManager
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
this.$rootScope = $rootScope;
|
||||
this.preferencesManager = preferencesManager;
|
||||
super($timeout);
|
||||
this.panelPuppet = {
|
||||
onReady: () => this.loadPreferences()
|
||||
};
|
||||
@@ -92,7 +85,7 @@ class TagsPanelCtrl extends PureCtrl {
|
||||
this.loadPreferences();
|
||||
} else if (eventName === AppStateEvents.TagChanged) {
|
||||
this.setState({
|
||||
selectedTag: this.appState.getSelectedTag()
|
||||
selectedTag: this.application.getAppState().getSelectedTag()
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -136,11 +129,11 @@ class TagsPanelCtrl extends PureCtrl {
|
||||
if (!this.panelPuppet.ready) {
|
||||
return;
|
||||
}
|
||||
const width = this.preferencesManager.getValue(PrefKeys.TagsPanelWidth);
|
||||
const width = this.application.getPrefsService().getValue(PrefKeys.TagsPanelWidth);
|
||||
if (width) {
|
||||
this.panelPuppet.setWidth(width);
|
||||
if (this.panelPuppet.isCollapsed()) {
|
||||
this.appState.panelDidResize({
|
||||
this.application.getAppState().panelDidResize({
|
||||
name: PANEL_NAME_TAGS,
|
||||
collapsed: this.panelPuppet.isCollapsed()
|
||||
});
|
||||
@@ -149,12 +142,12 @@ class TagsPanelCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
onPanelResize = (newWidth, lastLeft, isAtMaxWidth, isCollapsed) => {
|
||||
this.preferencesManager.setUserPrefValue(
|
||||
this.application.getPrefsService().setUserPrefValue(
|
||||
PrefKeys.TagsPanelWidth,
|
||||
newWidth,
|
||||
true
|
||||
);
|
||||
this.appState.panelDidResize({
|
||||
this.application.getAppState().panelDidResize({
|
||||
name: PANEL_NAME_TAGS,
|
||||
collapsed: isCollapsed
|
||||
});
|
||||
@@ -202,7 +195,7 @@ class TagsPanelCtrl extends PureCtrl {
|
||||
tag.content.conflict_of = null;
|
||||
this.application.saveItem({ item: tag });
|
||||
}
|
||||
this.appState.setSelectedTag(tag);
|
||||
this.application.getAppState().setSelectedTag(tag);
|
||||
}
|
||||
|
||||
async clickedAddNewTag() {
|
||||
@@ -299,7 +292,9 @@ class TagsPanelCtrl extends PureCtrl {
|
||||
export class TagsPanel {
|
||||
constructor() {
|
||||
this.restrict = 'E';
|
||||
this.scope = {};
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
this.template = template;
|
||||
this.replace = true;
|
||||
this.controller = TagsPanelCtrl;
|
||||
|
||||
Reference in New Issue
Block a user