Footer TS

This commit is contained in:
Mo Bitar
2020-04-12 12:41:49 -05:00
parent 3542cba002
commit 956c9a1814
11 changed files with 331 additions and 325 deletions

View File

@@ -1,7 +1,8 @@
import { PanelPuppet, WebDirective, PermissionsModalScope, ModalComponentScope } from './../types';
import { getPlatformString } from '@/utils';
import template from '%/application-view.pug';
import { AppStateEvent } from '@/services/state';
import { ApplicationEvent } from 'snjs';
import { ApplicationEvent, SNComponent } from 'snjs';
import angular from 'angular';
import {
PANEL_NAME_NOTES,
@@ -12,14 +13,27 @@ import {
STRING_DEFAULT_FILE_ERROR
} from '@/strings';
import { PureCtrl } from './abstract/pure_ctrl';
import { PermissionDialog } from '@/../../../../snjs/dist/@types/services/component_manager';
class ApplicationViewCtrl extends PureCtrl {
private $compile?: ng.ICompileService
private $location?: ng.ILocationService
private $rootScope?: ng.IRootScopeService
public platformString: string
private completedInitialSync = false
private syncStatus: any
private notesCollapsed = false
private tagsCollapsed = false
private showingDownloadStatus = false
private uploadSyncStatus: any
private lastAlertShownDate?: Date
/* @ngInject */
constructor(
$compile,
$location,
$rootScope,
$timeout
$compile: ng.ICompileService,
$location: ng.ILocationService,
$rootScope: ng.IRootScopeService,
$timeout: ng.ITimeoutService
) {
super($timeout);
this.$location = $location;
@@ -35,17 +49,16 @@ class ApplicationViewCtrl extends PureCtrl {
}
deinit() {
this.$location = null;
this.$rootScope = null;
this.$compile = null;
this.application = null;
this.lockScreenPuppet = null;
this.$location = undefined;
this.$rootScope = undefined;
this.$compile = undefined;
this.application = undefined;
window.removeEventListener('dragover', this.onDragOver, true);
window.removeEventListener('drop', this.onDragDrop, true);
this.onDragDrop = null;
this.onDragOver = null;
this.openModalComponent = null;
this.presentPermissionsDialog = null;
(this.onDragDrop as any) = undefined;
(this.onDragOver as any) = undefined;
(this.openModalComponent as any) = undefined;
(this.presentPermissionsDialog as any) = undefined;
super.deinit();
}
@@ -55,41 +68,39 @@ class ApplicationViewCtrl extends PureCtrl {
}
async loadApplication() {
await this.application.prepareForLaunch({
callbacks: {
receiveChallenge: async (challenge, orchestrator) => {
this.application.promptForChallenge(challenge, orchestrator);
}
await this.application!.prepareForLaunch({
receiveChallenge: async (challenge, orchestrator) => {
this.application!.promptForChallenge(challenge, orchestrator);
}
});
await this.application.launch();
await this.application!.launch();
}
onAppStart() {
async onAppStart() {
super.onAppStart();
this.overrideComponentManagerFunctions();
this.application.componentManager.setDesktopManager(
this.application.getDesktopService()
this.application!.componentManager!.setDesktopManager(
this.application!.getDesktopService()
);
this.setState({
ready: true,
needsUnlock: this.application.hasPasscode()
needsUnlock: this.application!.hasPasscode()
});
}
onAppLaunch() {
async onAppLaunch() {
super.onAppLaunch();
this.setState({ needsUnlock: false });
this.handleAutoSignInFromParams();
}
onUpdateAvailable() {
this.$rootScope.$broadcast('new-update-available');
this.$rootScope!.$broadcast('new-update-available');
};
/** @override */
async onAppEvent(eventName) {
async onAppEvent(eventName: ApplicationEvent) {
super.onAppEvent(eventName);
if (eventName === ApplicationEvent.LocalDataIncrementalLoad) {
this.updateLocalDataStatus();
@@ -102,31 +113,31 @@ class ApplicationViewCtrl extends PureCtrl {
this.updateLocalDataStatus();
} else if (eventName === ApplicationEvent.WillSync) {
if (!this.completedInitialSync) {
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
this.syncStatus = this.application!.getStatusService().replaceStatusWithString(
this.syncStatus,
"Syncing..."
);
}
} else if (eventName === ApplicationEvent.CompletedSync) {
if (!this.completedInitialSync) {
this.syncStatus = this.application.getStatusService().removeStatus(this.syncStatus);
this.syncStatus = this.application!.getStatusService().removeStatus(this.syncStatus);
this.completedInitialSync = true;
}
} else if (eventName === ApplicationEvent.InvalidSyncSession) {
this.showInvalidSessionAlert();
} else if (eventName === ApplicationEvent.LocalDatabaseReadError) {
this.application.alertService.alert({
text: 'Unable to load local database. Please restart the app and try again.'
});
this.application!.alertService!.alert(
'Unable to load local database. Please restart the app and try again.'
);
} else if (eventName === ApplicationEvent.LocalDatabaseWriteError) {
this.application.alertService.alert({
text: 'Unable to write to local database. Please restart the app and try again.'
});
this.application!.alertService!.alert(
'Unable to write to local database. Please restart the app and try again.'
);
}
}
/** @override */
async onAppStateEvent(eventName, data) {
async onAppStateEvent(eventName: AppStateEvent, data?: any) {
if (eventName === AppStateEvent.PanelResized) {
if (data.panel === PANEL_NAME_NOTES) {
this.notesCollapsed = data.collapsed;
@@ -139,41 +150,41 @@ class ApplicationViewCtrl extends PureCtrl {
if (this.tagsCollapsed) { appClass += " collapsed-tags"; }
this.setState({ appClass });
} else if (eventName === AppStateEvent.WindowDidFocus) {
if (!(await this.application.isLocked())) {
this.application.sync();
if (!(await this.application!.isLocked())) {
this.application!.sync();
}
}
}
updateLocalDataStatus() {
const syncStatus = this.application.getSyncStatus();
const syncStatus = this.application!.getSyncStatus();
const stats = syncStatus.getStats();
const encryption = this.application.isEncryptionAvailable();
const encryption = this.application!.isEncryptionAvailable();
if (stats.localDataDone) {
this.syncStatus = this.application.getStatusService().removeStatus(this.syncStatus);
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 = this.application!.getStatusService().replaceStatusWithString(
this.syncStatus,
loadingStatus
);
}
updateSyncStatus() {
const syncStatus = this.application.getSyncStatus();
const syncStatus = this.application!.getSyncStatus();
const stats = syncStatus.getStats();
if (syncStatus.hasError()) {
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
this.syncStatus = this.application!.getStatusService().replaceStatusWithString(
this.syncStatus,
'Unable to Sync'
);
} else if (stats.downloadCount > 20) {
const text = `Downloading ${stats.downloadCount} items. Keep app open.`;
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
this.syncStatus = this.application!.getStatusService().replaceStatusWithString(
this.syncStatus,
text
);
@@ -181,56 +192,63 @@ class ApplicationViewCtrl extends PureCtrl {
} else if (this.showingDownloadStatus) {
this.showingDownloadStatus = false;
const text = "Download Complete.";
this.syncStatus = this.application.getStatusService().replaceStatusWithString(
this.syncStatus = this.application!.getStatusService().replaceStatusWithString(
this.syncStatus,
text
);
setTimeout(() => {
this.syncStatus = this.application.getStatusService().removeStatus(this.syncStatus);
this.syncStatus = this.application!.getStatusService().removeStatus(this.syncStatus);
}, 2000);
} else if (stats.uploadTotalCount > 20) {
this.uploadSyncStatus = this.application.getStatusService().replaceStatusWithString(
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 = this.application!.getStatusService().removeStatus(
this.uploadSyncStatus
);
}
}
openModalComponent(component) {
const scope = this.$rootScope.$new(true);
openModalComponent(component: SNComponent) {
const scope = this.$rootScope!.$new(true) as ModalComponentScope;
scope.component = component;
const el = this.$compile("<component-modal component='component' class='sk-modal'></component-modal>")(scope);
const el = this.$compile!(
"<component-modal component='component' class='sk-modal'></component-modal>"
)(scope as any);
angular.element(document.body).append(el);
}
presentPermissionsDialog(dialog) {
const scope = this.$rootScope.$new(true);
presentPermissionsDialog(dialog: PermissionDialog) {
const scope = this.$rootScope!.$new(true) as PermissionsModalScope;
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);
const el = this.$compile!(
"<permissions-modal component='component' permissions-string='permissionsString'"
+ " callback='callback' class='sk-modal'></permissions-modal>"
)(scope as any);
angular.element(document.body).append(el);
}
overrideComponentManagerFunctions() {
this.application.componentManager.openModalComponent = this.openModalComponent;
this.application.componentManager.presentPermissionsDialog = this.presentPermissionsDialog;
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();
if (
!this.lastAlertShownDate ||
(new Date().getTime() - this.lastAlertShownDate!.getTime()) / 1000 > SHOW_INTERVAL
) {
this.lastAlertShownDate = new Date();
setTimeout(() => {
this.application.alertService.alert({
text: STRING_SESSION_EXPIRED
});
this.application!.alertService!.alert(
STRING_SESSION_EXPIRED
);
}, 500);
}
}
@@ -245,49 +263,49 @@ class ApplicationViewCtrl extends PureCtrl {
window.addEventListener('drop', this.onDragDrop, true);
}
onDragOver(event) {
if (event.dataTransfer.files.length > 0) {
onDragOver(event: DragEvent) {
if (event.dataTransfer!.files.length > 0) {
event.preventDefault();
}
}
onDragDrop(event) {
if (event.dataTransfer.files.length > 0) {
onDragDrop(event: DragEvent) {
if (event.dataTransfer!.files.length > 0) {
event.preventDefault();
this.application.alertService.alert({
text: STRING_DEFAULT_FILE_ERROR
});
this.application!.alertService!.alert(
STRING_DEFAULT_FILE_ERROR
);
}
}
async handleAutoSignInFromParams() {
const params = this.$location.search();
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();
const user = this.application!.getUser();
if (user) {
if (user.email === email && await this.application.getHost() === server) {
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!.signOut();
}
}
await this.application.setHost(server);
this.application.signIn({
email: email,
password: password,
});
await this.application!.setHost(server);
this.application!.signIn(
email,
password,
);
}
}
export class ApplicationView {
export class ApplicationView extends WebDirective {
constructor() {
super();
this.template = template;
this.controller = ApplicationViewCtrl;
this.replace = true;

View File

@@ -1,9 +1,14 @@
import { FooterStatus, WebDirective } from './../types';
import { dateToLocalizedString } from '@/utils';
import {
ApplicationEvent,
TIMING_STRATEGY_FORCE_SPAWN_NEW,
SyncQueueStrategy,
ProtectedAction,
ContentTypes
ContentType,
SNComponent,
SNTheme,
ComponentArea,
ComponentAction
} from 'snjs';
import template from '%/footer.pug';
import { AppStateEvent, EventSource } from '@/services/state';
@@ -11,40 +16,71 @@ import {
STRING_GENERIC_SYNC_ERROR,
STRING_NEW_UPDATE_READY
} from '@/strings';
import { PureCtrl } from '@Controllers';
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
import { ComponentMutator } from '@/../../../../snjs/dist/@types/models';
type DockShortcut = {
name: string,
component: SNComponent,
icon: {
type: string
background_color: string
border_color: string
}
}
class FooterCtrl extends PureCtrl {
private $rootScope: ng.IRootScopeService
private rooms: SNComponent[] = []
private themesWithIcons: SNTheme[] = []
private showSyncResolution = false
private unregisterComponent: any
private rootScopeListener1: any
private rootScopeListener2: any
public arbitraryStatusMessage?: string
public user?: any
private backupStatus?: FooterStatus
private offline = true
private showAccountMenu = false
private queueExtReload = false
private reloadInProgress = false
public hasError = false
public isRefreshing = false
public lastSyncDate?: string
public newUpdateAvailable = false
public dockShortcuts: DockShortcut[] = []
public roomShowState: Partial<Record<string, boolean>> = {}
/* @ngInject */
constructor(
$rootScope,
$timeout,
$rootScope: ng.IRootScopeService,
$timeout: ng.ITimeoutService,
) {
super($timeout);
this.$rootScope = $rootScope;
this.rooms = [];
this.themesWithIcons = [];
this.showSyncResolution = false;
this.addRootScopeListeners();
this.toggleSyncResolutionMenu = this.toggleSyncResolutionMenu.bind(this);
this.closeAccountMenu = this.closeAccountMenu.bind(this);
}
deinit() {
this.rooms.length = 0;
this.themesWithIcons.length = 0;
this.unregisterComponent();
this.unregisterComponent = null;
this.unregisterComponent = undefined;
this.rootScopeListener1();
this.rootScopeListener2();
this.rootScopeListener1 = null;
this.rootScopeListener2 = null;
this.closeAccountMenu = null;
this.toggleSyncResolutionMenu = null;
this.rootScopeListener1 = undefined;
this.rootScopeListener2 = undefined;
(this.closeAccountMenu as any) = undefined;
(this.toggleSyncResolutionMenu as any) = undefined;
super.deinit();
}
$onInit() {
super.$onInit();
this.application.getStatusService().addStatusObserver((string) => {
this.application!.getStatusService().addStatusObserver((string: string) => {
this.$timeout(() => {
this.arbitraryStatusMessage = string;
});
@@ -58,18 +94,18 @@ class FooterCtrl extends PureCtrl {
}
reloadUpgradeStatus() {
this.application.checkForSecurityUpdate().then((available) => {
this.application!.checkForSecurityUpdate().then((available) => {
this.setState({
dataUpgradeAvailable: available
});
});
}
onAppLaunch() {
async onAppLaunch() {
super.onAppLaunch();
this.reloadPasscodeStatus();
this.reloadUpgradeStatus();
this.user = this.application.getUser();
this.user = this.application!.getUser();
this.updateOfflineStatus();
this.findErrors();
this.streamItems();
@@ -77,7 +113,7 @@ class FooterCtrl extends PureCtrl {
}
async reloadPasscodeStatus() {
const hasPasscode = this.application.hasPasscode();
const hasPasscode = this.application!.hasPasscode();
this.setState({
hasPasscode: hasPasscode
});
@@ -95,30 +131,30 @@ class FooterCtrl extends PureCtrl {
}
/** @override */
onAppStateEvent(eventName, data) {
onAppStateEvent(eventName: AppStateEvent, data: any) {
if (eventName === AppStateEvent.EditorFocused) {
if (data.eventSource === EventSource.UserInteraction) {
this.closeAllRooms();
this.closeAccountMenu();
}
} else if (eventName === AppStateEvent.BeganBackupDownload) {
this.backupStatus = this.application.getStatusService().addStatusFromString(
this.backupStatus = this.application!.getStatusService().addStatusFromString(
"Saving local backup..."
);
} else if (eventName === AppStateEvent.EndedBackupDownload) {
if (data.success) {
this.backupStatus = this.application.getStatusService().replaceStatusWithString(
this.backupStatus,
this.backupStatus = this.application!.getStatusService().replaceStatusWithString(
this.backupStatus!,
"Successfully saved backup."
);
} else {
this.backupStatus = this.application.getStatusService().replaceStatusWithString(
this.backupStatus,
this.backupStatus = this.application!.getStatusService().replaceStatusWithString(
this.backupStatus!,
"Unable to save local backup."
);
}
this.$timeout(() => {
this.backupStatus = this.application.getStatusService().removeStatus(this.backupStatus);
this.backupStatus = this.application!.getStatusService().removeStatus(this.backupStatus!);
}, 2000);
}
}
@@ -131,7 +167,7 @@ class FooterCtrl extends PureCtrl {
/** @override */
onAppEvent(eventName) {
onAppEvent(eventName: ApplicationEvent) {
if (eventName === ApplicationEvent.KeyStatusChanged) {
this.reloadUpgradeStatus();
} else if (eventName === ApplicationEvent.EnteredOutOfSync) {
@@ -143,7 +179,7 @@ class FooterCtrl extends PureCtrl {
outOfSync: false
});
} else if (eventName === ApplicationEvent.CompletedSync) {
if (this.offline && this.application.getNoteCount() === 0) {
if (this.offline && this.application!.getNoteCount() === 0) {
this.showAccountMenu = true;
}
this.syncUpdated();
@@ -156,52 +192,53 @@ class FooterCtrl extends PureCtrl {
}
streamItems() {
this.application.streamItems({
contentType: ContentType.Component,
stream: async () => {
this.rooms = this.application.getItems({
contentType: ContentType.Component
}).filter((candidate) => {
return candidate.area === 'rooms' && !candidate.deleted;
this.application!.streamItems(
ContentType.Component,
async () => {
const components = this.application!.getItems(ContentType.Component) as SNComponent[];
this.rooms = components.filter((candidate) => {
return candidate.area === ComponentArea.Rooms && !candidate.deleted;
});
if (this.queueExtReload) {
this.queueExtReload = false;
this.reloadExtendedData();
}
}
});
);
this.application.streamItems({
contentType: 'SN|Theme',
stream: async () => {
const themes = this.application.getDisplayableItems({
contentType: ContentType.Theme
}).filter((candidate) => {
this.application!.streamItems(
ContentType.Theme,
async () => {
const themes = this.application!.getDisplayableItems(ContentType.Theme) as SNTheme[];
const filteredThemes = themes.filter((candidate) => {
return (
!candidate.deleted &&
candidate.content.package_info &&
candidate.content.package_info.dock_icon
candidate.package_info &&
candidate.package_info.dock_icon
);
}).sort((a, b) => {
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
});
const differ = themes.length !== this.themesWithIcons.length;
this.themesWithIcons = themes;
const differ = filteredThemes.length !== this.themesWithIcons.length;
this.themesWithIcons = filteredThemes;
if (differ) {
this.reloadDockShortcuts();
}
}
});
);
}
registerComponentHandler() {
this.unregisterComponent = this.application.componentManager.registerHandler({
identifier: "roomBar",
areas: ["rooms", "modal"],
activationHandler: (component) => { },
this.unregisterComponent = this.application!.componentManager!.registerHandler({
identifier: 'room-bar',
areas: [ComponentArea.Rooms, ComponentArea.Modal],
activationHandler: () => { },
actionHandler: (component, action, data) => {
if (action === "set-size") {
component.setLastSize(data);
if (action === ComponentAction.SetSize) {
this.application!.changeItem(component.uuid, (m) => {
const mutator = m as ComponentMutator;
mutator.setLastSize(data);
})
}
},
focusHandler: (component, focused) => {
@@ -224,7 +261,8 @@ class FooterCtrl extends PureCtrl {
* then closing it after a short delay.
*/
const extWindow = this.rooms.find((room) => {
return room.package_info.identifier === this.application.getNativeExtService().extManagerId;
return room.package_info.identifier === this.application!
.getNativeExtService().extManagerId;
});
if (!extWindow) {
this.queueExtReload = true;
@@ -240,15 +278,15 @@ class FooterCtrl extends PureCtrl {
}
updateOfflineStatus() {
this.offline = this.application.noAccount();
this.offline = this.application!.noAccount();
}
openSecurityUpdate() {
this.application.performProtocolUpgrade();
this.application!.performProtocolUpgrade();
}
findErrors() {
this.error = this.application.getSyncStatus().error;
this.hasError = this.application!.getSyncStatus().hasError();
}
accountMenuPressed() {
@@ -256,31 +294,31 @@ class FooterCtrl extends PureCtrl {
this.closeAllRooms();
}
toggleSyncResolutionMenu = () => {
toggleSyncResolutionMenu() {
this.showSyncResolution = !this.showSyncResolution;
}
closeAccountMenu = () => {
closeAccountMenu() {
this.showAccountMenu = false;
}
lockApp() {
this.application.lock();
this.application!.lock();
}
refreshData() {
this.isRefreshing = true;
this.application.sync({
timingStrategy: TIMING_STRATEGY_FORCE_SPAWN_NEW,
this.application!.sync({
queueStrategy: SyncQueueStrategy.ForceSpawnNew,
checkIntegrity: true
}).then((response) => {
this.$timeout(() => {
this.isRefreshing = false;
}, 200);
if (response && response.error) {
this.application.alertService.alert({
text: STRING_GENERIC_SYNC_ERROR
});
this.application!.alertService!.alert(
STRING_GENERIC_SYNC_ERROR
);
} else {
this.syncUpdated();
}
@@ -288,7 +326,7 @@ class FooterCtrl extends PureCtrl {
}
syncUpdated() {
this.lastSyncDate = dateToLocalizedString(this.application.getLastSyncDate());
this.lastSyncDate = dateToLocalizedString(this.application!.getLastSyncDate()!);
}
onNewUpdateAvailable() {
@@ -297,16 +335,16 @@ class FooterCtrl extends PureCtrl {
clickedNewUpdateAnnouncement() {
this.newUpdateAvailable = false;
this.application.alertService.alert({
text: STRING_NEW_UPDATE_READY
});
this.application!.alertService!.alert(
STRING_NEW_UPDATE_READY
);
}
reloadDockShortcuts() {
const shortcuts = [];
for (const theme of this.themesWithIcons) {
const name = theme.content.package_info.name;
const icon = theme.content.package_info.dock_icon;
const name = theme.package_info.name;
const icon = theme.package_info.dock_icon;
if (!icon) {
continue;
}
@@ -314,7 +352,7 @@ class FooterCtrl extends PureCtrl {
name: name,
component: theme,
icon: icon
});
} as DockShortcut);
}
this.dockShortcuts = shortcuts.sort((a, b) => {
@@ -327,46 +365,49 @@ class FooterCtrl extends PureCtrl {
return -1;
} else if (bType === 'circle' && aType === 'svg') {
return 1;
} else {
return 0;
}
});
}
initSvgForShortcut(shortcut) {
initSvgForShortcut(shortcut: DockShortcut) {
const id = 'dock-svg-' + shortcut.component.uuid;
const element = document.getElementById(id);
const element = document.getElementById(id)!;
const parser = new DOMParser();
const svg = shortcut.component.content.package_info.dock_icon.source;
const svg = shortcut.component.package_info.dock_icon.source;
const doc = parser.parseFromString(svg, 'image/svg+xml');
element.appendChild(doc.documentElement);
}
selectShortcut(shortcut) {
this.application.componentManager.toggleComponent(shortcut.component);
selectShortcut(shortcut: DockShortcut) {
this.application!.componentManager!.toggleComponent(shortcut.component);
}
onRoomDismiss(room) {
room.showRoom = false;
onRoomDismiss(room: SNComponent) {
this.roomShowState[room.uuid] = false;
}
closeAllRooms() {
for (const room of this.rooms) {
room.showRoom = false;
this.roomShowState[room.uuid] = false;
}
}
async selectRoom(room) {
async selectRoom(room: SNComponent) {
const run = () => {
this.$timeout(() => {
room.showRoom = !room.showRoom;
this.roomShowState[room.uuid] = !this.roomShowState[room.uuid];
});
};
if (!room.showRoom) {
const requiresPrivilege = await this.application.privilegesService.actionRequiresPrivilege(
ProtectedAction.ManageExtensions
);
if (!this.roomShowState[room.uuid]) {
const requiresPrivilege = await this.application!.privilegesService!
.actionRequiresPrivilege(
ProtectedAction.ManageExtensions
);
if (requiresPrivilege) {
this.application.presentPrivilegesModal(
this.application!.presentPrivilegesModal(
ProtectedAction.ManageExtensions,
run
);
@@ -379,15 +420,16 @@ class FooterCtrl extends PureCtrl {
}
clickOutsideAccountMenu() {
if (this.application && this.application.authenticationInProgress()) {
if (this.application && this.application!.authenticationInProgress()) {
return;
}
this.showAccountMenu = false;
}
}
export class Footer {
export class Footer extends WebDirective {
constructor() {
super();
this.restrict = 'E';
this.template = template;
this.controller = FooterCtrl;

View File

@@ -1,78 +0,0 @@
import template from '%/lock-screen.pug';
import { AppStateEvent } from '@/services/state';
import { PureCtrl } from './abstract/pure_ctrl';
const ELEMENT_ID_PASSCODE_INPUT = 'passcode-input';
class LockScreenCtrl extends PureCtrl {
/* @ngInject */
constructor(
$timeout,
) {
super($timeout);
this.formData = {};
}
$onInit() {
super.$onInit();
this.puppet.focusInput = () => {
this.passcodeInput.focus();
};
}
get passcodeInput() {
return document.getElementById(
ELEMENT_ID_PASSCODE_INPUT
);
}
/** @override */
async onAppStateEvent(eventName, data) {
if (eventName === AppStateEvent.WindowDidFocus) {
const input = this.passcodeInput;
if (input) {
input.focus();
}
}
}
async submitPasscodeForm() {
if (
!this.formData.passcode ||
this.formData.passcode.length === 0
) {
return;
}
this.passcodeInput.blur();
this.onValue()(this.formData.passcode);
}
forgotPasscode() {
this.formData.showRecovery = true;
}
beginDeleteData() {
this.application.alertService.confirm({
text: "Are you sure you want to clear all local data?",
destructive: true,
onConfirm: async () => {
await this.application.signOut();
await this.application.restart();
}
});
}
}
export class LockScreen {
constructor() {
this.restrict = 'E';
this.template = template;
this.controller = LockScreenCtrl;
this.controllerAs = 'ctrl';
this.bindToController = true;
this.scope = {
onValue: '&',
puppet: '='
};
}
}

View File

@@ -1,8 +1,16 @@
import { ApplicationManager } from './../applicationManager';
import { WebDirective } from './../types';
import template from '%/root.pug';
import { WebApplication } from '@/application';
class RootCtrl {
private $timeout: ng.ITimeoutService
private applicationManager: ApplicationManager
public applications: WebApplication[] = []
/* @ngInject */
constructor($timeout, applicationManager) {
constructor($timeout: ng.ITimeoutService, applicationManager: ApplicationManager) {
this.$timeout = $timeout;
this.applicationManager = applicationManager;
this.applicationManager.addApplicationChangeObserver(() => {
@@ -17,8 +25,9 @@ class RootCtrl {
}
}
export class Root {
export class Root extends WebDirective {
constructor() {
super();
this.template = template;
this.controller = RootCtrl;
this.replace = true;

View File

@@ -1,5 +1,6 @@
import { WebApplication } from './application';
import { SNAlertService } from "../../../../snjs/dist/@types";
import { RawPayload } from '../../../../snjs/dist/@types/protocol/payloads/generator';
const DB_NAME = 'standardnotes';
const STORE_NAME = 'items';
@@ -105,7 +106,7 @@ export class Database {
});
}
public async getAllPayloads() {
public async getAllPayloads(): Promise<any[]> {
const db = (await this.openDatabase())!;
return new Promise((resolve) => {
const objectStore =
@@ -126,11 +127,11 @@ export class Database {
});
}
public async savePayload(payload: any) {
public async savePayload(payload: any): Promise<void> {
return this.savePayloads([payload]);
}
public async savePayloads(payloads: any[]) {
public async savePayloads(payloads: any[]): Promise<void> {
if (payloads.length === 0) {
return;
}
@@ -157,8 +158,8 @@ export class Database {
});
}
private putItems(objectStore: IDBObjectStore, items: any[]) {
return Promise.all(items.map((item) => {
private async putItems(objectStore: IDBObjectStore, items: any[]): Promise<void> {
await Promise.all(items.map((item) => {
return new Promise((resolve) => {
const request = objectStore.put(item);
request.onerror = resolve;
@@ -167,19 +168,21 @@ export class Database {
}));
}
public async deletePayload(uuid: string) {
public async deletePayload(uuid: string): Promise<void> {
const db = (await this.openDatabase())!;
return new Promise((resolve, reject) => {
const request =
db.transaction(STORE_NAME, READ_WRITE)
.objectStore(STORE_NAME)
.delete(uuid);
request.onsuccess = resolve;
request.onsuccess = () => {
resolve();
};
request.onerror = reject;
});
}
public async clearAllPayloads() {
public async clearAllPayloads(): Promise<void> {
const deleteRequest = window.indexedDB.deleteDatabase(DB_NAME);
return new Promise((resolve, reject) => {
deleteRequest.onerror = () => {
@@ -200,7 +203,7 @@ export class Database {
this.alertService!.alert(message);
}
private showGenericError(error: {code: number, name: string}) {
private showGenericError(error: { code: number, name: string }) {
const message =
`Unable to save changes locally due to an unknown system issue. ` +
`Issue Code: ${error.code} Issue Name: ${error.name}.`;

View File

@@ -1,64 +0,0 @@
import _ from 'lodash';
export class StatusManager {
constructor() {
this.statuses = [];
this.observers = [];
}
statusFromString(string) {
return {string: string};
}
replaceStatusWithString(status, string) {
this.removeStatus(status);
return this.addStatusFromString(string);
}
addStatusFromString(string) {
return this.addStatus(this.statusFromString(string));
}
addStatus(status) {
if(typeof status !== "object") {
console.error("Attempting to set non-object status", status);
return;
}
this.statuses.push(status);
this.notifyObservers();
return status;
}
removeStatus(status) {
_.pull(this.statuses, status);
this.notifyObservers();
return null;
}
getStatusString() {
let result = "";
this.statuses.forEach((status, index) => {
if(index > 0) {
result += " ";
}
result += status.string;
});
return result;
}
notifyObservers() {
for(const observer of this.observers) {
observer(this.getStatusString());
}
}
addStatusObserver(callback) {
this.observers.push(callback);
}
removeStatusObserver(callback) {
_.pull(this.statuses, callback);
}
}

View File

@@ -0,0 +1,60 @@
import { removeFromArray } from 'snjs';
import { FooterStatus } from './../types';
type StatusCallback = (string: string) => void
export class StatusManager {
private statuses: FooterStatus[] = []
private observers: StatusCallback[] = []
statusFromString(string: string) {
return {string: string};
}
replaceStatusWithString(status: FooterStatus, string: string) {
this.removeStatus(status);
return this.addStatusFromString(string);
}
addStatusFromString(string: string) {
return this.addStatus(this.statusFromString(string));
}
addStatus(status: FooterStatus) {
this.statuses.push(status);
this.notifyObservers();
return status;
}
removeStatus(status: FooterStatus) {
removeFromArray(this.statuses, status);
this.notifyObservers();
return undefined;
}
getStatusString() {
let result = '';
this.statuses.forEach((status, index) => {
if(index > 0) {
result += ' ';
}
result += status.string;
});
return result;
}
notifyObservers() {
for(const observer of this.observers) {
observer(this.getStatusString());
}
}
addStatusObserver(callback: StatusCallback) {
this.observers.push(callback);
return () => {
removeFromArray(this.observers, callback);
}
}
}

View File

@@ -1,3 +1,4 @@
import { SNComponent } from 'snjs';
export class WebDirective implements ng.IDirective {
controller?: string | ng.Injectable<ng.IControllerConstructor>;
controllerAs?: string;
@@ -18,6 +19,17 @@ export interface PasswordWizardScope extends Partial<ng.IScope> {
application: any
}
export interface PermissionsModalScope extends Partial<ng.IScope> {
application: any
component: SNComponent
permissionsString: string
callback: (approved: boolean) => void
}
export interface ModalComponentScope extends Partial<ng.IScope> {
component: SNComponent
}
export type PanelPuppet = {
onReady?: () => void
ready?: boolean
@@ -25,4 +37,8 @@ export type PanelPuppet = {
setLeft?: (left: number) => void
isCollapsed?: () => boolean
flash?: () => void
}
export type FooterStatus = {
string: string
}

View File

@@ -8,10 +8,10 @@
)
.sk-app-bar-item-column
.sk-circle.small(
ng-class="ctrl.error ? 'danger' : (ctrl.user ? 'info' : 'neutral')"
ng-class="ctrl.hasError ? 'danger' : (ctrl.user ? 'info' : 'neutral')"
)
.sk-app-bar-item-column
.sk-label.title(ng-class='{red: ctrl.error}') Account
.sk-label.title(ng-class='{red: ctrl.hasError}') Account
account-menu(
close-function='ctrl.closeAccountMenu()',
ng-click='$event.stopPropagation()',
@@ -31,7 +31,7 @@
.sk-label {{room.name}}
component-modal(
component='room',
ng-if='room.showRoom',
ng-if='ctrl.roomShowState[room.uuid]',
on-dismiss='ctrl.onRoomDismiss()',
application='ctrl.application'
)