fix: typescript errors

This commit is contained in:
Baptiste Grob
2020-08-12 14:43:56 +02:00
parent 0c1f3d43d1
commit 2fb6adb6ea
31 changed files with 233 additions and 1463 deletions

View File

@@ -1,622 +0,0 @@
import { isDesktopApplication, isNullOrUndefined } from '@/utils';
import { PrivilegesManager } from '@/services/privilegesManager';
import template from '%/directives/account-menu.pug';
import { protocolManager } from 'snjs';
import { PureCtrl } from '@Controllers';
import {
STRING_ACCOUNT_MENU_UNCHECK_MERGE,
STRING_SIGN_OUT_CONFIRMATION,
STRING_ERROR_DECRYPTING_IMPORT,
STRING_E2E_ENABLED,
STRING_LOCAL_ENC_ENABLED,
STRING_ENC_NOT_ENABLED,
STRING_IMPORT_SUCCESS,
STRING_REMOVE_PASSCODE_CONFIRMATION,
STRING_REMOVE_PASSCODE_OFFLINE_ADDENDUM,
STRING_NON_MATCHING_PASSCODES,
STRING_NON_MATCHING_PASSWORDS,
STRING_INVALID_IMPORT_FILE,
STRING_GENERATING_LOGIN_KEYS,
STRING_GENERATING_REGISTER_KEYS,
StringImportError
} from '@/strings';
const ELEMENT_ID_IMPORT_PASSWORD_INPUT = 'import-password-request';
const ELEMENT_NAME_AUTH_EMAIL = 'email';
const ELEMENT_NAME_AUTH_PASSWORD = 'password';
const ELEMENT_NAME_AUTH_PASSWORD_CONF = 'password_conf';
class AccountMenuCtrl extends PureCtrl {
/* @ngInject */
constructor(
$scope,
$rootScope,
$timeout,
alertManager,
archiveManager,
appVersion,
authManager,
modelManager,
passcodeManager,
privilegesManager,
storageManager,
syncManager,
) {
super($timeout);
this.$scope = $scope;
this.$rootScope = $rootScope;
this.$timeout = $timeout;
this.alertManager = alertManager;
this.archiveManager = archiveManager;
this.authManager = authManager;
this.modelManager = modelManager;
this.passcodeManager = passcodeManager;
this.privilegesManager = privilegesManager;
this.storageManager = storageManager;
this.syncManager = syncManager;
this.state = {
appVersion: 'v' + (window.electronAppVersion || appVersion),
user: this.authManager.user,
canAddPasscode: !this.authManager.isEphemeralSession(),
passcodeAutoLockOptions: this.passcodeManager.getAutoLockIntervalOptions(),
formData: {
mergeLocal: true,
ephemeral: false
},
mutable: {
backupEncrypted: this.encryptedBackupsAvailable()
}
};
this.syncStatus = this.syncManager.syncStatus;
this.syncManager.getServerURL().then((url) => {
this.setState({
server: url,
formData: { ...this.state.formData, url: url }
});
});
this.authManager.checkForSecurityUpdate().then((available) => {
this.setState({
securityUpdateAvailable: available
});
});
this.reloadAutoLockInterval();
}
$onInit() {
this.initProps({
closeFunction: this.closeFunction
});
}
close() {
this.$timeout(() => {
this.props.closeFunction()();
});
}
encryptedBackupsAvailable() {
return !isNullOrUndefined(this.authManager.user) || this.passcodeManager.hasPasscode();
}
submitMfaForm() {
const params = {
[this.state.formData.mfa.payload.mfa_key]: this.state.formData.userMfaCode
};
this.login(params);
}
blurAuthFields() {
const names = [
ELEMENT_NAME_AUTH_EMAIL,
ELEMENT_NAME_AUTH_PASSWORD,
ELEMENT_NAME_AUTH_PASSWORD_CONF
];
for(const name of names) {
const element = document.getElementsByName(name)[0];
if(element) {
element.blur();
}
}
}
submitAuthForm() {
if (!this.state.formData.email || !this.state.formData.user_password) {
return;
}
this.blurAuthFields();
if (this.state.formData.showLogin) {
this.login();
} else {
this.register();
}
}
async setFormDataState(formData) {
return this.setState({
formData: {
...this.state.formData,
...formData
}
});
}
async login(extraParams) {
/** Prevent a timed sync from occuring while signing in. */
this.syncManager.lockSyncing();
await this.setFormDataState({
status: STRING_GENERATING_LOGIN_KEYS,
authenticating: true
});
const response = await this.authManager.login(
this.state.formData.url,
this.state.formData.email,
this.state.formData.user_password,
this.state.formData.ephemeral,
this.state.formData.strictSignin,
extraParams
);
const hasError = !response || response.error;
if (!hasError) {
this.setFormDataState({
user_password: null
});
await this.onAuthSuccess();
this.syncManager.unlockSyncing();
this.syncManager.sync({ performIntegrityCheck: true });
return;
}
this.syncManager.unlockSyncing();
await this.setFormDataState({
status: null
});
const error = response
? response.error
: { message: "An unknown error occured." };
if (error.tag === 'mfa-required' || error.tag === 'mfa-invalid') {
await this.setFormDataState({
showLogin: false,
mfa: error
});
} else {
await this.setFormDataState({
showLogin: true,
mfa: null
});
if (error.message) {
this.alertManager.alert({
text: error.message
});
}
}
await this.setFormDataState({
authenticating: false,
});
}
async register() {
const confirmation = this.state.formData.password_conf;
if (confirmation !== this.state.formData.user_password) {
this.alertManager.alert({
text: STRING_NON_MATCHING_PASSWORDS
});
return;
}
await this.setFormDataState({
confirmPassword: false,
status: STRING_GENERATING_REGISTER_KEYS,
authenticating: true
});
const response = await this.authManager.register(
this.state.formData.url,
this.state.formData.email,
this.state.formData.user_password,
this.state.formData.ephemeral
);
if (!response || response.error) {
await this.setFormDataState({
status: null
});
const error = response
? response.error
: { message: "An unknown error occured." };
await this.setFormDataState({
authenticating: false
});
this.alertManager.alert({
text: error.message
});
} else {
await this.onAuthSuccess();
this.syncManager.sync();
}
}
mergeLocalChanged() {
if (!this.state.formData.mergeLocal) {
this.alertManager.confirm({
text: STRING_ACCOUNT_MENU_UNCHECK_MERGE,
destructive: true,
onCancel: () => {
this.setFormDataState({
mergeLocal: true
});
}
});
}
}
async onAuthSuccess() {
if (this.state.formData.mergeLocal) {
this.$rootScope.$broadcast('major-data-change');
await this.clearDatabaseAndRewriteAllItems({ alternateUuids: true });
} else {
this.modelManager.removeAllItemsFromMemory();
await this.storageManager.clearAllModels();
}
await this.setFormDataState({
authenticating: false
});
this.syncManager.refreshErroredItems();
this.close();
}
openPasswordWizard(type) {
this.close();
this.authManager.presentPasswordWizard(type);
}
async openPrivilegesModal() {
this.close();
const run = () => {
this.privilegesManager.presentPrivilegesManagementModal();
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePrivileges
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePrivileges,
() => {
run();
}
);
} else {
run();
}
}
/**
* Allows IndexedDB unencrypted logs to be deleted
* `clearAllModels` will remove data from backing store,
* but not from working memory See:
* https://github.com/standardnotes/desktop/issues/131
*/
async clearDatabaseAndRewriteAllItems({ alternateUuids } = {}) {
await this.storageManager.clearAllModels();
await this.syncManager.markAllItemsDirtyAndSaveOffline(alternateUuids);
}
destroyLocalData() {
this.alertManager.confirm({
text: STRING_SIGN_OUT_CONFIRMATION,
destructive: true,
onConfirm: async () => {
await this.authManager.signout(true);
window.location.reload();
}
});
}
async submitImportPassword() {
await this.performImport(
this.state.importData.data,
this.state.importData.password
);
}
async readFile(file) {
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = function (e) {
try {
const data = JSON.parse(e.target.result);
resolve(data);
} catch (e) {
this.alertManager.alert({
text: STRING_INVALID_IMPORT_FILE
});
}
};
reader.readAsText(file);
});
}
/**
* @template
*/
async importFileSelected(files) {
const run = async () => {
const file = files[0];
const data = await this.readFile(file);
if (!data) {
return;
}
if (data.auth_params) {
await this.setState({
importData: {
...this.state.importData,
requestPassword: true,
data: data
}
});
const element = document.getElementById(
ELEMENT_ID_IMPORT_PASSWORD_INPUT
);
if (element) {
element.scrollIntoView(false);
}
} else {
await this.performImport(data, null);
}
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManageBackups
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManageBackups,
run
);
} else {
run();
}
}
async performImport(data, password) {
await this.setState({
importData: {
...this.state.importData,
loading: true
}
});
const errorCount = await this.importJSONData(data, password);
this.setState({
importData: null
});
if (errorCount > 0) {
const message = StringImportError({ errorCount: errorCount });
this.alertManager.alert({
text: message
});
} else {
this.alertManager.alert({
text: STRING_IMPORT_SUCCESS
});
}
}
async importJSONData(data, password) {
let errorCount = 0;
if (data.auth_params) {
const keys = await protocolManager.computeEncryptionKeysForUser(
password,
data.auth_params
);
try {
const throws = false;
await protocolManager.decryptMultipleItems(data.items, keys, throws);
const items = [];
for (const item of data.items) {
item.enc_item_key = null;
item.auth_hash = null;
if (item.errorDecrypting) {
errorCount++;
} else {
items.push(item);
}
}
data.items = items;
} catch (e) {
this.alertManager.alert({
text: STRING_ERROR_DECRYPTING_IMPORT
});
return;
}
}
const items = await this.modelManager.importItems(data.items);
for (const item of items) {
/**
* Don't want to activate any components during import process in
* case of exceptions breaking up the import proccess
*/
if (item.content_type === 'SN|Component') {
item.active = false;
}
}
this.syncManager.sync();
return errorCount;
}
async downloadDataArchive() {
this.archiveManager.downloadBackup(this.state.mutable.backupEncrypted);
this.close();
}
notesAndTagsCount() {
return this.modelManager.allItemsMatchingTypes([
'Note',
'Tag'
]).length;
}
encryptionStatusForNotes() {
const length = this.notesAndTagsCount();
return length + "/" + length + " notes and tags encrypted";
}
encryptionEnabled() {
return this.passcodeManager.hasPasscode() || !this.authManager.offline();
}
encryptionSource() {
if (!this.authManager.offline()) {
return "Account keys";
} else if (this.passcodeManager.hasPasscode()) {
return "Local Passcode";
} else {
return null;
}
}
encryptionStatusString() {
if (!this.authManager.offline()) {
return STRING_E2E_ENABLED;
} else if (this.passcodeManager.hasPasscode()) {
return STRING_LOCAL_ENC_ENABLED;
} else {
return STRING_ENC_NOT_ENABLED;
}
}
async reloadAutoLockInterval() {
const interval = await this.passcodeManager.getAutoLockInterval();
this.setState({
selectedAutoLockInterval: interval
});
}
async selectAutoLockInterval(interval) {
const run = async () => {
await this.passcodeManager.setAutoLockInterval(interval);
this.reloadAutoLockInterval();
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePasscode
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePasscode,
() => {
run();
}
);
} else {
run();
}
}
hidePasswordForm() {
this.setFormDataState({
showLogin: false,
showRegister: false,
user_password: null,
password_conf: null
});
}
hasPasscode() {
return this.passcodeManager.hasPasscode();
}
addPasscodeClicked() {
this.setFormDataState({
showPasscodeForm: true
});
}
submitPasscodeForm() {
const passcode = this.state.formData.passcode;
if (passcode !== this.state.formData.confirmPasscode) {
this.alertManager.alert({
text: STRING_NON_MATCHING_PASSCODES
});
return;
}
const func = this.state.formData.changingPasscode
? this.passcodeManager.changePasscode.bind(this.passcodeManager)
: this.passcodeManager.setPasscode.bind(this.passcodeManager);
func(passcode, async () => {
await this.setFormDataState({
passcode: null,
confirmPasscode: null,
showPasscodeForm: false
});
if (await this.authManager.offline()) {
this.$rootScope.$broadcast('major-data-change');
this.clearDatabaseAndRewriteAllItems();
}
});
}
async changePasscodePressed() {
const run = () => {
this.state.formData.changingPasscode = true;
this.addPasscodeClicked();
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePasscode
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePasscode,
run
);
} else {
run();
}
}
async removePasscodePressed() {
const run = () => {
const signedIn = !this.authManager.offline();
let message = STRING_REMOVE_PASSCODE_CONFIRMATION;
if (!signedIn) {
message += STRING_REMOVE_PASSCODE_OFFLINE_ADDENDUM;
}
this.alertManager.confirm({
text: message,
destructive: true,
onConfirm: () => {
this.passcodeManager.clearPasscode();
if (this.authManager.offline()) {
this.syncManager.markAllItemsDirtyAndSaveOffline();
}
}
});
};
const needsPrivilege = await this.privilegesManager.actionRequiresPrivilege(
PrivilegesManager.ActionManagePasscode
);
if (needsPrivilege) {
this.privilegesManager.presentPrivilegesModal(
PrivilegesManager.ActionManagePasscode,
run
);
} else {
run();
}
}
isDesktopApplication() {
return isDesktopApplication();
}
}
export class AccountMenu {
constructor() {
this.restrict = 'E';
this.template = template;
this.controller = AccountMenuCtrl;
this.controllerAs = 'self';
this.bindToController = true;
this.scope = {
closeFunction: '&'
};
}
}

View File

@@ -137,8 +137,8 @@ class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope {
...action,
running: params?.running,
error: params?.error,
subrows: params?.subrows || act?.subrows,
};
subrows: params?.subrows || act?.subrows,
} as Action;
}
return act;
});
@@ -147,12 +147,12 @@ class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope {
}
private async updateExtension(
extension: SNActionsExtension,
extension: SNActionsExtension,
params?: UpdateExtensionParams
) {
const updatedExtension = await this.application.changeItem(extension.uuid, (mutator) => {
const extensionMutator = mutator as ActionsExtensionMutator;
extensionMutator.hidden = params && params.hidden;
extensionMutator.hidden = Boolean(params?.hidden);
}) as SNActionsExtension;
const extensions = this.state.extensions.map((ext: SNActionsExtension) => {
if (extension.uuid === ext.uuid) {

View File

@@ -1,280 +0,0 @@
import template from '%/directives/component-view.pug';
import { isDesktopApplication } from '../../utils';
/**
* The maximum amount of time we'll wait for a component
* to load before displaying error
*/
const MAX_LOAD_THRESHOLD = 4000;
const VISIBILITY_CHANGE_LISTENER_KEY = 'visibilitychange';
class ComponentViewCtrl {
/* @ngInject */
constructor(
$scope,
$rootScope,
$timeout,
componentManager,
desktopManager,
themeManager
) {
this.$rootScope = $rootScope;
this.$timeout = $timeout;
this.themeManager = themeManager;
this.desktopManager = desktopManager;
this.componentManager = componentManager;
this.componentValid = true;
this.destroyed = false;
$scope.$watch('ctrl.component', (component, prevComponent) => {
this.componentValueDidSet(component, prevComponent);
});
$scope.$on('ext-reload-complete', () => {
this.reloadStatus(false);
});
$scope.$on('$destroy', () => {
this.destroyed = true;
this.destroy();
});
}
$onInit() {
this.registerComponentHandlers();
this.registerPackageUpdateObserver();
};
registerPackageUpdateObserver() {
this.updateObserver = this.desktopManager
.registerUpdateObserver((component) => {
if(component === this.component && component.active) {
this.reloadComponent();
}
});
}
registerComponentHandlers() {
this.themeHandlerIdentifier = 'component-view-' + Math.random();
this.componentManager.registerHandler({
identifier: this.themeHandlerIdentifier,
areas: ['themes'],
activationHandler: (component) => {
this.reloadThemeStatus();
}
});
this.identifier = 'component-view-' + Math.random();
this.componentManager.registerHandler({
identifier: this.identifier,
areas: [this.component.area],
activationHandler: (component) => {
if(component !== this.component) {
return;
}
this.$timeout(() => {
this.handleActivation();
});
},
actionHandler: (component, action, data) => {
if(action === 'set-size') {
this.componentManager.handleSetSizeEvent(component, data);
}
}
});
}
onVisibilityChange() {
if(document.visibilityState === 'hidden') {
return;
}
if(this.issueLoading) {
this.reloadComponent();
}
}
async reloadComponent() {
this.componentValid = false;
await this.componentManager.reloadComponent(this.component);
if (this.destroyed) return;
this.reloadStatus();
}
reloadStatus(doManualReload = true) {
this.reloading = true;
const component = this.component;
const previouslyValid = this.componentValid;
const offlineRestricted = component.offlineOnly && !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) {
component.readonly = this.expired;
}
this.componentValid = !offlineRestricted && !hasUrlError;
if(!this.componentValid) {
this.loading = false;
}
if(offlineRestricted) {
this.error = 'offline-restricted';
} else if(hasUrlError) {
this.error = 'url-missing';
} else {
this.error = null;
}
if(this.componentValid !== previouslyValid) {
if(this.componentValid) {
this.componentManager.reloadComponent(component, true);
}
}
if(this.expired && doManualReload) {
this.$rootScope.$broadcast('reload-ext-dat');
}
this.reloadThemeStatus();
this.$timeout(() => {
this.reloading = false;
}, 500);
}
handleActivation() {
if(!this.component.active) {
return;
}
const iframe = this.componentManager.iframeForComponent(
this.component
);
if(!iframe) {
return;
}
this.loading = true;
if(this.loadTimeout) {
this.$timeout.cancel(this.loadTimeout);
}
this.loadTimeout = this.$timeout(() => {
this.handleIframeLoadTimeout();
}, MAX_LOAD_THRESHOLD);
iframe.onload = (event) => {
this.handleIframeLoad(iframe);
};
}
async handleIframeLoadTimeout() {
if(this.loading) {
this.loading = false;
this.issueLoading = true;
if(!this.didAttemptReload) {
this.didAttemptReload = true;
this.reloadComponent();
} else {
document.addEventListener(
VISIBILITY_CHANGE_LISTENER_KEY,
this.onVisibilityChange.bind(this)
);
}
}
}
async handleIframeLoad(iframe) {
let desktopError = false;
if(isDesktopApplication()) {
try {
/** Accessing iframe.contentWindow.origin only allowed in desktop app. */
if(!iframe.contentWindow.origin || iframe.contentWindow.origin === 'null') {
desktopError = true;
}
} catch (e) {}
}
this.$timeout.cancel(this.loadTimeout);
await this.componentManager.registerComponentWindow(
this.component,
iframe.contentWindow
);
const avoidFlickerTimeout = 7;
this.$timeout(() => {
this.loading = false;
// eslint-disable-next-line no-unneeded-ternary
this.issueLoading = desktopError ? true : false;
this.onLoad && this.onLoad(this.component);
}, avoidFlickerTimeout);
}
componentValueDidSet(component, prevComponent) {
const dontSync = true;
if(prevComponent && component !== prevComponent) {
this.componentManager.deactivateComponent(
prevComponent,
dontSync
);
}
if(component) {
this.componentManager.activateComponent(
component,
dontSync
);
this.reloadStatus();
}
}
reloadThemeStatus() {
if(this.component.acceptsThemes()) {
return;
}
if(this.themeManager.hasActiveTheme()) {
if(!this.dismissedNoThemesMessage) {
this.showNoThemesMessage = true;
}
} else {
this.showNoThemesMessage = false;
}
}
dismissNoThemesMessage() {
this.showNoThemesMessage = false;
this.dismissedNoThemesMessage = true;
}
disableActiveTheme() {
this.themeManager.deactivateAllThemes();
this.dismissNoThemesMessage();
}
getUrl() {
const url = this.componentManager.urlForComponent(this.component);
this.component.runningLocally = (url === this.component.local_url);
return url;
}
destroy() {
this.componentManager.deregisterHandler(this.themeHandlerIdentifier);
this.componentManager.deregisterHandler(this.identifier);
if(this.component && !this.manualDealloc) {
const dontSync = true;
this.componentManager.deactivateComponent(this.component, dontSync);
}
this.desktopManager.deregisterUpdateObserver(this.updateObserver);
document.removeEventListener(
VISIBILITY_CHANGE_LISTENER_KEY,
this.onVisibilityChange.bind(this)
);
}
}
export class ComponentView {
constructor() {
this.restrict = 'E';
this.template = template;
this.scope = {
component: '=',
onLoad: '=?',
manualDealloc: '=?'
};
this.controller = ComponentViewCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
}
}

View File

@@ -1,302 +0,0 @@
import { protocolManager } from 'snjs';
import template from '%/directives/password-wizard.pug';
import { STRING_FAILED_PASSWORD_CHANGE } from '@/strings';
const DEFAULT_CONTINUE_TITLE = "Continue";
const Steps = {
IntroStep: 0,
BackupStep: 1,
SignoutStep: 2,
PasswordStep: 3,
SyncStep: 4,
FinishStep: 5
};
class PasswordWizardCtrl {
/* @ngInject */
constructor(
$element,
$scope,
$timeout,
alertManager,
archiveManager,
authManager,
modelManager,
syncManager,
) {
this.$element = $element;
this.$timeout = $timeout;
this.$scope = $scope;
this.alertManager = alertManager;
this.archiveManager = archiveManager;
this.authManager = authManager;
this.modelManager = modelManager;
this.syncManager = syncManager;
this.registerWindowUnloadStopper();
}
$onInit() {
this.syncStatus = this.syncManager.syncStatus;
this.formData = {};
this.configureDefaults();
}
configureDefaults() {
if (this.type === 'change-pw') {
this.title = "Change Password";
this.changePassword = true;
} else if (this.type === 'upgrade-security') {
this.title = "Security Update";
this.securityUpdate = true;
}
this.continueTitle = DEFAULT_CONTINUE_TITLE;
this.step = Steps.IntroStep;
}
/** Confirms with user before closing tab */
registerWindowUnloadStopper() {
window.onbeforeunload = (e) => {
return true;
};
this.$scope.$on("$destroy", () => {
window.onbeforeunload = null;
});
}
titleForStep(step) {
switch (step) {
case Steps.BackupStep:
return "Download a backup of your data";
case Steps.SignoutStep:
return "Sign out of all your devices";
case Steps.PasswordStep:
return this.changePassword
? "Password information"
: "Enter your current password";
case Steps.SyncStep:
return "Encrypt and sync data with new keys";
case Steps.FinishStep:
return "Sign back in to your devices";
default:
return null;
}
}
async nextStep() {
if (this.lockContinue || this.isContinuing) {
return;
}
this.isContinuing = true;
if (this.step === Steps.FinishStep) {
this.dismiss();
return;
}
const next = () => {
this.step++;
this.initializeStep(this.step);
this.isContinuing = false;
};
const preprocessor = this.preprocessorForStep(this.step);
if (preprocessor) {
await preprocessor().then((success) => {
if(success) {
next();
} else {
this.$timeout(() => {
this.isContinuing = false;
});
}
}).catch(() => {
this.isContinuing = false;
});
} else {
next();
}
}
preprocessorForStep(step) {
if (step === Steps.PasswordStep) {
return async () => {
this.showSpinner = true;
this.continueTitle = "Generating Keys...";
const success = await this.validateCurrentPassword();
this.showSpinner = false;
this.continueTitle = DEFAULT_CONTINUE_TITLE;
return success;
};
}
}
async initializeStep(step) {
if (step === Steps.SyncStep) {
await this.initializeSyncingStep();
} else if (step === Steps.FinishStep) {
this.continueTitle = "Finish";
}
}
async initializeSyncingStep() {
this.lockContinue = true;
this.formData.status = "Processing encryption keys...";
this.formData.processing = true;
const passwordSuccess = await this.processPasswordChange();
this.formData.statusError = !passwordSuccess;
this.formData.processing = passwordSuccess;
if(!passwordSuccess) {
this.formData.status = "Unable to process your password. Please try again.";
return;
}
this.formData.status = "Encrypting and syncing data with new keys...";
const syncSuccess = await this.resyncData();
this.formData.statusError = !syncSuccess;
this.formData.processing = !syncSuccess;
if (syncSuccess) {
this.lockContinue = false;
if (this.changePassword) {
this.formData.status = "Successfully changed password and synced all items.";
} else if (this.securityUpdate) {
this.formData.status = "Successfully performed security update and synced all items.";
}
} else {
this.formData.status = STRING_FAILED_PASSWORD_CHANGE;
}
}
async validateCurrentPassword() {
const currentPassword = this.formData.currentPassword;
const newPass = this.securityUpdate ? currentPassword : this.formData.newPassword;
if (!currentPassword || currentPassword.length === 0) {
this.alertManager.alert({
text: "Please enter your current password."
});
return false;
}
if (this.changePassword) {
if (!newPass || newPass.length === 0) {
this.alertManager.alert({
text: "Please enter a new password."
});
return false;
}
if (newPass !== this.formData.newPasswordConfirmation) {
this.alertManager.alert({
text: "Your new password does not match its confirmation."
});
this.formData.status = null;
return false;
}
}
if (!this.authManager.user.email) {
this.alertManager.alert({
text: "We don't have your email stored. Please log out then log back in to fix this issue."
});
this.formData.status = null;
return false;
}
const minLength = this.authManager.getMinPasswordLength();
if (!this.securityUpdate && newPass.length < minLength) {
const message = `Your password must be at least ${minLength} characters in length. For your security, please choose a longer password or, ideally, a passphrase, and try again.`;
this.alertManager.alert({
text: message
});
return false;
}
/** Validate current password */
const authParams = await this.authManager.getAuthParams();
const password = this.formData.currentPassword;
const keys = await protocolManager.computeEncryptionKeysForUser(
password,
authParams
);
const success = keys.mk === (await this.authManager.keys()).mk;
if (success) {
this.currentServerPw = keys.pw;
} else {
this.alertManager.alert({
text: "The current password you entered is not correct. Please try again."
});
}
return success;
}
async resyncData() {
await this.modelManager.setAllItemsDirty();
const response = await this.syncManager.sync();
if (!response || response.error) {
this.alertManager.alert({
text: STRING_FAILED_PASSWORD_CHANGE
});
return false;
} else {
return true;
}
}
async processPasswordChange() {
const newUserPassword = this.securityUpdate
? this.formData.currentPassword
: this.formData.newPassword;
const currentServerPw = this.currentServerPw;
const results = await protocolManager.generateInitialKeysAndAuthParamsForUser(
this.authManager.user.email,
newUserPassword
);
const newKeys = results.keys;
const newAuthParams = results.authParams;
/**
* Perform a sync beforehand to pull in any last minutes changes before we change
* the encryption key (and thus cant decrypt new changes).
*/
await this.syncManager.sync();
const response = await this.authManager.changePassword(
await this.syncManager.getServerURL(),
this.authManager.user.email,
currentServerPw,
newKeys,
newAuthParams
);
if (response.error) {
this.alertManager.alert({
text: response.error.message
? response.error.message
: "There was an error changing your password. Please try again."
});
return false;
} else {
return true;
}
}
downloadBackup(encrypted) {
this.archiveManager.downloadBackup(encrypted);
}
dismiss() {
if (this.lockContinue) {
this.alertManager.alert({
text: "Cannot close window until pending tasks are complete."
});
} else {
this.$element.remove();
this.$scope.$destroy();
}
}
}
export class PasswordWizard {
constructor() {
this.restrict = 'E';
this.template = template;
this.controller = PasswordWizardCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
this.scope = {
type: '='
};
}
}

View File

@@ -167,8 +167,8 @@ class PasswordWizardCtrl extends PureViewCtrl implements PasswordWizardScope {
});
if (!success) {
this.application.alertService!.alert(
response!.error.message
? response!.error.message
response?.error?.message
? response.error.message
: "There was an error changing your password. Please try again."
);
this.setFormDataState({

View File

@@ -9,6 +9,7 @@ import {
} from 'snjs';
import template from '%/directives/revision-preview-modal.pug';
import { PayloadContent } from '@node_modules/snjs/dist/@types/protocol/payloads/generator';
import { confirmDialog } from '@/services/alertService';
interface RevisionPreviewScope {
uuid: string
@@ -88,7 +89,7 @@ class RevisionPreviewModalCtrl implements RevisionPreviewScope {
}
}
restore(asCopy: boolean) {
async restore(asCopy: boolean) {
const run = async () => {
if (asCopy) {
const contentCopy = Object.assign({}, this.content);
@@ -109,15 +110,12 @@ class RevisionPreviewModalCtrl implements RevisionPreviewScope {
};
if (!asCopy) {
this.application.alertService!.confirm(
"Are you sure you want to replace the current note's contents with what you see in this preview?",
undefined,
undefined,
undefined,
run,
undefined,
true,
);
if (await confirmDialog({
text: "Are you sure you want to replace the current note's contents with what you see in this preview?",
confirmButtonStyle: 'danger',
})) {
run();
}
} else {
run();
}

View File

@@ -2,6 +2,7 @@ import { WebDirective } from './../../types';
import { WebApplication } from '@/ui_models/application';
import template from '%/directives/session-history-menu.pug';
import { SNItem, ItemHistoryEntry, ItemHistory } from '@node_modules/snjs/dist/@types';
import { confirmDialog } from '@/services/alertService';
interface SessionHistoryScope {
application: WebApplication
@@ -57,43 +58,33 @@ class SessionHistoryMenuCtrl implements SessionHistoryScope {
}
}
clearItemHistory() {
this.application.alertService!.confirm(
"Are you sure you want to delete the local session history for this note?",
undefined,
undefined,
undefined,
() => {
this.application.historyManager!.clearHistoryForItem(this.item).then(() => {
this.$timeout(() => {
this.reloadHistory();
});
async clearItemHistory() {
if (await confirmDialog({
text: "Are you sure you want to delete the local session history for this note?",
confirmButtonStyle: 'danger',
})) {
this.application.historyManager!.clearHistoryForItem(this.item).then(() => {
this.$timeout(() => {
this.reloadHistory();
});
},
undefined,
true,
);
});
}
}
clearAllHistory() {
this.application.alertService!.confirm(
"Are you sure you want to delete the local session history for all notes?",
undefined,
undefined,
undefined,
() => {
this.application.historyManager!.clearAllHistory().then(() => {
this.$timeout(() => {
this.reloadHistory();
});
if (confirmDialog({
text: "Are you sure you want to delete the local session history for all notes?",
confirmButtonStyle: 'danger'
})) {
this.application.historyManager!.clearAllHistory().then(() => {
this.$timeout(() => {
this.reloadHistory();
});
},
undefined,
true,
);
});
}
}
toggleDiskSaving() {
async toggleDiskSaving() {
const run = () => {
this.application.historyManager!.toggleDiskSaving().then(() => {
this.$timeout(() => {
@@ -102,17 +93,14 @@ class SessionHistoryMenuCtrl implements SessionHistoryScope {
});
};
if (!this.application.historyManager!.isDiskEnabled()) {
this.application.alertService!.confirm(
`Are you sure you want to save history to disk? This will decrease general
performance, especially as you type. You are advised to disable this feature
if you experience any lagging.`,
undefined,
undefined,
undefined,
run,
undefined,
true,
);
if (await confirmDialog({
text: `Are you sure you want to save history to disk? This will decrease general
performance, especially as you type. You are advised to disable this feature
if you experience any lagging.`,
confirmButtonStyle: 'danger',
})) {
run();
}
} else {
run();
}

View File

@@ -1,163 +0,0 @@
import { PrivilegesManager } from '@/services/privilegesManager';
export class ArchiveManager {
/* @ngInject */
constructor(passcodeManager, authManager, modelManager, privilegesManager) {
this.passcodeManager = passcodeManager;
this.authManager = authManager;
this.modelManager = modelManager;
this.privilegesManager = privilegesManager;
}
/*
Public
*/
async downloadBackup(encrypted) {
return this.downloadBackupOfItems(this.modelManager.allItems, encrypted);
}
async downloadBackupOfItems(items, encrypted) {
const run = async () => {
// download in Standard Notes format
let keys, authParams;
if(encrypted) {
if(this.authManager.offline() && this.passcodeManager.hasPasscode()) {
keys = this.passcodeManager.keys();
authParams = this.passcodeManager.passcodeAuthParams();
} else {
keys = await this.authManager.keys();
authParams = await this.authManager.getAuthParams();
}
const data = await this.__itemsData(items, keys, authParams);
this.__downloadData(data,
`Standard Notes Encrypted Backup and Import File - ${this.__formattedDate()}.txt`);
} else {
this.__downloadZippedItems(items);
}
};
if(await this.privilegesManager.actionRequiresPrivilege(PrivilegesManager.ActionManageBackups)) {
this.privilegesManager.presentPrivilegesModal(PrivilegesManager.ActionManageBackups, () => {
run();
});
} else {
run();
}
}
/*
Private
*/
__formattedDate() {
var string = `${new Date()}`;
// Match up to the first parenthesis, i.e do not include '(Central Standard Time)'
var matches = string.match(/^(.*?) \(/);
if(matches.length >= 2) {
return matches[1];
}
return string;
}
async __itemsData(items, keys, authParams) {
const data = await this.modelManager.getJSONDataForItems(items, keys, authParams);
const blobData = new Blob([data], {type: 'text/json'});
return blobData;
}
__loadZip(callback) {
if(window.zip) {
callback();
return;
}
var scriptTag = document.createElement('script');
scriptTag.src = "/assets/zip/zip.js";
scriptTag.async = false;
var headTag = document.getElementsByTagName('head')[0];
headTag.appendChild(scriptTag);
scriptTag.onload = function() {
zip.workerScriptsPath = "assets/zip/";
callback();
};
}
__downloadZippedItems(items) {
this.__loadZip(() => {
zip.createWriter(new zip.BlobWriter("application/zip"), async (zipWriter) => {
var index = 0;
const data = await this.modelManager.getJSONDataForItems(items);
await new Promise((resolve) => {
const blob = new Blob([data], {type: 'text/plain'});
zipWriter.add(
'Standard Notes Backup and Import File.txt',
new zip.BlobReader(blob),
resolve
);
});
const nextFile = () => {
var item = items[index];
var name, contents;
if(item.content_type === "Note") {
name = item.content.title;
contents = item.content.text;
} else {
name = item.content_type;
contents = JSON.stringify(item.content, null, 2);
}
if(!name) {
name = "";
}
const blob = new Blob([contents], {type: 'text/plain'});
let filePrefix = name.replace(/\//g, "").replace(/\\+/g, "");
const fileSuffix = `-${item.uuid.split("-")[0]}.txt`;
// Standard max filename length is 255. Slice the note name down to allow filenameEnd
filePrefix = filePrefix.slice(0, (255 - fileSuffix.length));
const fileName = `Items/${item.content_type}/${filePrefix}${fileSuffix}`;
zipWriter.add(fileName, new zip.BlobReader(blob), () => {
index++;
if(index < items.length) {
nextFile();
} else {
zipWriter.close((blob) => {
this.__downloadData(blob, `Standard Notes Backup - ${this.__formattedDate()}.zip`);
zipWriter = null;
});
}
});
};
nextFile();
}, onerror);
});
}
__hrefForData(data) {
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (this.textFile !== null) {
window.URL.revokeObjectURL(this.textFile);
}
this.textFile = window.URL.createObjectURL(data);
// returns a URL you can use as a href
return this.textFile;
}
__downloadData(data, fileName) {
var link = document.createElement('a');
link.setAttribute('download', fileName);
link.href = this.__hrefForData(data);
document.body.appendChild(link);
link.click();
link.remove();
}
}

View File

@@ -1,4 +1,116 @@
import { WebDirective } from './../types';
export declare class EditorPanel extends WebDirective {
constructor();
/// <reference types="pug" />
export class EditorPanel {
restrict: string;
scope: {};
template: import("pug").compileTemplate;
replace: boolean;
controller: typeof EditorCtrl;
controllerAs: string;
bindToController: boolean;
}
declare class EditorCtrl {
constructor($timeout: any, $rootScope: any, alertManager: any, appState: any, authManager: any, actionsManager: any, componentManager: any, desktopManager: any, keyboardManager: any, modelManager: any, preferencesManager: any, privilegesManager: any, sessionHistory: any, syncManager: any);
$rootScope: any;
alertManager: any;
appState: any;
actionsManager: any;
authManager: any;
componentManager: any;
desktopManager: any;
keyboardManager: any;
modelManager: any;
preferencesManager: any;
privilegesManager: any;
syncManager: any;
state: {
componentStack: never[];
editorDebounce: number;
isDesktop: any;
spellcheck: boolean;
mutable: {
tagsString: string;
};
};
leftResizeControl: {};
rightResizeControl: {};
/** Used by .pug template */
prefKeyMonospace: any;
prefKeySpellcheck: any;
prefKeyMarginResizers: any;
addAppStateObserver(): void;
handleNoteSelectionChange(note: any, previousNote: any): Promise<void>;
addMappingObservers(): void;
addSyncEventHandler(): void;
addSyncStatusObserver(): void;
syncStatusObserver: any;
editorForNote(note: any): any;
setMenuState(menu: any, state: any): void;
toggleMenu(menu: any): void;
closeAllMenus({ exclude }?: {
exclude: any;
}): void;
editorMenuOnSelect: (component: any) => void;
hasAvailableExtensions(): boolean;
performFirefoxPinnedTabFix(): void;
saveNote({ bypassDebouncer, updateClientModified, dontUpdatePreviews }: {
bypassDebouncer: any;
updateClientModified: any;
dontUpdatePreviews: any;
}): void;
saveTimeout: any;
didShowErrorAlert: boolean | undefined;
showSavingStatus(): void;
showAllChangesSavedStatus(): void;
showErrorStatus(error: any): void;
setStatus(status: any, wait?: boolean): void;
statusTimeout: any;
contentChanged(): void;
onTitleEnter($event: any): void;
onTitleChange(): void;
focusEditor(): void;
lastEditorFocusEventSource: any;
focusTitle(): void;
clickedTextArea(): void;
onNameFocus(): void;
editingName: boolean | undefined;
onContentFocus(): void;
onNameBlur(): void;
selectedMenuItem(hide: any): void;
deleteNote(permanently: any): Promise<void>;
performNoteDeletion(note: any): void;
restoreTrashedNote(): void;
deleteNotePermanantely(): void;
getTrashCount(): any;
emptyTrash(): void;
togglePin(): void;
toggleLockNote(): void;
toggleProtectNote(): void;
toggleNotePreview(): void;
toggleArchiveNote(): void;
reloadTagsString(): void;
addTag(tag: any): void;
removeTag(tag: any): void;
saveTags({ strings }?: {
strings: any;
}): void;
onPanelResizeFinish: (width: any, left: any, isMaxWidth: any) => void;
loadPreferences(): void;
reloadFont(): void;
toggleKey(key: any): Promise<void>;
/** @components */
onEditorLoad: (editor: any) => void;
registerComponentHandler(): void;
reloadComponentStackArray(): void;
reloadComponentContext(): void;
toggleStackComponentForCurrentItem(component: any): void;
disassociateComponentWithCurrentNote(component: any): void;
associateComponentWithCurrentNote(component: any): void;
registerKeyboardShortcuts(): void;
altKeyObserver: any;
trashKeyObserver: any;
deleteKeyObserver: any;
onSystemEditorLoad(): void;
loadedTabListener: boolean | undefined;
tabObserver: any;
}
export {};

View File

@@ -4,5 +4,5 @@ export declare function autofocus($timeout: ng.ITimeoutService): {
scope: {
shouldFocus: string;
};
link: ($scope: import("angular").IScope, $element: JQLite) => void;
link: ($scope: ng.IScope, $element: JQLite) => void;
};

View File

@@ -2,5 +2,5 @@
export declare function clickOutside($document: ng.IDocumentService): {
restrict: string;
replace: boolean;
link: ($scope: import("angular").IScope, $element: JQLite, attrs: any) => void;
link($scope: ng.IScope, $element: JQLite, attrs: any): void;
};

View File

@@ -1,9 +1,9 @@
import angular from 'angular';
/// <reference types="angular" />
export declare function delayHide($timeout: ng.ITimeoutService): {
restrict: string;
scope: {
show: string;
delay: string;
};
link: (scope: angular.IScope, elem: JQLite) => void;
link: (scope: ng.IScope, elem: JQLite) => void;
};

View File

@@ -1,5 +1,5 @@
/// <reference types="angular" />
export declare function elemReady($parse: ng.IParseService): {
restrict: string;
link: ($scope: import("angular").IScope, elem: JQLite, attrs: any) => void;
link: ($scope: ng.IScope, elem: JQLite, attrs: any) => void;
};

View File

@@ -4,5 +4,5 @@ export declare function fileChange(): {
scope: {
handler: string;
};
link: (scope: import("angular").IScope, element: JQLite) => void;
link: (scope: ng.IScope, element: JQLite) => void;
};

View File

@@ -1,4 +1,4 @@
/// <reference types="angular" />
export declare function infiniteScroll(): {
link: (scope: import("angular").IScope, elem: JQLite, attrs: any) => void;
link: (scope: ng.IScope, elem: JQLite, attrs: any) => void;
};

View File

@@ -1,5 +1,5 @@
/// <reference types="angular" />
export declare function lowercase(): {
require: string;
link: (scope: import("angular").IScope, _: JQLite, attrs: any, ctrl: any) => void;
link: (scope: ng.IScope, _: JQLite, attrs: any, ctrl: any) => void;
};

View File

@@ -1,5 +1,5 @@
/// <reference types="angular" />
export declare function selectOnFocus($window: ng.IWindowService): {
restrict: string;
link: (scope: import("angular").IScope, element: JQLite) => void;
link: (scope: ng.IScope, element: JQLite) => void;
};

View File

@@ -1,2 +1,2 @@
/// <reference types="angular" />
export declare function snEnter(): (scope: import("angular").IScope, element: JQLite, attrs: any) => void;
export declare function snEnter(): (scope: ng.IScope, element: JQLite, attrs: any) => void;

View File

@@ -1,7 +1,9 @@
import { DeviceInterface, SNApplication } from 'snjs';
import { Platform } from './services/platform';
export declare class WebDeviceInterface extends DeviceInterface {
private platform;
private database;
constructor(namespace: string, timeout: any);
constructor(namespace: string, timeout: any, platform: Platform);
setApplication(application: SNApplication): void;
deinit(): void;
getRawStorageValue(key: string): Promise<string | null>;
@@ -22,7 +24,7 @@ export declare class WebDeviceInterface extends DeviceInterface {
saveRawDatabasePayloads(payloads: any[]): Promise<void>;
removeRawDatabasePayloadWithId(id: string): Promise<void>;
removeAllRawDatabasePayloads(): Promise<void>;
getKeychainValue(): Promise<any>;
getKeychainValue(): Promise<unknown>;
setKeychainValue(value: any): Promise<void>;
clearKeychainValue(): Promise<void>;
openUrl(url: string): void;

View File

@@ -1,5 +1,22 @@
import { SNAlertService } from 'snjs';
export declare class AlertService extends SNAlertService {
alert(text: string, title: string, closeButtonText: string | undefined, onClose: () => void): Promise<unknown>;
confirm(text: string, title: string, confirmButtonText: string | undefined, cancelButtonText: string | undefined, onConfirm: () => void, onCancel: () => void, destructive?: boolean): Promise<unknown>;
import { SNAlertService, ButtonType } from 'snjs';
/** @returns a promise resolving to true if the user confirmed, false if they canceled */
export declare function confirmDialog({ text, title, confirmButtonText, cancelButtonText, confirmButtonStyle, }: {
text: string;
title?: string;
confirmButtonText?: string;
cancelButtonText?: string;
confirmButtonStyle?: 'danger' | 'info';
}): Promise<boolean>;
export declare function alertDialog({ title, text, closeButtonText, }: {
title?: string;
text: string;
closeButtonText?: string;
}): Promise<void>;
export declare class AlertService implements SNAlertService {
/**
* @deprecated use the standalone `alertDialog` function instead
*/
alert(text: string, title?: string, closeButtonText?: string): Promise<void>;
confirm(text: string, title?: string, confirmButtonText?: string, confirmButtonType?: ButtonType, cancelButtonText?: string): Promise<boolean>;
blockingDialog(text: string): () => void;
}

View File

@@ -1,11 +1,9 @@
import { WebApplication } from '@/ui_models/application';
import { SNItem } from 'snjs';
export declare class ArchiveManager {
private readonly application;
private textFile?;
constructor(application: WebApplication);
downloadBackup(encrypted: boolean): Promise<void>;
downloadBackupOfItems(items: SNItem[], encrypted: boolean): Promise<void>;
private formattedDate;
private itemsData;
private get zip();

View File

@@ -0,0 +1,11 @@
/** Platform-specific (i-e desktop/web) behavior is handled by a Platform object. */
export interface Platform {
getKeychainValue(): Promise<unknown>;
setKeychainValue(value: any): Promise<void>;
clearKeychainValue(): Promise<void>;
}
export declare class WebPlatform implements Platform {
getKeychainValue(): Promise<unknown>;
setKeychainValue(value: any): Promise<void>;
clearKeychainValue(): Promise<void>;
}

View File

@@ -7,7 +7,7 @@ export declare class PreferencesManager extends ApplicationService {
onAppLaunch(): Promise<void>;
get webApplication(): WebApplication;
streamPreferences(): void;
private loadSingleton;
private reloadSingleton;
syncUserPreferences(): void;
getValue(key: WebPrefKey, defaultValue?: any): any;
setUserPrefValue(key: WebPrefKey, value: any, sync?: boolean): Promise<void>;

View File

@@ -2,7 +2,7 @@ import { WebApplication } from '@/ui_models/application';
import { ApplicationService, ApplicationEvent } from 'snjs';
export declare class ThemeManager extends ApplicationService {
private activeThemes;
private unsubState;
private unsubState?;
private unregisterDesktop;
private unregisterComponent;
/** @override */

View File

@@ -32,5 +32,11 @@ export declare const STRING_GENERATING_LOGIN_KEYS = "Generating Login Keys...";
export declare const STRING_GENERATING_REGISTER_KEYS = "Generating Account Keys...";
export declare const STRING_INVALID_IMPORT_FILE = "Unable to open file. Ensure it is a proper JSON file and try again.";
export declare function StringImportError(errorCount: number): string;
export declare const STRING_ENTER_ACCOUNT_PASSCODE = "Enter your application passcode";
export declare const STRING_ENTER_ACCOUNT_PASSWORD = "Enter your account password";
export declare const STRING_ENTER_PASSCODE_FOR_MIGRATION = "Your application passcode is required to perform an upgrade of your local data storage structure.";
export declare const STRING_STORAGE_UPDATE = "Storage Update";
export declare const STRING_AUTHENTICATION_REQUIRED = "Authentication Required";
/** @password_change */
export declare const STRING_FAILED_PASSWORD_CHANGE = "There was an error re-encrypting your items. Your password was changed, but not all your items were properly re-encrypted and synced. You should try syncing again. If all else fails, you should restore your notes from backup.";
export declare const STRING_CONFIRM_APP_QUIT_DURING_UPGRADE: string;

View File

@@ -2,9 +2,10 @@
import { ComponentGroup } from './component_group';
import { EditorGroup } from '@/ui_models/editor_group';
import { PasswordWizardType } from '@/types';
import { SNApplication, Challenge, ChallengeOrchestrator, ProtectedAction } from 'snjs';
import { SNApplication, Challenge, ProtectedAction } from 'snjs';
import { DesktopManager, LockManager, ArchiveManager, NativeExtManager, StatusManager, ThemeManager, PreferencesManager, KeyboardManager } from '@/services';
import { AppState } from '@/ui_models/app_state';
import { Platform } from '@/services/platform';
declare type WebServices = {
appState: AppState;
desktopService: DesktopManager;
@@ -24,7 +25,7 @@ export declare class WebApplication extends SNApplication {
private currentAuthenticationElement?;
editorGroup: EditorGroup;
componentGroup: ComponentGroup;
constructor($compile: ng.ICompileService, $timeout: ng.ITimeoutService, scope: ng.IScope, onDeinit: (app: WebApplication) => void);
constructor($compile: ng.ICompileService, $timeout: ng.ITimeoutService, scope: ng.IScope, onDeinit: (app: WebApplication) => void, platform: Platform);
/** @override */
deinit(): void;
setWebServices(services: WebServices): void;
@@ -39,7 +40,7 @@ export declare class WebApplication extends SNApplication {
getKeyboardService(): KeyboardManager;
checkForSecurityUpdate(): Promise<boolean>;
presentPasswordWizard(type: PasswordWizardType): void;
promptForChallenge(challenge: Challenge, orchestrator: ChallengeOrchestrator): void;
promptForChallenge(challenge: Challenge): void;
performProtocolUpgrade(): Promise<void>;
presentPrivilegesModal(action: ProtectedAction, onSuccess?: any, onCancel?: any): Promise<void>;
presentPrivilegesManagementModal(): void;

View File

@@ -1,14 +1,16 @@
/// <reference types="angular" />
import { WebApplication } from './application';
import { Platform } from '@/services/platform';
declare type AppManagerChangeCallback = () => void;
export declare class ApplicationGroup {
private platform;
$compile: ng.ICompileService;
$rootScope: ng.IRootScopeService;
$timeout: ng.ITimeoutService;
applications: WebApplication[];
changeObservers: AppManagerChangeCallback[];
activeApplication?: WebApplication;
constructor($compile: ng.ICompileService, $rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService);
constructor($compile: ng.ICompileService, $rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService, platform: Platform);
private createDefaultApplication;
/** @callback */
onApplicationDeinit(application: WebApplication): void;
@@ -20,7 +22,7 @@ export declare class ApplicationGroup {
* Any application which is no longer active is destroyed, and
* must be removed from the interface.
*/
addApplicationChangeObserver(callback: AppManagerChangeCallback): void;
addApplicationChangeObserver(callback: AppManagerChangeCallback): () => void;
private notifyObserversOfAppChange;
}
export {};

View File

@@ -20,6 +20,7 @@ export declare class Editor {
* Register to be notified when the editor's note changes.
*/
onNoteChange(callback: () => void): void;
clearNoteChangeListener(): void;
/**
* Register to be notified when the editor's note's values change
* (and thus a new object reference is created)
@@ -28,5 +29,5 @@ export declare class Editor {
/**
* Sets the editor contents by setting its note.
*/
setNote(note: SNNote): void;
setNote(note: SNNote, isTemplate?: boolean): void;
}

View File

@@ -1,3 +1,4 @@
export declare const isDev: boolean;
export declare function getParameterByName(name: string, url: string): string | null;
export declare function isNullOrUndefined(value: any): boolean;
export declare function getPlatformString(): string;

View File

@@ -3,16 +3,16 @@ import { ApplicationEvent } from 'snjs';
import { WebApplication } from '@/ui_models/application';
export declare type CtrlState = Partial<Record<string, any>>;
export declare type CtrlProps = Partial<Record<string, any>>;
export declare class PureViewCtrl {
export declare class PureViewCtrl<P = CtrlProps, S = CtrlState> {
props: P;
$timeout: ng.ITimeoutService;
/** Passed through templates */
application: WebApplication;
props: CtrlProps;
state: CtrlState;
state: S;
private unsubApp;
private unsubState;
private stateTimeout;
constructor($timeout: ng.ITimeoutService);
private stateTimeout?;
constructor($timeout: ng.ITimeoutService, props?: P);
$onInit(): void;
deinit(): void;
$onDestroy(): void;
@@ -20,8 +20,8 @@ export declare class PureViewCtrl {
/** @private */
resetState(): Promise<void>;
/** @override */
getInitialState(): {};
setState(state: CtrlState): Promise<unknown>;
getInitialState(): S;
setState(state: Partial<S>): Promise<unknown>;
updateUI(func: () => void): Promise<void>;
initProps(props: CtrlProps): void;
addAppStateObserver(): void;

View File

@@ -149,7 +149,7 @@ declare class $SanitizeProvider {
* @returns {boolean|$sanitizeProvider} Returns the currently configured value if called
* without an argument or self for chaining otherwise.
*/
enableSvg: (enableSvg: any) => any;
enableSvg: (enableSvg: any) => boolean | any;
/**
* @ngdoc method
* @name $sanitizeProvider#addValidElements
@@ -196,7 +196,7 @@ declare class $SanitizeProvider {
*
* @return {$sanitizeProvider} Returns self for chaining.
*/
addValidElements: (elements: Object | string[]) => any;
addValidElements: (elements: Array<string> | Object) => any;
/**
* @ngdoc method
* @name $sanitizeProvider#addValidAttrs
@@ -226,7 +226,7 @@ declare class $SanitizeProvider {
*
* @returns {$sanitizeProvider} Returns self for chaining.
*/
addValidAttrs: (attrs: string[]) => any;
addValidAttrs: (attrs: Array<string>) => any;
}
declare function sanitizeText(chars: any): string;
declare var $sanitizeMinErr: any;