ApplicationManager and better memory management
This commit is contained in:
@@ -4,20 +4,16 @@ import angular from 'angular';
|
||||
import { configRoutes } from './routes';
|
||||
|
||||
import {
|
||||
Application
|
||||
} from './application';
|
||||
|
||||
import {
|
||||
AppState
|
||||
} from './state';
|
||||
ApplicationManager
|
||||
} from './applicationManager';
|
||||
|
||||
import {
|
||||
Root,
|
||||
ApplicationView,
|
||||
TagsPanel,
|
||||
NotesPanel,
|
||||
EditorPanel,
|
||||
Footer,
|
||||
LockScreen
|
||||
Footer
|
||||
} from './controllers';
|
||||
|
||||
import {
|
||||
@@ -54,18 +50,6 @@ import {
|
||||
|
||||
import { trusted } from './filters';
|
||||
|
||||
import {
|
||||
ArchiveManager,
|
||||
DesktopManager,
|
||||
KeyboardManager,
|
||||
GodService,
|
||||
LockManager,
|
||||
NativeExtManager,
|
||||
PreferencesManager,
|
||||
StatusManager,
|
||||
ThemeManager,
|
||||
} from './services';
|
||||
|
||||
angular.module('app', ['ngSanitize']);
|
||||
|
||||
// Config
|
||||
@@ -78,11 +62,12 @@ angular
|
||||
angular
|
||||
.module('app')
|
||||
.directive('root', () => new Root())
|
||||
.directive('applicationView', () => new ApplicationView())
|
||||
.directive('tagsPanel', () => new TagsPanel())
|
||||
.directive('notesPanel', () => new NotesPanel())
|
||||
.directive('editorPanel', () => new EditorPanel())
|
||||
.directive('footer', () => new Footer())
|
||||
.directive('lockScreen', () => new LockScreen());
|
||||
// .directive('lockScreen', () => new LockScreen());
|
||||
|
||||
// Directives - Functional
|
||||
angular
|
||||
@@ -93,9 +78,6 @@ angular
|
||||
.directive('elemReady', elemReady)
|
||||
.directive('fileChange', fileChange)
|
||||
.directive('infiniteScroll', [
|
||||
'$rootScope',
|
||||
'$window',
|
||||
'$timeout',
|
||||
infiniteScroll
|
||||
])
|
||||
.directive('lowercase', lowercase)
|
||||
@@ -134,16 +116,4 @@ angular
|
||||
.filter('trusted', ['$sce', trusted]);
|
||||
|
||||
// Services
|
||||
angular
|
||||
.module('app')
|
||||
.service('appState', AppState)
|
||||
.service('application', Application)
|
||||
.service('archiveManager', ArchiveManager)
|
||||
.service('desktopManager', DesktopManager)
|
||||
.service('godService', GodService)
|
||||
.service('keyboardManager', KeyboardManager)
|
||||
.service('lockManager', LockManager)
|
||||
.service('nativeExtManager', NativeExtManager)
|
||||
.service('preferencesManager', PreferencesManager)
|
||||
.service('statusManager', StatusManager)
|
||||
.service('themeManager', ThemeManager);
|
||||
angular.module('app').service('applicationManager', ApplicationManager);
|
||||
|
||||
@@ -4,13 +4,14 @@ import {
|
||||
Environments,
|
||||
platformFromString
|
||||
} from 'snjs';
|
||||
import angular from 'angular';
|
||||
import { getPlatformString } from '@/utils';
|
||||
import { AlertService } from '@/services/alertService';
|
||||
import { WebDeviceInterface } from '@/web_device_interface';
|
||||
|
||||
export class Application extends SNApplication {
|
||||
export class WebApplication extends SNApplication {
|
||||
/* @ngInject */
|
||||
constructor($timeout) {
|
||||
constructor($compile, $timeout, scope, onDeinit) {
|
||||
const deviceInterface = new WebDeviceInterface({ timeout: $timeout });
|
||||
super({
|
||||
environment: Environments.Web,
|
||||
@@ -25,6 +26,189 @@ export class Application extends SNApplication {
|
||||
}
|
||||
]
|
||||
});
|
||||
this.$compile = $compile;
|
||||
this.scope = scope;
|
||||
this.onDeinit = onDeinit;
|
||||
deviceInterface.setApplication(this);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
deinit() {
|
||||
for (const key of Object.keys(this.webServices)) {
|
||||
const service = this.webServices[key];
|
||||
if(service.deinit) {
|
||||
service.deinit();
|
||||
}
|
||||
service.application = null;
|
||||
delete this.webServices[key];
|
||||
}
|
||||
this.webServices = {};
|
||||
this.onDeinit(this);
|
||||
this.onDeinit = null;
|
||||
this.$compile = null;
|
||||
this.$timeout = null;
|
||||
this.scope.application = null;
|
||||
this.scope.$destroy();
|
||||
this.scope = null;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @access public
|
||||
* @param {object} services
|
||||
*/
|
||||
setWebServices(services) {
|
||||
this.webServices = services;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getAppState() {
|
||||
return this.webServices.appState;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getDesktopService() {
|
||||
return this.webServices.desktopService;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getLockService() {
|
||||
return this.webServices.lockService;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getArchiveService() {
|
||||
return this.webServices.archiveService;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getNativeExtService() {
|
||||
return this.webServices.nativeExtService;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getStatusService() {
|
||||
return this.webServices.statusService;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getThemeService() {
|
||||
return this.webServices.themeService;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getPrefsService() {
|
||||
return this.webServices.prefsService;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getKeyboardService() {
|
||||
return this.webServices.keyboardService;
|
||||
}
|
||||
|
||||
async checkForSecurityUpdate() {
|
||||
return this.protocolUpgradeAvailable();
|
||||
}
|
||||
|
||||
presentPasswordWizard(type) {
|
||||
const scope = this.scope.$new(true);
|
||||
scope.type = type;
|
||||
scope.application = this;
|
||||
const el = this.$compile("<password-wizard application='application' type='type'></password-wizard>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
promptForChallenge(challenge, orchestrator) {
|
||||
const scope = this.scope.$new(true);
|
||||
scope.challenge = challenge;
|
||||
scope.orchestrator = orchestrator;
|
||||
scope.application = this;
|
||||
const el = this.$compile(
|
||||
"<challenge-modal " +
|
||||
"class='sk-modal' application='application' challenge='challenge' orchestrator='orchestrator'>" +
|
||||
"</challenge-modal>"
|
||||
)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
async performProtocolUpgrade() {
|
||||
const errors = await this.upgradeProtocolVersion();
|
||||
if (errors.length === 0) {
|
||||
this.alertService.alert({
|
||||
text: "Success! Your encryption version has been upgraded." +
|
||||
" You'll be asked to enter your credentials again on other devices you're signed into."
|
||||
});
|
||||
} else {
|
||||
this.alertService.alert({
|
||||
text: "Unable to upgrade encryption version. Please try again."
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async presentPrivilegesModal(action, onSuccess, onCancel) {
|
||||
if (this.authenticationInProgress()) {
|
||||
onCancel && onCancel();
|
||||
return;
|
||||
}
|
||||
|
||||
const customSuccess = async () => {
|
||||
onSuccess && await onSuccess();
|
||||
this.currentAuthenticationElement = null;
|
||||
};
|
||||
const customCancel = async () => {
|
||||
onCancel && await onCancel();
|
||||
this.currentAuthenticationElement = null;
|
||||
};
|
||||
|
||||
const scope = this.scope.$new(true);
|
||||
scope.action = action;
|
||||
scope.onSuccess = customSuccess;
|
||||
scope.onCancel = customCancel;
|
||||
scope.application = this;
|
||||
const el = this.$compile(`
|
||||
<privileges-auth-modal application='application' action='action' on-success='onSuccess'
|
||||
on-cancel='onCancel' class='sk-modal'></privileges-auth-modal>
|
||||
`)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
|
||||
this.currentAuthenticationElement = el;
|
||||
}
|
||||
|
||||
presentPrivilegesManagementModal() {
|
||||
const scope = this.scope.$new(true);
|
||||
scope.application = this;
|
||||
const el = this.$compile("<privileges-management-modal application='application' class='sk-modal'></privileges-management-modal>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
authenticationInProgress() {
|
||||
return this.currentAuthenticationElement != null;
|
||||
}
|
||||
|
||||
presentPasswordModal(callback) {
|
||||
const scope = this.scope.$new(true);
|
||||
scope.type = "password";
|
||||
scope.title = "Decryption Assistance";
|
||||
scope.message = `Unable to decrypt this item with your current keys.
|
||||
Please enter your account password at the time of this revision.`;
|
||||
scope.callback = callback;
|
||||
const el = this.$compile(
|
||||
`<input-modal type='type' message='message'
|
||||
title='title' callback='callback'></input-modal>`
|
||||
)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
presentRevisionPreviewModal(uuid, content) {
|
||||
const scope = this.scope.$new(true);
|
||||
scope.uuid = uuid;
|
||||
scope.content = content;
|
||||
scope.application = this;
|
||||
const el = this.$compile(
|
||||
`<revision-preview-modal application='application' uuid='uuid' content='content'
|
||||
class='sk-modal'></revision-preview-modal>`
|
||||
)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
}
|
||||
125
app/assets/javascripts/applicationManager.js
Normal file
125
app/assets/javascripts/applicationManager.js
Normal file
@@ -0,0 +1,125 @@
|
||||
import { WebApplication } from './application';
|
||||
import { removeFromArray } from 'snjs';
|
||||
import {
|
||||
ArchiveManager,
|
||||
DesktopManager,
|
||||
KeyboardManager,
|
||||
LockManager,
|
||||
NativeExtManager,
|
||||
PreferencesManager,
|
||||
StatusManager,
|
||||
ThemeManager,
|
||||
AppState
|
||||
} from './services';
|
||||
|
||||
export class ApplicationManager {
|
||||
/* @ngInject */
|
||||
constructor($compile, $rootScope, $timeout) {
|
||||
this.$compile = $compile;
|
||||
this.$timeout = $timeout;
|
||||
this.$rootScope = $rootScope;
|
||||
this.applications = [];
|
||||
this.changeObservers = [];
|
||||
this.onApplicationDeinit = this.onApplicationDeinit.bind(this);
|
||||
this.createDefaultApplication();
|
||||
}
|
||||
|
||||
/** @access private */
|
||||
createDefaultApplication() {
|
||||
this.activeApplication = this.createNewApplication();
|
||||
this.applications.push(this.activeApplication);
|
||||
this.notifyObserversOfAppChange();
|
||||
}
|
||||
|
||||
/** @callback */
|
||||
onApplicationDeinit(application) {
|
||||
removeFromArray(this.applications, application);
|
||||
if(this.activeApplication === application) {
|
||||
this.activeApplication = null;
|
||||
}
|
||||
if (this.applications.length === 0) {
|
||||
this.createDefaultApplication();
|
||||
}
|
||||
this.notifyObserversOfAppChange();
|
||||
}
|
||||
|
||||
/** @access private */
|
||||
createNewApplication() {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
const application = new WebApplication(
|
||||
this.$compile,
|
||||
this.$timeout,
|
||||
scope,
|
||||
this.onApplicationDeinit
|
||||
);
|
||||
const appState = new AppState(
|
||||
this.$rootScope,
|
||||
this.$timeout,
|
||||
application
|
||||
);
|
||||
const archiveService = new ArchiveManager(
|
||||
application
|
||||
);
|
||||
const desktopService = new DesktopManager(
|
||||
this.$rootScope,
|
||||
this.$timeout,
|
||||
application
|
||||
);
|
||||
const keyboardService = new KeyboardManager();
|
||||
const lockService = new LockManager(
|
||||
application
|
||||
);
|
||||
const nativeExtService = new NativeExtManager(
|
||||
application
|
||||
);
|
||||
const prefsService = new PreferencesManager(
|
||||
application
|
||||
);
|
||||
const statusService = new StatusManager();
|
||||
const themeService = new ThemeManager(
|
||||
application,
|
||||
);
|
||||
application.setWebServices({
|
||||
appState,
|
||||
archiveService,
|
||||
desktopService,
|
||||
keyboardService,
|
||||
lockService,
|
||||
nativeExtService,
|
||||
prefsService,
|
||||
statusService,
|
||||
themeService
|
||||
});
|
||||
return application;
|
||||
}
|
||||
|
||||
get application() {
|
||||
return this.activeApplication;
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
getApplications() {
|
||||
return this.applications.slice();
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies observer when the active application has changed.
|
||||
* Any application which is no longer active is destroyed, and
|
||||
* must be removed from the interface.
|
||||
* @access public
|
||||
* @param {function} callback
|
||||
*/
|
||||
addApplicationChangeObserver(callback) {
|
||||
this.changeObservers.push(callback);
|
||||
if (this.application) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
notifyObserversOfAppChange() {
|
||||
for (const observer of this.changeObservers) {
|
||||
observer();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -3,27 +3,38 @@ export function clickOutside($document) {
|
||||
return {
|
||||
restrict: 'A',
|
||||
replace: false,
|
||||
link: function($scope, $element, attrs) {
|
||||
var didApplyClickOutside = false;
|
||||
link: function ($scope, $element, attrs) {
|
||||
// Causes memory leak as-is:
|
||||
// let didApplyClickOutside = false;
|
||||
|
||||
$element.bind('click', function(e) {
|
||||
didApplyClickOutside = false;
|
||||
if (attrs.isOpen) {
|
||||
e.stopPropagation();
|
||||
}
|
||||
});
|
||||
// $scope.$on('$destroy', () => {
|
||||
// attrs.clickOutside = null;
|
||||
// $element.unbind('click', $scope.onElementClick);
|
||||
// $document.unbind('click', $scope.onDocumentClick);
|
||||
// $scope.onElementClick = null;
|
||||
// $scope.onDocumentClick = null;
|
||||
// });
|
||||
|
||||
$document.bind('click', function() {
|
||||
// Ignore click if on SKAlert
|
||||
if (event.target.closest(".sk-modal")) {
|
||||
return;
|
||||
}
|
||||
// $scope.onElementClick = (event) => {
|
||||
// didApplyClickOutside = false;
|
||||
// if (attrs.isOpen) {
|
||||
// event.stopPropagation();
|
||||
// }
|
||||
// };
|
||||
|
||||
// $scope.onDocumentClick = (event) => {
|
||||
// /* Ignore click if on SKAlert */
|
||||
// if (event.target.closest('.sk-modal')) {
|
||||
// return;
|
||||
// }
|
||||
// if (!didApplyClickOutside) {
|
||||
// $scope.$apply(attrs.clickOutside);
|
||||
// didApplyClickOutside = true;
|
||||
// }
|
||||
// };
|
||||
|
||||
if (!didApplyClickOutside) {
|
||||
$scope.$apply(attrs.clickOutside);
|
||||
didApplyClickOutside = true;
|
||||
}
|
||||
});
|
||||
// $element.bind('click', $scope.onElementClick);
|
||||
// $document.bind('click', $scope.onDocumentClick);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
/* @ngInject */
|
||||
export function infiniteScroll($rootScope, $window, $timeout) {
|
||||
export function infiniteScroll() {
|
||||
return {
|
||||
link: function(scope, elem, attrs) {
|
||||
const offset = parseInt(attrs.threshold) || 0;
|
||||
const e = elem[0];
|
||||
elem.on('scroll', function() {
|
||||
scope.onScroll = () => {
|
||||
if (
|
||||
scope.$eval(attrs.canLoad) &&
|
||||
e.scrollTop + e.offsetHeight >= e.scrollHeight - offset
|
||||
) {
|
||||
scope.$apply(attrs.infiniteScroll);
|
||||
}
|
||||
};
|
||||
elem.on('scroll', scope.onScroll);
|
||||
scope.$on('$destroy', () => {
|
||||
elem.off('scroll', scope.onScroll);;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
@@ -28,32 +28,18 @@ const ELEMENT_NAME_AUTH_PASSWORD_CONF = 'password_conf';
|
||||
class AccountMenuCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$rootScope,
|
||||
$timeout,
|
||||
appVersion,
|
||||
application,
|
||||
appState,
|
||||
archiveManager,
|
||||
godService,
|
||||
lockManager,
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
this.$rootScope = $rootScope;
|
||||
this.appState = appState;
|
||||
this.application = application;
|
||||
this.archiveManager = archiveManager;
|
||||
this.godService = godService;
|
||||
this.lockManager = lockManager;
|
||||
super($timeout);
|
||||
this.appVersion = appVersion;
|
||||
this.syncStatus = this.application.getSyncStatus();
|
||||
}
|
||||
|
||||
/** @override */
|
||||
getInitialState() {
|
||||
return {
|
||||
appVersion: 'v' + (window.electronAppVersion || this.appVersion),
|
||||
passcodeAutoLockOptions: this.lockManager.getAutoLockIntervalOptions(),
|
||||
passcodeAutoLockOptions: this.application.getLockService().getAutoLockIntervalOptions(),
|
||||
user: this.application.getUser(),
|
||||
formData: {
|
||||
mergeLocal: true,
|
||||
@@ -90,11 +76,12 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
this.initProps({
|
||||
closeFunction: this.closeFunction
|
||||
});
|
||||
this.syncStatus = this.application.getSyncStatus();
|
||||
}
|
||||
|
||||
close() {
|
||||
this.$timeout(() => {
|
||||
this.props.closeFunction()();
|
||||
this.props.closeFunction();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -277,19 +264,19 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
|
||||
openPasswordWizard() {
|
||||
this.close();
|
||||
this.godService.presentPasswordWizard();
|
||||
this.application.presentPasswordWizard();
|
||||
}
|
||||
|
||||
async openPrivilegesModal() {
|
||||
this.close();
|
||||
const run = () => {
|
||||
this.godService.presentPrivilegesManagementModal();
|
||||
this.application.presentPrivilegesManagementModal();
|
||||
};
|
||||
const needsPrivilege = await this.application.privilegesService.actionRequiresPrivilege(
|
||||
ProtectedActions.ManagePrivileges
|
||||
);
|
||||
if (needsPrivilege) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.ManagePrivileges,
|
||||
() => {
|
||||
run();
|
||||
@@ -366,7 +353,7 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
ProtectedActions.ManageBackups
|
||||
);
|
||||
if (needsPrivilege) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.ManageBackups,
|
||||
run
|
||||
);
|
||||
@@ -416,7 +403,7 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
async downloadDataArchive() {
|
||||
this.archiveManager.downloadBackup(this.state.mutable.backupEncrypted);
|
||||
this.application.getArchiveService().downloadBackup(this.state.mutable.backupEncrypted);
|
||||
}
|
||||
|
||||
notesAndTagsCount() {
|
||||
@@ -434,7 +421,7 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
async reloadAutoLockInterval() {
|
||||
const interval = await this.lockManager.getAutoLockInterval();
|
||||
const interval = await this.application.getLockService().getAutoLockInterval();
|
||||
this.setState({
|
||||
selectedAutoLockInterval: interval
|
||||
});
|
||||
@@ -442,14 +429,14 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
|
||||
async selectAutoLockInterval(interval) {
|
||||
const run = async () => {
|
||||
await this.lockManager.setAutoLockInterval(interval);
|
||||
await this.application.getLockService().setAutoLockInterval(interval);
|
||||
this.reloadAutoLockInterval();
|
||||
};
|
||||
const needsPrivilege = await this.application.privilegesService.actionRequiresPrivilege(
|
||||
ProtectedActions.ManagePasscode
|
||||
);
|
||||
if (needsPrivilege) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.ManagePasscode,
|
||||
() => {
|
||||
run();
|
||||
@@ -508,7 +495,7 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
ProtectedActions.ManagePasscode
|
||||
);
|
||||
if (needsPrivilege) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.ManagePasscode,
|
||||
run
|
||||
);
|
||||
@@ -536,7 +523,7 @@ class AccountMenuCtrl extends PureCtrl {
|
||||
ProtectedActions.ManagePasscode
|
||||
);
|
||||
if (needsPrivilege) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.ManagePasscode,
|
||||
run
|
||||
);
|
||||
@@ -558,7 +545,8 @@ export class AccountMenu {
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
closeFunction: '&'
|
||||
closeFunction: '&',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,14 +4,9 @@ import { PureCtrl } from '@Controllers';
|
||||
class ActionsMenuCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$timeout,
|
||||
application,
|
||||
appState,
|
||||
godService
|
||||
$timeout
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
this.godService = godService;
|
||||
super($timeout);
|
||||
this.state = {
|
||||
extensions: []
|
||||
};
|
||||
@@ -77,7 +72,7 @@ class ActionsMenuCtrl extends PureCtrl {
|
||||
switch (action.verb) {
|
||||
case 'render': {
|
||||
const item = result.item;
|
||||
this.godService.presentRevisionPreviewModal(
|
||||
this.application.presentRevisionPreviewModal(
|
||||
item.uuid,
|
||||
item.content
|
||||
);
|
||||
@@ -111,7 +106,8 @@ export class ActionsMenu {
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
item: '='
|
||||
item: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,10 @@ import { PureCtrl } from '@Controllers';
|
||||
class ChallengeModalCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$element,
|
||||
$timeout,
|
||||
application,
|
||||
appState
|
||||
$timeout
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
super($timeout);
|
||||
this.$element = $element;
|
||||
this.processingTypes = [];
|
||||
}
|
||||
@@ -48,6 +45,13 @@ class ChallengeModalCtrl extends PureCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.application = null;
|
||||
this.orchestrator = null;
|
||||
this.challenge = null;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
reloadProcessingStatus() {
|
||||
this.setState({
|
||||
processing: this.processingTypes.length > 0
|
||||
@@ -106,7 +110,10 @@ class ChallengeModalCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$element.remove();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,11 +123,10 @@ export class ChallengeModal {
|
||||
this.template = template;
|
||||
this.controller = ChallengeModalCtrl;
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
onSubmit: '=',
|
||||
this.bindToController = {
|
||||
challenge: '=',
|
||||
orchestrator: '='
|
||||
orchestrator: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,18 +2,19 @@ import template from '%/directives/component-modal.pug';
|
||||
|
||||
export class ComponentModalCtrl {
|
||||
/* @ngInject */
|
||||
constructor($scope, $element) {
|
||||
constructor($element) {
|
||||
this.$element = $element;
|
||||
this.$scope = $scope;
|
||||
}
|
||||
|
||||
dismiss(callback) {
|
||||
this.$element.remove();
|
||||
this.$scope.$destroy();
|
||||
if(this.onDismiss && this.onDismiss()) {
|
||||
this.onDismiss()(this.component);
|
||||
if(this.onDismiss) {
|
||||
this.onDismiss(this.component);
|
||||
}
|
||||
callback && callback();
|
||||
this.callback && this.callback();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,26 +14,41 @@ class ComponentViewCtrl {
|
||||
$scope,
|
||||
$rootScope,
|
||||
$timeout,
|
||||
application,
|
||||
desktopManager,
|
||||
themeManager
|
||||
) {
|
||||
this.$rootScope = $rootScope;
|
||||
this.$timeout = $timeout;
|
||||
this.application = application;
|
||||
this.themeManager = themeManager;
|
||||
this.desktopManager = desktopManager;
|
||||
this.componentValid = true;
|
||||
|
||||
$scope.$watch('ctrl.component', (component, prevComponent) => {
|
||||
this.cleanUpWatch = $scope.$watch('ctrl.component', (component, prevComponent) => {
|
||||
this.componentValueDidSet(component, prevComponent);
|
||||
});
|
||||
$scope.$on('ext-reload-complete', () => {
|
||||
this.cleanUpOn = $scope.$on('ext-reload-complete', () => {
|
||||
this.reloadStatus(false);
|
||||
});
|
||||
$scope.$on('$destroy', () => {
|
||||
this.destroy();
|
||||
});
|
||||
|
||||
/** To allow for registering events */
|
||||
this.onVisibilityChange = this.onVisibilityChange.bind(this);
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.cleanUpWatch();
|
||||
this.cleanUpOn();
|
||||
this.cleanUpWatch = null;
|
||||
this.cleanUpOn = null;
|
||||
this.application.componentManager.deregisterHandler(this.themeHandlerIdentifier);
|
||||
this.application.componentManager.deregisterHandler(this.identifier);
|
||||
if (this.component && !this.manualDealloc) {
|
||||
const dontSync = true;
|
||||
this.application.componentManager.deactivateComponent(this.component, dontSync);
|
||||
}
|
||||
this.application.getDesktopService().deregisterUpdateObserver(this.updateObserver);
|
||||
document.removeEventListener(
|
||||
VISIBILITY_CHANGE_LISTENER_KEY,
|
||||
this.onVisibilityChange
|
||||
);
|
||||
this.component = null;
|
||||
this.onLoad = null;
|
||||
this.application = null;
|
||||
this.onVisibilityChange = null;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
@@ -42,12 +57,12 @@ class ComponentViewCtrl {
|
||||
};
|
||||
|
||||
registerPackageUpdateObserver() {
|
||||
this.updateObserver = this.desktopManager
|
||||
.registerUpdateObserver((component) => {
|
||||
if(component === this.component && component.active) {
|
||||
this.reloadComponent();
|
||||
}
|
||||
});
|
||||
this.updateObserver = this.application.getDesktopService()
|
||||
.registerUpdateObserver((component) => {
|
||||
if (component === this.component && component.active) {
|
||||
this.reloadComponent();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
registerComponentHandlers() {
|
||||
@@ -65,7 +80,7 @@ class ComponentViewCtrl {
|
||||
identifier: this.identifier,
|
||||
areas: [this.component.area],
|
||||
activationHandler: (component) => {
|
||||
if(component !== this.component) {
|
||||
if (component !== this.component) {
|
||||
return;
|
||||
}
|
||||
this.$timeout(() => {
|
||||
@@ -73,7 +88,7 @@ class ComponentViewCtrl {
|
||||
});
|
||||
},
|
||||
actionHandler: (component, action, data) => {
|
||||
if(action === 'set-size') {
|
||||
if (action === 'set-size') {
|
||||
this.application.componentManager.handleSetSizeEvent(component, data);
|
||||
}
|
||||
}
|
||||
@@ -81,10 +96,10 @@ class ComponentViewCtrl {
|
||||
}
|
||||
|
||||
onVisibilityChange() {
|
||||
if(document.visibilityState === 'hidden') {
|
||||
if (document.visibilityState === 'hidden') {
|
||||
return;
|
||||
}
|
||||
if(this.issueLoading) {
|
||||
if (this.issueLoading) {
|
||||
this.reloadComponent();
|
||||
}
|
||||
}
|
||||
@@ -100,34 +115,34 @@ class ComponentViewCtrl {
|
||||
const component = this.component;
|
||||
const previouslyValid = this.componentValid;
|
||||
const offlineRestricted = component.offlineOnly && !isDesktopApplication();
|
||||
const hasUrlError = function(){
|
||||
if(isDesktopApplication()) {
|
||||
const hasUrlError = function () {
|
||||
if (isDesktopApplication()) {
|
||||
return !component.local_url && !component.hasValidHostedUrl();
|
||||
} else {
|
||||
return !component.hasValidHostedUrl();
|
||||
}
|
||||
}();
|
||||
this.expired = component.valid_until && component.valid_until <= new Date();
|
||||
if(!component.lockReadonly) {
|
||||
if (!component.lockReadonly) {
|
||||
component.readonly = this.expired;
|
||||
}
|
||||
this.componentValid = !offlineRestricted && !hasUrlError;
|
||||
if(!this.componentValid) {
|
||||
if (!this.componentValid) {
|
||||
this.loading = false;
|
||||
}
|
||||
if(offlineRestricted) {
|
||||
if (offlineRestricted) {
|
||||
this.error = 'offline-restricted';
|
||||
} else if(hasUrlError) {
|
||||
} else if (hasUrlError) {
|
||||
this.error = 'url-missing';
|
||||
} else {
|
||||
this.error = null;
|
||||
}
|
||||
if(this.componentValid !== previouslyValid) {
|
||||
if(this.componentValid) {
|
||||
if (this.componentValid !== previouslyValid) {
|
||||
if (this.componentValid) {
|
||||
this.application.componentManager.reloadComponent(component, true);
|
||||
}
|
||||
}
|
||||
if(this.expired && doManualReload) {
|
||||
if (this.expired && doManualReload) {
|
||||
this.$rootScope.$broadcast('reload-ext-dat');
|
||||
}
|
||||
|
||||
@@ -137,17 +152,17 @@ class ComponentViewCtrl {
|
||||
}
|
||||
|
||||
handleActivation() {
|
||||
if(!this.component.active) {
|
||||
if (!this.component.active) {
|
||||
return;
|
||||
}
|
||||
const iframe = this.application.componentManager.iframeForComponent(
|
||||
this.component
|
||||
);
|
||||
if(!iframe) {
|
||||
if (!iframe) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
if(this.loadTimeout) {
|
||||
if (this.loadTimeout) {
|
||||
this.$timeout.cancel(this.loadTimeout);
|
||||
}
|
||||
this.loadTimeout = this.$timeout(() => {
|
||||
@@ -160,16 +175,16 @@ class ComponentViewCtrl {
|
||||
}
|
||||
|
||||
async handleIframeLoadTimeout() {
|
||||
if(this.loading) {
|
||||
if (this.loading) {
|
||||
this.loading = false;
|
||||
this.issueLoading = true;
|
||||
if(!this.didAttemptReload) {
|
||||
if (!this.didAttemptReload) {
|
||||
this.didAttemptReload = true;
|
||||
this.reloadComponent();
|
||||
} else {
|
||||
document.addEventListener(
|
||||
VISIBILITY_CHANGE_LISTENER_KEY,
|
||||
this.onVisibilityChange.bind(this)
|
||||
this.onVisibilityChange
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -177,13 +192,13 @@ class ComponentViewCtrl {
|
||||
|
||||
async handleIframeLoad(iframe) {
|
||||
let desktopError = false;
|
||||
if(isDesktopApplication()) {
|
||||
if (isDesktopApplication()) {
|
||||
try {
|
||||
/** Accessing iframe.contentWindow.origin only allowed in desktop app. */
|
||||
if(!iframe.contentWindow.origin || iframe.contentWindow.origin === 'null') {
|
||||
if (!iframe.contentWindow.origin || iframe.contentWindow.origin === 'null') {
|
||||
desktopError = true;
|
||||
}
|
||||
} catch (e) {}
|
||||
} catch (e) { }
|
||||
}
|
||||
this.$timeout.cancel(this.loadTimeout);
|
||||
await this.application.componentManager.registerComponentWindow(
|
||||
@@ -201,13 +216,13 @@ class ComponentViewCtrl {
|
||||
|
||||
componentValueDidSet(component, prevComponent) {
|
||||
const dontSync = true;
|
||||
if(prevComponent && component !== prevComponent) {
|
||||
if (prevComponent && component !== prevComponent) {
|
||||
this.application.componentManager.deactivateComponent(
|
||||
prevComponent,
|
||||
dontSync
|
||||
);
|
||||
}
|
||||
if(component) {
|
||||
if (component) {
|
||||
this.application.componentManager.activateComponent(
|
||||
component,
|
||||
dontSync
|
||||
@@ -217,7 +232,7 @@ class ComponentViewCtrl {
|
||||
}
|
||||
|
||||
disableActiveTheme() {
|
||||
this.themeManager.deactivateAllThemes();
|
||||
this.application.getThemeService().deactivateAllThemes();
|
||||
}
|
||||
|
||||
getUrl() {
|
||||
@@ -225,21 +240,6 @@ class ComponentViewCtrl {
|
||||
this.component.runningLocally = (url === this.component.local_url);
|
||||
return url;
|
||||
}
|
||||
|
||||
destroy() {
|
||||
this.application.componentManager.deregisterHandler(this.themeHandlerIdentifier);
|
||||
this.application.componentManager.deregisterHandler(this.identifier);
|
||||
if(this.component && !this.manualDealloc) {
|
||||
const dontSync = true;
|
||||
this.application.componentManager.deactivateComponent(this.component, dontSync);
|
||||
}
|
||||
|
||||
this.desktopManager.deregisterUpdateObserver(this.updateObserver);
|
||||
document.removeEventListener(
|
||||
VISIBILITY_CHANGE_LISTENER_KEY,
|
||||
this.onVisibilityChange.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class ComponentView {
|
||||
@@ -249,7 +249,8 @@ export class ComponentView {
|
||||
this.scope = {
|
||||
component: '=',
|
||||
onLoad: '=?',
|
||||
manualDealloc: '=?'
|
||||
manualDealloc: '=?',
|
||||
application: '='
|
||||
};
|
||||
this.controller = ComponentViewCtrl;
|
||||
this.controllerAs = 'ctrl';
|
||||
|
||||
@@ -2,14 +2,8 @@ import template from '%/directives/conflict-resolution-modal.pug';
|
||||
|
||||
class ConflictResolutionCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$element,
|
||||
archiveManager,
|
||||
application
|
||||
) {
|
||||
constructor($element) {
|
||||
this.$element = $element;
|
||||
this.application = application;
|
||||
this.archiveManager = archiveManager;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
@@ -56,7 +50,7 @@ class ConflictResolutionCtrl {
|
||||
}
|
||||
|
||||
export() {
|
||||
this.archiveManager.downloadBackupOfItems(
|
||||
this.application.getArchiveService().downloadBackupOfItems(
|
||||
[this.item1, this.item2],
|
||||
true
|
||||
);
|
||||
@@ -67,7 +61,10 @@ class ConflictResolutionCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$element.remove();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,7 +78,8 @@ export class ConflictResolutionModal {
|
||||
this.scope = {
|
||||
item1: '=',
|
||||
item2: '=',
|
||||
callback: '='
|
||||
callback: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,12 +5,9 @@ import { PureCtrl } from '@Controllers';
|
||||
class EditorMenuCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$timeout,
|
||||
application,
|
||||
appState
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
super($timeout);
|
||||
this.state = {
|
||||
isDesktop: isDesktopApplication()
|
||||
};
|
||||
@@ -98,7 +95,8 @@ export class EditorMenu {
|
||||
this.scope = {
|
||||
callback: '&',
|
||||
selectedEditor: '=',
|
||||
currentItem: '='
|
||||
currentItem: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,14 +3,16 @@ import template from '%/directives/input-modal.pug';
|
||||
class InputModalCtrl {
|
||||
|
||||
/* @ngInject */
|
||||
constructor($scope, $element) {
|
||||
constructor($element) {
|
||||
this.$element = $element;
|
||||
this.formData = {};
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$element.remove();
|
||||
this.$scope.$destroy();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
|
||||
submit() {
|
||||
|
||||
@@ -26,13 +26,17 @@ class PanelResizerCtrl {
|
||||
constructor(
|
||||
$compile,
|
||||
$element,
|
||||
$scope,
|
||||
$timeout,
|
||||
) {
|
||||
this.$compile = $compile;
|
||||
this.$element = $element;
|
||||
this.$scope = $scope;
|
||||
this.$timeout = $timeout;
|
||||
|
||||
/** To allow for registering events */
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
this.onMouseMove = this.onMouseMove.bind(this);
|
||||
this.onMouseUp = this.onMouseUp.bind(this);
|
||||
this.onMouseDown = this.onMouseDown.bind(this);
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
@@ -45,6 +49,19 @@ class PanelResizerCtrl {
|
||||
this.addMouseUpListener();
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
this.onResizeFinish = null;
|
||||
this.control = null;
|
||||
window.removeEventListener(WINDOW_EVENT_RESIZE, this.handleResize);
|
||||
document.removeEventListener(MouseEvents.Move, this.onMouseMove);
|
||||
document.removeEventListener(MouseEvents.Up, this.onMouseUp);
|
||||
this.resizerColumn.removeEventListener(MouseEvents.Down, this.onMouseDown);
|
||||
this.handleResize = null;
|
||||
this.onMouseMove = null;
|
||||
this.onMouseUp = null;
|
||||
this.onMouseDown = null;
|
||||
}
|
||||
|
||||
configureControl() {
|
||||
this.control.setWidth = (value) => {
|
||||
this.setWidth(value, true);
|
||||
@@ -96,17 +113,17 @@ class PanelResizerCtrl {
|
||||
}
|
||||
|
||||
configureRightPanel() {
|
||||
const handleResize = debounce(event => {
|
||||
window.addEventListener(WINDOW_EVENT_RESIZE, this.handleResize);
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
debounce(() => {
|
||||
this.reloadDefaultValues();
|
||||
this.handleWidthEvent();
|
||||
this.$timeout(() => {
|
||||
this.finishSettingWidth();
|
||||
});
|
||||
}, 250);
|
||||
window.addEventListener(WINDOW_EVENT_RESIZE, handleResize);
|
||||
this.$scope.$on('$destroy', () => {
|
||||
window.removeEventListener(WINDOW_EVENT_RESIZE, handleResize);
|
||||
});
|
||||
}
|
||||
|
||||
getParentRect() {
|
||||
@@ -135,7 +152,7 @@ class PanelResizerCtrl {
|
||||
this.finishSettingWidth();
|
||||
|
||||
const newCollapseState = !preClickCollapseState;
|
||||
this.onResizeFinish()(
|
||||
this.onResizeFinish(
|
||||
this.lastWidth,
|
||||
this.lastLeft,
|
||||
this.isAtMaxWidth(),
|
||||
@@ -146,31 +163,35 @@ class PanelResizerCtrl {
|
||||
}
|
||||
|
||||
addMouseDownListener() {
|
||||
this.resizerColumn.addEventListener(MouseEvents.Down, (event) => {
|
||||
this.addInvisibleOverlay();
|
||||
this.pressed = true;
|
||||
this.lastDownX = event.clientX;
|
||||
this.startWidth = this.panel.scrollWidth;
|
||||
this.startLeft = this.panel.offsetLeft;
|
||||
this.panel.classList.add(CssClasses.NoSelection);
|
||||
if (this.hoverable) {
|
||||
this.resizerColumn.classList.add(CssClasses.Dragging);
|
||||
}
|
||||
});
|
||||
this.resizerColumn.addEventListener(MouseEvents.Down, this.onMouseDown);
|
||||
}
|
||||
|
||||
onMouseDown(event) {
|
||||
this.addInvisibleOverlay();
|
||||
this.pressed = true;
|
||||
this.lastDownX = event.clientX;
|
||||
this.startWidth = this.panel.scrollWidth;
|
||||
this.startLeft = this.panel.offsetLeft;
|
||||
this.panel.classList.add(CssClasses.NoSelection);
|
||||
if (this.hoverable) {
|
||||
this.resizerColumn.classList.add(CssClasses.Dragging);
|
||||
}
|
||||
}
|
||||
|
||||
addMouseMoveListener() {
|
||||
document.addEventListener(MouseEvents.Move, (event) => {
|
||||
if (!this.pressed) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (this.property && this.property === PanelSides.Left) {
|
||||
this.handleLeftEvent(event);
|
||||
} else {
|
||||
this.handleWidthEvent(event);
|
||||
}
|
||||
});
|
||||
document.addEventListener(MouseEvents.Move, this.onMouseMove);
|
||||
}
|
||||
|
||||
onMouseMove(event) {
|
||||
if (!this.pressed) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
if (this.property && this.property === PanelSides.Left) {
|
||||
this.handleLeftEvent(event);
|
||||
} else {
|
||||
this.handleWidthEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
handleWidthEvent(event) {
|
||||
@@ -186,9 +207,6 @@ class PanelResizerCtrl {
|
||||
const deltaX = x - this.lastDownX;
|
||||
const newWidth = this.startWidth + deltaX;
|
||||
this.setWidth(newWidth, false);
|
||||
if (this.onResize()) {
|
||||
this.onResize()(this.lastWidth, this.panel);
|
||||
}
|
||||
}
|
||||
|
||||
handleLeftEvent(event) {
|
||||
@@ -216,24 +234,27 @@ class PanelResizerCtrl {
|
||||
}
|
||||
|
||||
addMouseUpListener() {
|
||||
document.addEventListener(MouseEvents.Up, event => {
|
||||
this.removeInvisibleOverlay();
|
||||
if (this.pressed) {
|
||||
this.pressed = false;
|
||||
this.resizerColumn.classList.remove(CssClasses.Dragging);
|
||||
this.panel.classList.remove(CssClasses.NoSelection);
|
||||
const isMaxWidth = this.isAtMaxWidth();
|
||||
if (this.onResizeFinish) {
|
||||
this.onResizeFinish()(
|
||||
this.lastWidth,
|
||||
this.lastLeft,
|
||||
isMaxWidth,
|
||||
this.isCollapsed()
|
||||
);
|
||||
}
|
||||
this.finishSettingWidth();
|
||||
}
|
||||
});
|
||||
document.addEventListener(MouseEvents.Up, this.onMouseUp);
|
||||
}
|
||||
|
||||
onMouseUp() {
|
||||
this.removeInvisibleOverlay();
|
||||
if (!this.pressed) {
|
||||
return;
|
||||
}
|
||||
this.pressed = false;
|
||||
this.resizerColumn.classList.remove(CssClasses.Dragging);
|
||||
this.panel.classList.remove(CssClasses.NoSelection);
|
||||
const isMaxWidth = this.isAtMaxWidth();
|
||||
if (this.onResizeFinish) {
|
||||
this.onResizeFinish(
|
||||
this.lastWidth,
|
||||
this.lastLeft,
|
||||
isMaxWidth,
|
||||
this.isCollapsed()
|
||||
);
|
||||
}
|
||||
this.finishSettingWidth();
|
||||
}
|
||||
|
||||
isAtMaxWidth() {
|
||||
@@ -301,7 +322,7 @@ class PanelResizerCtrl {
|
||||
if (this.overlay) {
|
||||
return;
|
||||
}
|
||||
this.overlay = this.$compile(`<div id='resizer-overlay'></div>`)(this.$scope);
|
||||
this.overlay = this.$compile(`<div id='resizer-overlay'></div>`)(this);
|
||||
angular.element(document.body).prepend(this.overlay);
|
||||
}
|
||||
|
||||
@@ -336,7 +357,6 @@ export class PanelResizer {
|
||||
hoverable: '=',
|
||||
index: '=',
|
||||
minWidth: '=',
|
||||
onResize: '&',
|
||||
onResizeFinish: '&',
|
||||
panelId: '=',
|
||||
property: '='
|
||||
|
||||
@@ -11,15 +11,11 @@ class PasswordWizardCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$element,
|
||||
$scope,
|
||||
$timeout,
|
||||
application,
|
||||
appState
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
super($timeout);
|
||||
this.$element = $element;
|
||||
this.$timeout = $timeout;
|
||||
this.$scope = $scope;
|
||||
this.registerWindowUnloadStopper();
|
||||
}
|
||||
|
||||
@@ -38,14 +34,16 @@ class PasswordWizardCtrl extends PureCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
super.$onDestroy();
|
||||
window.onbeforeunload = null;
|
||||
}
|
||||
|
||||
/** Confirms with user before closing tab */
|
||||
registerWindowUnloadStopper() {
|
||||
window.onbeforeunload = (e) => {
|
||||
return true;
|
||||
};
|
||||
this.$scope.$on("$destroy", () => {
|
||||
window.onbeforeunload = null;
|
||||
});
|
||||
}
|
||||
|
||||
resetContinueState() {
|
||||
@@ -190,8 +188,10 @@ class PasswordWizardCtrl extends PureCtrl {
|
||||
text: "Cannot close window until pending tasks are complete."
|
||||
});
|
||||
} else {
|
||||
this.$element.remove();
|
||||
this.$scope.$destroy();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -204,7 +204,8 @@ export class PasswordWizard {
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
type: '='
|
||||
type: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,10 @@ class PermissionsModalCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$element.remove();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
|
||||
accept() {
|
||||
|
||||
@@ -4,12 +4,10 @@ class PrivilegesAuthModalCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$element,
|
||||
$timeout,
|
||||
application
|
||||
$timeout
|
||||
) {
|
||||
this.$element = $element;
|
||||
this.$timeout = $timeout;
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
@@ -83,7 +81,10 @@ class PrivilegesAuthModalCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$element.remove();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +98,8 @@ export class PrivilegesAuthModal {
|
||||
this.scope = {
|
||||
action: '=',
|
||||
onSuccess: '=',
|
||||
onCancel: '='
|
||||
onCancel: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,15 +5,11 @@ import { PureCtrl } from '@Controllers';
|
||||
class PrivilegesManagementModalCtrl extends PureCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$scope,
|
||||
$timeout,
|
||||
$element,
|
||||
application,
|
||||
appState
|
||||
$element
|
||||
) {
|
||||
super($scope, $timeout, application, appState);
|
||||
super($timeout);
|
||||
this.$element = $element;
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
onAppLaunch() {
|
||||
@@ -78,7 +74,10 @@ class PrivilegesManagementModalCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$element.remove();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,6 +88,8 @@ export class PrivilegesManagementModal {
|
||||
this.controller = PrivilegesManagementModalCtrl;
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.scope = {};
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,24 +8,21 @@ class RevisionPreviewModalCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$element,
|
||||
$scope,
|
||||
$timeout,
|
||||
application
|
||||
$timeout
|
||||
) {
|
||||
this.$element = $element;
|
||||
this.$scope = $scope;
|
||||
this.$timeout = $timeout;
|
||||
this.application = application;
|
||||
$scope.$on('$destroy', () => {
|
||||
if (this.identifier) {
|
||||
this.application.componentManager.deregisterHandler(this.identifier);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.configure();
|
||||
}
|
||||
|
||||
$onDestroy() {
|
||||
if (this.identifier) {
|
||||
this.application.componentManager.deregisterHandler(this.identifier);
|
||||
}
|
||||
}
|
||||
|
||||
async configure() {
|
||||
this.note = await this.application.createTemplateItem({
|
||||
@@ -110,8 +107,10 @@ class RevisionPreviewModalCtrl {
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.$element.remove();
|
||||
this.$scope.$destroy();
|
||||
const elem = this.$element;
|
||||
const scope = elem.scope();
|
||||
scope.$destroy();
|
||||
elem.remove();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,7 +123,8 @@ export class RevisionPreviewModal {
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
uuid: '=',
|
||||
content: '='
|
||||
content: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,19 +3,15 @@ import template from '%/directives/session-history-menu.pug';
|
||||
class SessionHistoryMenuCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$timeout,
|
||||
godService,
|
||||
application,
|
||||
$timeout
|
||||
) {
|
||||
this.$timeout = $timeout;
|
||||
this.godService = godService;
|
||||
this.application = application;
|
||||
this.diskEnabled = this.application.historyManager.isDiskEnabled();
|
||||
this.autoOptimize = this.application.historyManager.isAutoOptimizeEnabled();
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.reloadHistory();
|
||||
this.diskEnabled = this.application.historyManager.isDiskEnabled();
|
||||
this.autoOptimize = this.application.historyManager.isAutoOptimizeEnabled();
|
||||
}
|
||||
|
||||
reloadHistory() {
|
||||
@@ -27,7 +23,7 @@ class SessionHistoryMenuCtrl {
|
||||
}
|
||||
|
||||
openRevision(revision) {
|
||||
this.godService.presentRevisionPreviewModal(
|
||||
this.application.presentRevisionPreviewModal(
|
||||
revision.item.uuid,
|
||||
revision.item.content
|
||||
);
|
||||
@@ -110,7 +106,8 @@ export class SessionHistoryMenu {
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
item: '='
|
||||
item: '=',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,18 +3,14 @@ import template from '%/directives/sync-resolution-menu.pug';
|
||||
class SyncResolutionMenuCtrl {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$timeout,
|
||||
archiveManager,
|
||||
application
|
||||
$timeout
|
||||
) {
|
||||
this.$timeout = $timeout;
|
||||
this.archiveManager = archiveManager;
|
||||
this.application = application;
|
||||
this.status = {};
|
||||
}
|
||||
|
||||
downloadBackup(encrypted) {
|
||||
this.archiveManager.downloadBackup(encrypted);
|
||||
this.application.getArchiveService().downloadBackup(encrypted);
|
||||
this.status.backupFinished = true;
|
||||
}
|
||||
|
||||
@@ -38,7 +34,7 @@ class SyncResolutionMenuCtrl {
|
||||
|
||||
close() {
|
||||
this.$timeout(() => {
|
||||
this.closeFunction()();
|
||||
this.closeFunction();
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -51,7 +47,8 @@ export class SyncResolutionMenu {
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
closeFunction: '&'
|
||||
closeFunction: '&',
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
import { EncryptionIntents, ProtectedActions } from 'snjs';
|
||||
|
||||
export class ArchiveManager {
|
||||
/* @ngInject */
|
||||
constructor(lockManager, application, godService) {
|
||||
this.lockManager = lockManager;
|
||||
constructor(application) {
|
||||
this.application = application;
|
||||
this.godService = godService;
|
||||
}
|
||||
|
||||
/*
|
||||
Public
|
||||
*/
|
||||
/** @public */
|
||||
async downloadBackup(encrypted) {
|
||||
return this.downloadBackupOfItems(this.application.modelManager.allItems, encrypted);
|
||||
@@ -37,7 +31,7 @@ export class ArchiveManager {
|
||||
};
|
||||
|
||||
if (await this.application.privilegesService.actionRequiresPrivilege(ProtectedActions.ManageBackups)) {
|
||||
this.godService.presentPrivilegesModal(ProtectedActions.ManageBackups, () => {
|
||||
this.application.presentPrivilegesModal(ProtectedActions.ManageBackups, () => {
|
||||
run();
|
||||
});
|
||||
} else {
|
||||
|
||||
@@ -9,23 +9,25 @@ const COMPONENT_CONTENT_KEY_PACKAGE_INFO = 'package_info';
|
||||
const COMPONENT_CONTENT_KEY_LOCAL_URL = 'local_url';
|
||||
|
||||
export class DesktopManager extends ApplicationService {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$rootScope,
|
||||
$timeout,
|
||||
application,
|
||||
appState,
|
||||
application
|
||||
) {
|
||||
super(application);
|
||||
this.$rootScope = $rootScope;
|
||||
this.$timeout = $timeout;
|
||||
this.appState = appState;
|
||||
this.application = application;
|
||||
this.componentActivationObservers = [];
|
||||
this.updateObservers = [];
|
||||
this.isDesktop = isDesktopApplication();
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.componentActivationObservers.length = 0;
|
||||
this.updateObservers.length = 0;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
/** @override */
|
||||
onAppEvent(eventName) {
|
||||
super.onAppEvent(eventName);
|
||||
@@ -177,7 +179,7 @@ export class DesktopManager extends ApplicationService {
|
||||
/* Used to resolve 'sn://' */
|
||||
desktop_setExtServerHost(host) {
|
||||
this.extServerHost = host;
|
||||
this.appState.desktopExtensionsReady();
|
||||
this.application.getAppState().desktopExtensionsReady();
|
||||
}
|
||||
|
||||
desktop_setComponentInstallationSyncHandler(handler) {
|
||||
@@ -207,11 +209,11 @@ export class DesktopManager extends ApplicationService {
|
||||
}
|
||||
|
||||
desktop_didBeginBackup() {
|
||||
this.appState.beganBackupDownload();
|
||||
this.application.getAppState().beganBackupDownload();
|
||||
}
|
||||
|
||||
desktop_didFinishBackup(success) {
|
||||
this.appState.endedBackupDownload({
|
||||
this.application.getAppState().endedBackupDownload({
|
||||
success: success
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,114 +0,0 @@
|
||||
import angular from 'angular';
|
||||
|
||||
export class GodService {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$rootScope,
|
||||
$compile,
|
||||
application
|
||||
) {
|
||||
this.$rootScope = $rootScope;
|
||||
this.$compile = $compile;
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
async checkForSecurityUpdate() {
|
||||
return this.application.protocolUpgradeAvailable();
|
||||
}
|
||||
|
||||
presentPasswordWizard(type) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.type = type;
|
||||
const el = this.$compile("<password-wizard type='type'></password-wizard>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
promptForChallenge(challenge, orchestrator) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.challenge = challenge;
|
||||
scope.orchestrator = orchestrator;
|
||||
const el = this.$compile(
|
||||
"<challenge-modal " +
|
||||
"class='sk-modal' challenge='challenge' orchestrator='orchestrator'>" +
|
||||
"</challenge-modal>"
|
||||
)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
async performProtocolUpgrade() {
|
||||
const errors = await this.application.upgradeProtocolVersion();
|
||||
if (errors.length === 0) {
|
||||
this.application.alertService.alert({
|
||||
text: "Success! Your encryption version has been upgraded." +
|
||||
" You'll be asked to enter your credentials again on other devices you're signed into."
|
||||
});
|
||||
} else {
|
||||
this.application.alertService.alert({
|
||||
text: "Unable to upgrade encryption version. Please try again."
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async presentPrivilegesModal(action, onSuccess, onCancel) {
|
||||
if (this.authenticationInProgress()) {
|
||||
onCancel && onCancel();
|
||||
return;
|
||||
}
|
||||
|
||||
const customSuccess = async () => {
|
||||
onSuccess && await onSuccess();
|
||||
this.currentAuthenticationElement = null;
|
||||
};
|
||||
const customCancel = async () => {
|
||||
onCancel && await onCancel();
|
||||
this.currentAuthenticationElement = null;
|
||||
};
|
||||
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.action = action;
|
||||
scope.onSuccess = customSuccess;
|
||||
scope.onCancel = customCancel;
|
||||
const el = this.$compile(`
|
||||
<privileges-auth-modal action='action' on-success='onSuccess'
|
||||
on-cancel='onCancel' class='sk-modal'></privileges-auth-modal>
|
||||
`)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
|
||||
this.currentAuthenticationElement = el;
|
||||
}
|
||||
|
||||
presentPrivilegesManagementModal() {
|
||||
var scope = this.$rootScope.$new(true);
|
||||
var el = this.$compile("<privileges-management-modal class='sk-modal'></privileges-management-modal>")(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
authenticationInProgress() {
|
||||
return this.currentAuthenticationElement != null;
|
||||
}
|
||||
|
||||
presentPasswordModal(callback) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.type = "password";
|
||||
scope.title = "Decryption Assistance";
|
||||
scope.message = `Unable to decrypt this item with your current keys.
|
||||
Please enter your account password at the time of this revision.`;
|
||||
scope.callback = callback;
|
||||
const el = this.$compile(
|
||||
`<input-modal type='type' message='message'
|
||||
title='title' callback='callback'></input-modal>`
|
||||
)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
|
||||
presentRevisionPreviewModal(uuid, content) {
|
||||
const scope = this.$rootScope.$new(true);
|
||||
scope.uuid = uuid;
|
||||
scope.content = content;
|
||||
const el = this.$compile(
|
||||
`<revision-preview-modal uuid='uuid' content='content'
|
||||
class='sk-modal'></revision-preview-modal>`
|
||||
)(scope);
|
||||
angular.element(document.body).append(el);
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
export { AlertService } from './alertService';
|
||||
export { ArchiveManager } from './archiveManager';
|
||||
export { DesktopManager } from './desktopManager';
|
||||
export { GodService } from './godService';
|
||||
export { KeyboardManager } from './keyboardManager';
|
||||
export { LockManager } from './lockManager';
|
||||
export { NativeExtManager } from './nativeExtManager';
|
||||
export { PreferencesManager } from './preferencesManager';
|
||||
export { StatusManager } from './statusManager';
|
||||
export { ThemeManager } from './themeManager';
|
||||
export { AppState } from './state';
|
||||
|
||||
@@ -22,8 +22,19 @@ const KeyboardKeyEvents = {
|
||||
export class KeyboardManager {
|
||||
constructor() {
|
||||
this.observers = [];
|
||||
window.addEventListener('keydown', this.handleKeyDown.bind(this));
|
||||
window.addEventListener('keyup', this.handleKeyUp.bind(this));
|
||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
||||
this.handleKeyUp = this.handleKeyUp.bind(this);
|
||||
window.addEventListener('keydown', this.handleKeyDown);
|
||||
window.addEventListener('keyup', this.handleKeyUp);
|
||||
}
|
||||
|
||||
/** @access public */
|
||||
deinit() {
|
||||
this.observers.length = 0;
|
||||
window.removeEventListener('keydown', this.handleKeyDown);
|
||||
window.removeEventListener('keyup', this.handleKeyUp);
|
||||
this.handleKeyDown = null;
|
||||
this.handleKeyUp = null;
|
||||
}
|
||||
|
||||
modifiersForEvent(event) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import { AppStateEvents } from '../state';
|
||||
import { AppStateEvents } from '@/services/state';
|
||||
|
||||
const MILLISECONDS_PER_SECOND = 1000;
|
||||
const FOCUS_POLL_INTERVAL = 1 * MILLISECONDS_PER_SECOND;
|
||||
@@ -12,16 +12,15 @@ const LOCK_INTERVAL_ONE_HOUR= 3600 * MILLISECONDS_PER_SECOND;
|
||||
const STORAGE_KEY_AUTOLOCK_INTERVAL = "AutoLockIntervalKey";
|
||||
|
||||
export class LockManager {
|
||||
/* @ngInject */
|
||||
constructor($rootScope, application, appState) {
|
||||
this.$rootScope = $rootScope;
|
||||
constructor(application) {
|
||||
this.application = application;
|
||||
this.appState = appState;
|
||||
this.observeVisibility();
|
||||
setImmediate(() => {
|
||||
this.observeVisibility();
|
||||
});
|
||||
}
|
||||
|
||||
observeVisibility() {
|
||||
this.appState.addObserver((eventName, data) => {
|
||||
this.unsubState = this.application.getAppState().addObserver((eventName) => {
|
||||
if(eventName === AppStateEvents.WindowDidBlur) {
|
||||
this.documentVisibilityChanged(false);
|
||||
} else if(eventName === AppStateEvents.WindowDidFocus) {
|
||||
@@ -33,6 +32,13 @@ export class LockManager {
|
||||
}
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.unsubState();
|
||||
if (this.pollFocusInterval) {
|
||||
clearInterval(this.pollFocusInterval);
|
||||
}
|
||||
}
|
||||
|
||||
async setAutoLockInterval(interval) {
|
||||
return this.application.setValue(STORAGE_KEY_AUTOLOCK_INTERVAL, interval);
|
||||
}
|
||||
@@ -53,7 +59,7 @@ export class LockManager {
|
||||
* not triggered on a typical window blur event but rather on tab changes.
|
||||
*/
|
||||
beginWebFocusPolling() {
|
||||
this.pollFocusTimeout = setInterval(() => {
|
||||
this.pollFocusInterval = setInterval(() => {
|
||||
const hasFocus = document.hasFocus();
|
||||
if(hasFocus && this.lastFocusState === 'hidden') {
|
||||
this.documentVisibilityChanged(true);
|
||||
|
||||
@@ -13,7 +13,6 @@ export class NativeExtManager extends ApplicationService {
|
||||
/* @ngInject */
|
||||
constructor(application) {
|
||||
super(application);
|
||||
this.application = application;
|
||||
this.extManagerId = 'org.standardnotes.extensions-manager';
|
||||
this.batchManagerId = 'org.standardnotes.batch-manager';
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import {
|
||||
ApplicationEvents,
|
||||
SNPredicate,
|
||||
ContentTypes,
|
||||
CreateMaxPayloadFromAnyObject,
|
||||
@@ -24,15 +23,7 @@ export const PrefKeys = {
|
||||
};
|
||||
|
||||
export class PreferencesManager extends ApplicationService {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
appState,
|
||||
application
|
||||
) {
|
||||
super(application);
|
||||
this.appState = appState;
|
||||
}
|
||||
|
||||
|
||||
/** @override */
|
||||
onAppLaunch() {
|
||||
super.onAppLaunch();
|
||||
@@ -65,7 +56,7 @@ export class PreferencesManager extends ApplicationService {
|
||||
}
|
||||
|
||||
preferencesDidChange() {
|
||||
this.appState.setUserPreferences(this.userPreferences);
|
||||
this.application.getAppState().setUserPreferences(this.userPreferences);
|
||||
}
|
||||
|
||||
syncUserPreferences() {
|
||||
|
||||
@@ -23,21 +23,33 @@ export const EventSources = {
|
||||
export class AppState {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$timeout,
|
||||
$rootScope,
|
||||
application,
|
||||
godService
|
||||
$timeout,
|
||||
application
|
||||
) {
|
||||
this.$timeout = $timeout;
|
||||
this.$rootScope = $rootScope;
|
||||
this.application = application;
|
||||
this.godService = godService;
|
||||
this.observers = [];
|
||||
this.locked = true;
|
||||
this.registerVisibilityObservers();
|
||||
this.addAppEventObserver();
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.unsubApp();
|
||||
this.unsubApp = null;
|
||||
this.observers.length = 0;
|
||||
if(this.rootScopeCleanup1) {
|
||||
this.rootScopeCleanup1();
|
||||
this.rootScopeCleanup2();
|
||||
this.rootScopeCleanup1 = null;
|
||||
this.rootScopeCleanup2 = null;
|
||||
}
|
||||
document.removeEventListener('visibilitychange', this.onVisibilityChange);
|
||||
this.onVisibilityChange = null;
|
||||
}
|
||||
|
||||
addAppEventObserver() {
|
||||
this.unsubApp = this.application.addEventObserver(async (eventName) => {
|
||||
if (eventName === ApplicationEvents.Started) {
|
||||
@@ -54,23 +66,26 @@ export class AppState {
|
||||
|
||||
registerVisibilityObservers() {
|
||||
if (isDesktopApplication()) {
|
||||
this.$rootScope.$on('window-lost-focus', () => {
|
||||
this.rootScopeCleanup1 = this.$rootScope.$on('window-lost-focus', () => {
|
||||
this.notifyEvent(AppStateEvents.WindowDidBlur);
|
||||
});
|
||||
this.$rootScope.$on('window-gained-focus', () => {
|
||||
this.rootScopeCleanup2 = this.$rootScope.$on('window-gained-focus', () => {
|
||||
this.notifyEvent(AppStateEvents.WindowDidFocus);
|
||||
});
|
||||
} else {
|
||||
/* Tab visibility listener, web only */
|
||||
document.addEventListener('visibilitychange', (e) => {
|
||||
const visible = document.visibilityState === "visible";
|
||||
const event = visible
|
||||
? AppStateEvents.WindowDidFocus
|
||||
: AppStateEvents.WindowDidBlur;
|
||||
this.notifyEvent(event);
|
||||
});
|
||||
this.onVisibilityChange = this.onVisibilityChange.bind(this);
|
||||
document.addEventListener('visibilitychange', this.onVisibilityChange);
|
||||
}
|
||||
}
|
||||
|
||||
onVisibilityChange() {
|
||||
const visible = document.visibilityState === "visible";
|
||||
const event = visible
|
||||
? AppStateEvents.WindowDidFocus
|
||||
: AppStateEvents.WindowDidBlur;
|
||||
this.notifyEvent(event);
|
||||
}
|
||||
|
||||
/** @returns A function that unregisters this observer */
|
||||
addObserver(callback) {
|
||||
@@ -120,10 +135,10 @@ export class AppState {
|
||||
);
|
||||
};
|
||||
if (note && note.content.protected &&
|
||||
await this.application.privilegesService.actionRequiresPrivilege(
|
||||
await this.application.application.privilegesService.actionRequiresPrivilege(
|
||||
ProtectedActions.ViewProtectedNotes
|
||||
)) {
|
||||
this.godService.presentPrivilegesModal(
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedActions.ViewProtectedNotes,
|
||||
run
|
||||
);
|
||||
@@ -5,33 +5,35 @@ import {
|
||||
EncryptionIntents,
|
||||
ApplicationService,
|
||||
} from 'snjs';
|
||||
import { AppStateEvents } from '@/state';
|
||||
import { AppStateEvents } from '@/services/state';
|
||||
|
||||
const CACHED_THEMES_KEY = 'cachedThemes';
|
||||
|
||||
export class ThemeManager extends ApplicationService {
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
application,
|
||||
appState,
|
||||
desktopManager,
|
||||
) {
|
||||
constructor(application) {
|
||||
super(application);
|
||||
this.appState = appState;
|
||||
this.desktopManager = desktopManager;
|
||||
this.activeThemes = [];
|
||||
this.unsubState = appState.addObserver((eventName, data) => {
|
||||
if (eventName === AppStateEvents.DesktopExtsReady) {
|
||||
this.activateCachedThemes();
|
||||
}
|
||||
setImmediate(() => {
|
||||
this.unsubState = this.application.getAppState().addObserver((eventName, data) => {
|
||||
if (eventName === AppStateEvents.DesktopExtsReady) {
|
||||
this.activateCachedThemes();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.unsubState();
|
||||
this.unsubState = null;
|
||||
this.activeThemes.length = 0;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
/** @override */
|
||||
onAppStart() {
|
||||
super.onAppStart();
|
||||
this.registerObservers();
|
||||
if (!this.desktopManager.isDesktop) {
|
||||
if (!this.application.getDesktopService().isDesktop) {
|
||||
this.activateCachedThemes();
|
||||
}
|
||||
}
|
||||
@@ -52,7 +54,7 @@ export class ThemeManager extends ApplicationService {
|
||||
}
|
||||
|
||||
registerObservers() {
|
||||
this.desktopManager.registerUpdateObserver((component) => {
|
||||
this.application.getDesktopService().registerUpdateObserver((component) => {
|
||||
if (component.active && component.isTheme()) {
|
||||
this.deactivateTheme(component);
|
||||
setTimeout(() => {
|
||||
|
||||
@@ -36,7 +36,7 @@ export const STRING_E2E_ENABLED = "End-to-end encryption is enabled. Your data i
|
||||
export const STRING_LOCAL_ENC_ENABLED = "Encryption is enabled. Your data is encrypted using your passcode before it is saved to your device storage.";
|
||||
export const STRING_ENC_NOT_ENABLED = "Encryption is not enabled. Sign in, register, or add a passcode lock to enable encryption.";
|
||||
export const STRING_IMPORT_SUCCESS = "Your data has been successfully imported.";
|
||||
export const STRING_REMOVE_PASSCODE_CONFIRMATION = "Are you sure you want to remove your local passcode?";
|
||||
export const STRING_REMOVE_PASSCODE_CONFIRMATION = "Are you sure you want to remove your application passcode?";
|
||||
export const STRING_REMOVE_PASSCODE_OFFLINE_ADDENDUM = " This will remove encryption from your local data.";
|
||||
export const STRING_NON_MATCHING_PASSCODES = "The two passcodes you entered do not match. Please try again.";
|
||||
export const STRING_NON_MATCHING_PASSWORDS = "The two passwords you entered do not match. Please try again.";
|
||||
|
||||
15
app/assets/templates/application-view.pug
Normal file
15
app/assets/templates/application-view.pug
Normal file
@@ -0,0 +1,15 @@
|
||||
.main-ui-view(
|
||||
ng-class='self.platformString'
|
||||
)
|
||||
#app.app(
|
||||
ng-class='self.state.appClass',
|
||||
ng-if='!self.state.needsUnlock && self.state.ready'
|
||||
)
|
||||
tags-panel(application='self.application')
|
||||
notes-panel(application='self.application')
|
||||
editor-panel(application='self.application')
|
||||
|
||||
footer(
|
||||
ng-if='!self.state.needsUnlock && self.state.ready'
|
||||
application='self.application'
|
||||
)
|
||||
@@ -11,5 +11,6 @@
|
||||
| {{ctrl.component.name}}
|
||||
a.sk-a.info.close-button(ng-click="ctrl.dismiss()") Close
|
||||
component-view.component-view(
|
||||
component="ctrl.component"
|
||||
component="ctrl.component",
|
||||
application='self.application'
|
||||
)
|
||||
|
||||
@@ -46,6 +46,6 @@
|
||||
| an unlocked application, but do not affect data encryption state.
|
||||
p.sk-p
|
||||
| Privileges sync across your other devices; however, note that if you
|
||||
| require a "Local Passcode" privilege, and another device does not have
|
||||
| a local passcode set up, the local passcode requirement will be ignored
|
||||
| require an "Application Passcode" privilege, and another device does not have
|
||||
| an application passcode set up, the application passcode requirement will be ignored
|
||||
| on that device.
|
||||
|
||||
@@ -23,5 +23,6 @@
|
||||
) {{ctrl.content.text}}
|
||||
component-view.component-view(
|
||||
component="ctrl.editor"
|
||||
ng-if="ctrl.editor"
|
||||
ng-if="ctrl.editor",
|
||||
application='self.application'
|
||||
)
|
||||
|
||||
@@ -165,7 +165,8 @@
|
||||
callback='self.editorMenuOnSelect',
|
||||
current-item='self.state.note',
|
||||
ng-if='self.state.showEditorMenu',
|
||||
selected-editor='self.state.selectedEditor'
|
||||
selected-editor='self.state.selectedEditor',
|
||||
application='self.application'
|
||||
)
|
||||
.sk-app-bar-item(
|
||||
click-outside=`self.setMenuState('showExtensions', false)`,
|
||||
@@ -176,7 +177,8 @@
|
||||
.sk-label Actions
|
||||
actions-menu(
|
||||
item='self.state.note',
|
||||
ng-if='self.state.showExtensions'
|
||||
ng-if='self.state.showExtensions',
|
||||
application='self.application'
|
||||
)
|
||||
.sk-app-bar-item(
|
||||
click-outside=`self.setMenuState('showSessionHistory', false)`,
|
||||
@@ -186,7 +188,8 @@
|
||||
.sk-label Session History
|
||||
session-history-menu(
|
||||
item='self.state.note',
|
||||
ng-if='self.state.showSessionHistory'
|
||||
ng-if='self.state.showSessionHistory',
|
||||
application='self.application'
|
||||
)
|
||||
#editor-content.editor-content(
|
||||
ng-if='self.state.noteReady && !self.state.note.errorDecrypting'
|
||||
@@ -196,14 +199,15 @@
|
||||
hoverable='true',
|
||||
min-width='300',
|
||||
ng-if='self.state.marginResizersEnabled',
|
||||
on-resize-finish='self.onPanelResizeFinish',
|
||||
on-resize-finish='self.onPanelResizeFinish()',
|
||||
panel-id="'editor-content'",
|
||||
property="'left'"
|
||||
)
|
||||
component-view.component-view(
|
||||
component='self.state.selectedEditor',
|
||||
ng-if='self.state.selectedEditor',
|
||||
on-load='self.onEditorLoad'
|
||||
on-load='self.onEditorLoad',
|
||||
application='self.application'
|
||||
)
|
||||
textarea#note-text-editor.editable(
|
||||
dir='auto',
|
||||
@@ -222,7 +226,7 @@
|
||||
control='self.rightPanelPuppet',
|
||||
hoverable='true', min-width='300',
|
||||
ng-if='self.state.marginResizersEnabled',
|
||||
on-resize-finish='self.onPanelResizeFinish',
|
||||
on-resize-finish='self.onPanelResizeFinish()',
|
||||
panel-id="'editor-content'",
|
||||
property="'right'"
|
||||
)
|
||||
@@ -249,5 +253,6 @@
|
||||
manual-dealloc='true',
|
||||
ng-if='component.active',
|
||||
ng-repeat='component in self.state.componentStack',
|
||||
ng-show='!component.hidden'
|
||||
ng-show='!component.hidden',
|
||||
application='self.application'
|
||||
)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
#footer-bar.sk-app-bar.no-edges.no-bottom-edge
|
||||
.left
|
||||
.sk-app-bar-item(
|
||||
click-outside='ctrl.clickOutsideAccountMenu()',
|
||||
click-outside='ctrl.clickOutsideAccountMenu()',
|
||||
is-open='ctrl.showAccountMenu',
|
||||
ng-click='ctrl.accountMenuPressed()'
|
||||
)
|
||||
@@ -13,9 +13,10 @@
|
||||
.sk-app-bar-item-column
|
||||
.sk-label.title(ng-class='{red: ctrl.error}') Account
|
||||
account-menu(
|
||||
close-function='ctrl.closeAccountMenu',
|
||||
close-function='ctrl.closeAccountMenu()',
|
||||
ng-click='$event.stopPropagation()',
|
||||
ng-if='ctrl.showAccountMenu',
|
||||
ng-if='ctrl.showAccountMenu',
|
||||
application='ctrl.application'
|
||||
)
|
||||
.sk-app-bar-item
|
||||
a.no-decoration.sk-label.title(
|
||||
@@ -31,21 +32,22 @@
|
||||
component-modal(
|
||||
component='room',
|
||||
ng-if='room.showRoom',
|
||||
on-dismiss='ctrl.onRoomDismiss'
|
||||
on-dismiss='ctrl.onRoomDismiss()',
|
||||
application='self.application'
|
||||
)
|
||||
.center
|
||||
.sk-app-bar-item(ng-show='ctrl.arbitraryStatusMessage')
|
||||
.sk-app-bar-item(ng-if='ctrl.arbitraryStatusMessage')
|
||||
.sk-app-bar-item-column
|
||||
span.neutral.sk-label {{ctrl.arbitraryStatusMessage}}
|
||||
.right
|
||||
.sk-app-bar-item(
|
||||
ng-click='ctrl.openSecurityUpdate()',
|
||||
ng-show='ctrl.state.dataUpgradeAvailable'
|
||||
ng-if='ctrl.state.dataUpgradeAvailable'
|
||||
)
|
||||
span.success.sk-label Encryption upgrade available.
|
||||
.sk-app-bar-item(
|
||||
ng-click='ctrl.clickedNewUpdateAnnouncement()',
|
||||
ng-show='ctrl.newUpdateAvailable == true'
|
||||
ng-if='ctrl.newUpdateAvailable == true'
|
||||
)
|
||||
span.info.sk-label New update available.
|
||||
.sk-app-bar-item.no-pointer(
|
||||
@@ -59,9 +61,10 @@
|
||||
)
|
||||
.sk-label.warning(ng-if='ctrl.state.outOfSync') Potentially Out of Sync
|
||||
sync-resolution-menu(
|
||||
close-function='ctrl.toggleSyncResolutionMenu',
|
||||
close-function='ctrl.toggleSyncResolutionMenu()',
|
||||
ng-click='$event.stopPropagation();',
|
||||
ng-if='ctrl.showSyncResolution'
|
||||
ng-if='ctrl.showSyncResolution',
|
||||
application='self.application'
|
||||
)
|
||||
.sk-app-bar-item(ng-if='ctrl.lastSyncDate && ctrl.isRefreshing')
|
||||
.sk-spinner.small
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
) Forgot?
|
||||
div(ng-if='ctrl.formData.showRecovery')
|
||||
.sk-p
|
||||
| If you forgot your local passcode, your only option is to clear
|
||||
| If you forgot your application passcode, your only option is to clear
|
||||
| your local data from this device and sign back in to your account.
|
||||
.sk-panel-row
|
||||
a.sk-a.danger.center-text(
|
||||
|
||||
@@ -145,6 +145,6 @@
|
||||
control="self.panelPuppet"
|
||||
default-width="300"
|
||||
hoverable="true"
|
||||
on-resize-finish="self.onPanelResize"
|
||||
on-resize-finish="self.onPanelResize()"
|
||||
panel-id="'notes-column'"
|
||||
)
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
.main-ui-view(
|
||||
ng-class='self.platformString'
|
||||
)
|
||||
#app.app(
|
||||
ng-class='self.state.appClass',
|
||||
ng-if='!self.state.needsUnlock && self.state.ready'
|
||||
)
|
||||
tags-panel
|
||||
notes-panel
|
||||
editor-panel
|
||||
|
||||
footer(
|
||||
ng-if='!self.state.needsUnlock && self.state.ready'
|
||||
)
|
||||
application-view(
|
||||
ng-repeat='application in self.applications',
|
||||
application='application'
|
||||
)
|
||||
@@ -1,6 +1,9 @@
|
||||
#tags-column.sn-component.section.tags(aria-label='Tags')
|
||||
.component-view-container(ng-if='self.component.active')
|
||||
component-view.component-view(component='self.component')
|
||||
component-view.component-view(
|
||||
component='self.component',
|
||||
application='self.application'
|
||||
)
|
||||
#tags-content.content(ng-if='!(self.component && self.component.active)')
|
||||
.tags-title-section.section-title-bar
|
||||
.section-title-bar-header
|
||||
@@ -60,6 +63,6 @@
|
||||
control='self.panelPuppet',
|
||||
default-width='150',
|
||||
hoverable='true',
|
||||
on-resize-finish='self.onPanelResize',
|
||||
on-resize-finish='self.onPanelResize()',
|
||||
panel-id="'tags-column'"
|
||||
)
|
||||
|
||||
6944
dist/javascripts/app.js
vendored
6944
dist/javascripts/app.js
vendored
File diff suppressed because one or more lines are too long
2
dist/javascripts/app.js.map
vendored
2
dist/javascripts/app.js.map
vendored
File diff suppressed because one or more lines are too long
85
public/dist/libsodium.bundle.js
vendored
85
public/dist/libsodium.bundle.js
vendored
@@ -1,2 +1,85 @@
|
||||
(window.webpackJsonpSNCrypto=window.webpackJsonpSNCrypto||[]).push([[0],{125:function(t,c){},126:function(t,c){},168:function(t,c,n){"use strict";n.r(c);var o=n(21);n.d(c,"ready",(function(){return o.ready})),n.d(c,"crypto_pwhash",(function(){return o.crypto_pwhash})),n.d(c,"crypto_pwhash_ALG_DEFAULT",(function(){return o.crypto_pwhash_ALG_DEFAULT})),n.d(c,"crypto_aead_xchacha20poly1305_ietf_encrypt",(function(){return o.crypto_aead_xchacha20poly1305_ietf_encrypt})),n.d(c,"crypto_aead_xchacha20poly1305_ietf_decrypt",(function(){return o.crypto_aead_xchacha20poly1305_ietf_decrypt}))},51:function(t,c){},91:function(t,c){},93:function(t,c){}}]);
|
||||
(window["webpackJsonpSNCrypto"] = window["webpackJsonpSNCrypto"] || []).push([["libsodium"],{
|
||||
|
||||
/***/ "./lib/libsodium.js":
|
||||
/*!**************************!*\
|
||||
!*** ./lib/libsodium.js ***!
|
||||
\**************************/
|
||||
/*! exports provided: ready, crypto_pwhash, crypto_pwhash_ALG_DEFAULT, crypto_aead_xchacha20poly1305_ietf_encrypt, crypto_aead_xchacha20poly1305_ietf_decrypt */
|
||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
||||
|
||||
"use strict";
|
||||
__webpack_require__.r(__webpack_exports__);
|
||||
/* harmony import */ var libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! libsodium-wrappers */ "./node_modules/libsodium-wrappers/dist/modules/libsodium-wrappers.js");
|
||||
/* harmony import */ var libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0__);
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "ready", function() { return libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0__["ready"]; });
|
||||
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "crypto_pwhash", function() { return libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0__["crypto_pwhash"]; });
|
||||
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "crypto_pwhash_ALG_DEFAULT", function() { return libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0__["crypto_pwhash_ALG_DEFAULT"]; });
|
||||
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "crypto_aead_xchacha20poly1305_ietf_encrypt", function() { return libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0__["crypto_aead_xchacha20poly1305_ietf_encrypt"]; });
|
||||
|
||||
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "crypto_aead_xchacha20poly1305_ietf_decrypt", function() { return libsodium_wrappers__WEBPACK_IMPORTED_MODULE_0__["crypto_aead_xchacha20poly1305_ietf_decrypt"]; });
|
||||
|
||||
/* eslint-disable camelcase */
|
||||
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 0:
|
||||
/*!********************!*\
|
||||
!*** fs (ignored) ***!
|
||||
\********************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
/* (ignored) */
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 1:
|
||||
/*!**********************!*\
|
||||
!*** util (ignored) ***!
|
||||
\**********************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
/* (ignored) */
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 2:
|
||||
/*!**********************!*\
|
||||
!*** util (ignored) ***!
|
||||
\**********************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
/* (ignored) */
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 3:
|
||||
/*!************************!*\
|
||||
!*** buffer (ignored) ***!
|
||||
\************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
/* (ignored) */
|
||||
|
||||
/***/ }),
|
||||
|
||||
/***/ 4:
|
||||
/*!************************!*\
|
||||
!*** crypto (ignored) ***!
|
||||
\************************/
|
||||
/*! no static exports found */
|
||||
/***/ (function(module, exports) {
|
||||
|
||||
/* (ignored) */
|
||||
|
||||
/***/ })
|
||||
|
||||
}]);
|
||||
//# sourceMappingURL=libsodium.bundle.js.map
|
||||
30596
public/dist/vendors~libsodium.bundle.js
vendored
30596
public/dist/vendors~libsodium.bundle.js
vendored
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user