Remove dummy concept in favor of editor group and editors
This commit is contained in:
@@ -5,18 +5,17 @@ declare const __VERSION__: string
|
||||
import angular from 'angular';
|
||||
import { configRoutes } from './routes';
|
||||
|
||||
import {
|
||||
ApplicationManager
|
||||
} from './applicationManager';
|
||||
import { ApplicationGroup } from './ui_models/application_group';
|
||||
|
||||
import {
|
||||
Root,
|
||||
ApplicationGroupView,
|
||||
ApplicationView,
|
||||
TagsPanel,
|
||||
NotesPanel,
|
||||
EditorPanel,
|
||||
Footer
|
||||
} from './controllers';
|
||||
EditorGroupView,
|
||||
EditorView,
|
||||
TagsView,
|
||||
NotesView,
|
||||
FooterView
|
||||
} from '@/views';
|
||||
|
||||
import {
|
||||
autofocus,
|
||||
@@ -62,13 +61,13 @@ angular
|
||||
// Controllers
|
||||
angular
|
||||
.module('app')
|
||||
.directive('root', () => new Root())
|
||||
.directive('applicationGroupView', () => new ApplicationGroupView())
|
||||
.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('editorGroupView', () => new EditorGroupView())
|
||||
.directive('editorView', () => new EditorView())
|
||||
.directive('tagsView', () => new TagsView())
|
||||
.directive('notesView', () => new NotesView())
|
||||
.directive('footerView', () => new FooterView())
|
||||
|
||||
// Directives - Functional
|
||||
angular
|
||||
@@ -78,9 +77,7 @@ angular
|
||||
.directive('delayHide', delayHide)
|
||||
.directive('elemReady', elemReady)
|
||||
.directive('fileChange', fileChange)
|
||||
.directive('infiniteScroll', [
|
||||
infiniteScroll
|
||||
])
|
||||
.directive('infiniteScroll', [infiniteScroll])
|
||||
.directive('lowercase', lowercase)
|
||||
.directive('selectOnClick', ['$window', selectOnClick])
|
||||
.directive('snEnter', snEnter);
|
||||
@@ -93,11 +90,6 @@ angular
|
||||
.directive('challengeModal', () => new ChallengeModal())
|
||||
.directive('componentModal', () => new ComponentModal())
|
||||
.directive('componentView', () => new ComponentView())
|
||||
// .directive(
|
||||
// 'componentView',
|
||||
// ($rootScope, componentManager, desktopManager, $timeout) =>
|
||||
// new ComponentView($rootScope, componentManager, desktopManager, $timeout)
|
||||
// )
|
||||
.directive('editorMenu', () => new EditorMenu())
|
||||
.directive('inputModal', () => new InputModal())
|
||||
.directive('menuRow', () => new MenuRow())
|
||||
@@ -116,4 +108,4 @@ angular
|
||||
.filter('trusted', ['$sce', trusted]);
|
||||
|
||||
// Services
|
||||
angular.module('app').service('applicationManager', ApplicationManager);
|
||||
angular.module('app').service('mainApplicationGroup', ApplicationGroup);
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
export { PureCtrl } from './abstract/pure_ctrl';
|
||||
export { EditorPanel } from './editor';
|
||||
export { Footer } from './footer';
|
||||
export { NotesPanel } from './notes/notes';
|
||||
export { TagsPanel } from './tags';
|
||||
export { Root } from './root';
|
||||
export { ApplicationView } from './applicationView';
|
||||
@@ -1,37 +0,0 @@
|
||||
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: ng.ITimeoutService, applicationManager: ApplicationManager) {
|
||||
this.$timeout = $timeout;
|
||||
this.applicationManager = applicationManager;
|
||||
this.applicationManager.addApplicationChangeObserver(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.$timeout(() => {
|
||||
this.applications = this.applicationManager.getApplications();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class Root extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.template = template;
|
||||
this.controller = RootCtrl;
|
||||
this.replace = true;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,4 @@
|
||||
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';
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
import { debounce } from '@/utils';
|
||||
/* @ngInject */
|
||||
export function infiniteScroll() {
|
||||
return {
|
||||
link: function (scope: ng.IScope, elem: JQLite, attrs: any) {
|
||||
const scopeAny = scope as any;
|
||||
const offset = parseInt(attrs.threshold) || 0;
|
||||
const e = elem[0];
|
||||
const element = elem[0];
|
||||
scopeAny.paginate = debounce(() => {
|
||||
scope.$apply(attrs.infiniteScroll);
|
||||
}, 100);
|
||||
scopeAny.onScroll = () => {
|
||||
if (
|
||||
scope.$eval(attrs.canLoad) &&
|
||||
e.scrollTop + e.offsetHeight >= e.scrollHeight - offset
|
||||
element.scrollTop + element.offsetHeight >= element.scrollHeight - offset
|
||||
) {
|
||||
scope.$apply(attrs.infiniteScroll);
|
||||
scopeAny.paginate();
|
||||
}
|
||||
};
|
||||
elem.on('scroll', scopeAny.onScroll);
|
||||
|
||||
@@ -2,7 +2,7 @@ import { WebDirective } from './../../types';
|
||||
import { isDesktopApplication, isNullOrUndefined } from '@/utils';
|
||||
import template from '%/directives/account-menu.pug';
|
||||
import { ProtectedAction, ContentType } from 'snjs';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import {
|
||||
STRING_ACCOUNT_MENU_UNCHECK_MERGE,
|
||||
STRING_SIGN_OUT_CONFIRMATION,
|
||||
@@ -59,7 +59,7 @@ type AccountMenuState = {
|
||||
importData: any
|
||||
}
|
||||
|
||||
class AccountMenuCtrl extends PureCtrl {
|
||||
class AccountMenuCtrl extends PureViewCtrl {
|
||||
|
||||
public appVersion: string
|
||||
private syncStatus?: SyncOpStatus
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { WebDirective } from './../../types';
|
||||
import template from '%/directives/actions-menu.pug';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { SNItem, Action, SNActionsExtension } from '@/../../../../snjs/dist/@types';
|
||||
import { ActionResponse } from '@/../../../../snjs/dist/@types/services/actions_service';
|
||||
|
||||
@@ -10,7 +10,7 @@ type ActionsMenuScope = {
|
||||
item: SNItem
|
||||
}
|
||||
|
||||
class ActionsMenuCtrl extends PureCtrl implements ActionsMenuScope {
|
||||
class ActionsMenuCtrl extends PureViewCtrl implements ActionsMenuScope {
|
||||
|
||||
application!: WebApplication
|
||||
item!: SNItem
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WebDirective } from './../../types';
|
||||
import { WebApplication } from './../../application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import template from '%/directives/challenge-modal.pug';
|
||||
import {
|
||||
ChallengeType,
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Challenge,
|
||||
ChallengeOrchestrator
|
||||
} from 'snjs';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
|
||||
type InputValue = {
|
||||
value: string
|
||||
@@ -28,7 +28,7 @@ type ChallengeModalState = {
|
||||
processing: boolean
|
||||
}
|
||||
|
||||
class ChallengeModalCtrl extends PureCtrl implements ChallengeModalScope {
|
||||
class ChallengeModalCtrl extends PureViewCtrl implements ChallengeModalScope {
|
||||
private $element: JQLite
|
||||
private processingTypes: ChallengeType[] = []
|
||||
application!: WebApplication
|
||||
@@ -159,7 +159,8 @@ export class ChallengeModal extends WebDirective {
|
||||
this.template = template;
|
||||
this.controller = ChallengeModalCtrl;
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = {
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
challenge: '=',
|
||||
orchestrator: '=',
|
||||
application: '='
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from './../../application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { SNComponent } from 'snjs';
|
||||
import { WebDirective } from './../../types';
|
||||
import template from '%/directives/component-modal.pug';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { SNComponent } from 'snjs';
|
||||
import { WebDirective } from './../../types';
|
||||
import template from '%/directives/component-view.pug';
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { WebDirective } from './../../types';
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { SNComponent, SNItem, ComponentArea } from 'snjs';
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import template from '%/directives/editor-menu.pug';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { ComponentMutator } from '@/../../../../snjs/dist/@types/models';
|
||||
|
||||
interface EditorMenuScope {
|
||||
@@ -13,7 +13,7 @@ interface EditorMenuScope {
|
||||
application: WebApplication
|
||||
}
|
||||
|
||||
class EditorMenuCtrl extends PureCtrl implements EditorMenuScope {
|
||||
class EditorMenuCtrl extends PureViewCtrl implements EditorMenuScope {
|
||||
|
||||
callback!: (component: SNComponent) => void
|
||||
selectedEditor!: SNComponent
|
||||
|
||||
@@ -84,7 +84,7 @@ class PanelResizerCtrl implements PanelResizerScope {
|
||||
this.$timeout = $timeout;
|
||||
|
||||
/** To allow for registering events */
|
||||
this.handleResize = this.handleResize.bind(this);
|
||||
this.handleResize = debounce(this.handleResize.bind(this), 250);
|
||||
this.onMouseMove = this.onMouseMove.bind(this);
|
||||
this.onMouseUp = this.onMouseUp.bind(this);
|
||||
this.onMouseDown = this.onMouseDown.bind(this);
|
||||
@@ -163,13 +163,11 @@ class PanelResizerCtrl implements PanelResizerScope {
|
||||
}
|
||||
|
||||
handleResize() {
|
||||
debounce(() => {
|
||||
this.reloadDefaultValues();
|
||||
this.handleWidthEvent();
|
||||
this.$timeout(() => {
|
||||
this.finishSettingWidth();
|
||||
});
|
||||
}, 250);
|
||||
this.reloadDefaultValues();
|
||||
this.handleWidthEvent();
|
||||
this.$timeout(() => {
|
||||
this.finishSettingWidth();
|
||||
});
|
||||
}
|
||||
|
||||
getParentRect() {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { WebApplication } from './../../application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { PasswordWizardScope, PasswordWizardType, WebDirective } from './../../types';
|
||||
import template from '%/directives/password-wizard.pug';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
|
||||
const DEFAULT_CONTINUE_TITLE = "Continue";
|
||||
const Steps = {
|
||||
@@ -9,7 +9,7 @@ const Steps = {
|
||||
FinishStep: 2
|
||||
};
|
||||
|
||||
class PasswordWizardCtrl extends PureCtrl implements PasswordWizardScope {
|
||||
class PasswordWizardCtrl extends PureViewCtrl implements PasswordWizardScope {
|
||||
$element: JQLite
|
||||
application!: WebApplication
|
||||
type!: PasswordWizardType
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WebDirective } from './../../types';
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { ProtectedAction, PrivilegeCredential, PrivilegeSessionLength } from 'snjs';
|
||||
import template from '%/directives/privileges-auth-modal.pug';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { WebDirective } from './../../types';
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import template from '%/directives/privileges-management-modal.pug';
|
||||
import { PrivilegeCredential, ProtectedAction, SNPrivileges, PrivilegeSessionLength } from 'snjs';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { PrivilegeMutator } from '@/../../../../snjs/dist/@types/models';
|
||||
|
||||
type DisplayInfo = {
|
||||
@@ -10,7 +10,7 @@ type DisplayInfo = {
|
||||
prompt: string
|
||||
}
|
||||
|
||||
class PrivilegesManagementModalCtrl extends PureCtrl {
|
||||
class PrivilegesManagementModalCtrl extends PureViewCtrl {
|
||||
|
||||
hasPasscode = false
|
||||
hasAccount = false
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { WebDirective } from './../../types';
|
||||
import {
|
||||
ContentType,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { WebDirective } from './../../types';
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import template from '%/directives/session-history-menu.pug';
|
||||
import { SNItem, ItemHistoryEntry, ItemHistory } from '@/../../../../snjs/dist/@types';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { WebDirective } from './../../types';
|
||||
import template from '%/directives/sync-resolution-menu.pug';
|
||||
|
||||
|
||||
@@ -4,8 +4,8 @@ import { SKAlert } from 'sn-stylekit';
|
||||
|
||||
export class AlertService extends SNAlertService {
|
||||
async alert(
|
||||
title: string,
|
||||
text: string,
|
||||
title: string,
|
||||
closeButtonText = 'OK',
|
||||
onClose: () => void
|
||||
) {
|
||||
@@ -28,8 +28,8 @@ export class AlertService extends SNAlertService {
|
||||
}
|
||||
|
||||
async confirm(
|
||||
title: string,
|
||||
text: string,
|
||||
title: string,
|
||||
confirmButtonText = 'Confirm',
|
||||
cancelButtonText = 'Cancel',
|
||||
onConfirm: () => void,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { EncryptionIntent, ProtectedAction, SNItem, ContentType, SNNote } from 'snjs';
|
||||
|
||||
export class ArchiveManager {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { SNComponent, PurePayload, ComponentMutator, AppDataField } from 'snjs';
|
||||
/* eslint-disable camelcase */
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
// An interface used by the Desktop app to interact with SN
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import { EncryptionIntent, ApplicationService, ApplicationEvent, removeFromArray } from 'snjs';
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from './../application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import { AppStateEvent } from '@/services/state';
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import {
|
||||
SNPredicate,
|
||||
ContentType,
|
||||
|
||||
@@ -1,11 +1,20 @@
|
||||
import { WebApplication } from './../application';
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import pull from 'lodash/pull';
|
||||
import { ProtectedAction, ApplicationEvent, SNTag, SNNote, SNUserPrefs, ContentType, SNSmartTag } from 'snjs';
|
||||
import {
|
||||
ProtectedAction,
|
||||
ApplicationEvent,
|
||||
SNTag,
|
||||
SNNote,
|
||||
SNUserPrefs,
|
||||
ContentType,
|
||||
SNSmartTag
|
||||
} from 'snjs';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { Editor } from '@/ui_models/editor';
|
||||
|
||||
export enum AppStateEvent {
|
||||
TagChanged = 1,
|
||||
NoteChanged = 2,
|
||||
ActiveEditorChanged = 2,
|
||||
PreferencesChanged = 3,
|
||||
PanelResized = 4,
|
||||
EditorFocused = 5,
|
||||
@@ -34,8 +43,8 @@ export class AppState {
|
||||
rootScopeCleanup2: any
|
||||
onVisibilityChange: any
|
||||
selectedTag?: SNTag
|
||||
selectedNote?: SNNote
|
||||
userPreferences?: SNUserPrefs
|
||||
multiEditorEnabled = false
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
@@ -74,16 +83,90 @@ export class AppState {
|
||||
this.onVisibilityChange = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new editor if one doesn't exist. If one does, we'll replace the
|
||||
* editor's note with an empty one.
|
||||
*/
|
||||
createEditor(title?: string) {
|
||||
const activeEditor = this.getActiveEditor();
|
||||
if (!activeEditor || this.multiEditorEnabled) {
|
||||
this.application.editorGroup.createEditor(title);
|
||||
} else {
|
||||
activeEditor.reset(title);
|
||||
}
|
||||
}
|
||||
|
||||
async openEditor(noteUuid: string) {
|
||||
const note = this.application.findItem(noteUuid) as SNNote;
|
||||
const run = async () => {
|
||||
const activeEditor = this.getActiveEditor();
|
||||
if (!activeEditor || this.multiEditorEnabled) {
|
||||
this.application.editorGroup.createEditor(noteUuid);
|
||||
} else {
|
||||
activeEditor.setNote(note);
|
||||
}
|
||||
await this.notifyEvent(AppStateEvent.ActiveEditorChanged);
|
||||
};
|
||||
if (note && note.safeContent.protected &&
|
||||
await this.application.privilegesService!.actionRequiresPrivilege(
|
||||
ProtectedAction.ViewProtectedNotes
|
||||
)) {
|
||||
return new Promise((resolve) => {
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedAction.ViewProtectedNotes,
|
||||
() => {
|
||||
run().then(resolve);
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return run();
|
||||
}
|
||||
}
|
||||
|
||||
getActiveEditor() {
|
||||
return this.application.editorGroup.editors[0];
|
||||
}
|
||||
|
||||
getEditors() {
|
||||
return this.application.editorGroup.editors;
|
||||
}
|
||||
|
||||
closeEditor(editor: Editor) {
|
||||
this.application.editorGroup.closeEditor(editor);
|
||||
}
|
||||
|
||||
closeActiveEditor() {
|
||||
this.application.editorGroup.closeActiveEditor();
|
||||
}
|
||||
|
||||
closeAllEditors() {
|
||||
this.application.editorGroup.closeAllEditors();
|
||||
}
|
||||
|
||||
editorForNote(note: SNNote) {
|
||||
for (const editor of this.getEditors()) {
|
||||
if (editor.note.uuid === note.uuid) {
|
||||
return editor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
streamNotesAndTags() {
|
||||
this.application!.streamItems(
|
||||
[ContentType.Note, ContentType.Tag],
|
||||
async (items) => {
|
||||
if(this.selectedNote) {
|
||||
const matchingNote = items.find((candidate) => candidate.uuid === this.selectedNote!.uuid);
|
||||
if(matchingNote) {
|
||||
this.selectedNote = matchingNote as SNNote;
|
||||
/** Close any editors for deleted notes */
|
||||
const notes = items.filter((candidate) => candidate.content_type === ContentType.Note) as SNNote[];
|
||||
for (const note of notes) {
|
||||
if (note.deleted) {
|
||||
const editor = this.editorForNote(note);
|
||||
if (editor) {
|
||||
this.closeEditor(editor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.selectedTag) {
|
||||
const matchingTag = items.find((candidate) => candidate.uuid === this.selectedTag!.uuid);
|
||||
if (matchingTag) {
|
||||
@@ -161,32 +244,6 @@ export class AppState {
|
||||
);
|
||||
}
|
||||
|
||||
async setSelectedNote(note?: SNNote) {
|
||||
const run = async () => {
|
||||
const previousNote = this.selectedNote;
|
||||
this.selectedNote = note;
|
||||
await this.notifyEvent(
|
||||
AppStateEvent.NoteChanged,
|
||||
{ previousNote: previousNote }
|
||||
);
|
||||
};
|
||||
if (note && note.safeContent.protected &&
|
||||
await this.application.privilegesService!.actionRequiresPrivilege(
|
||||
ProtectedAction.ViewProtectedNotes
|
||||
)) {
|
||||
return new Promise((resolve) => {
|
||||
this.application.presentPrivilegesModal(
|
||||
ProtectedAction.ViewProtectedNotes,
|
||||
() => {
|
||||
run().then(resolve);
|
||||
}
|
||||
);
|
||||
});
|
||||
} else {
|
||||
return run();
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the tags that are referncing this note */
|
||||
getNoteTags(note: SNNote) {
|
||||
return this.application.referencingForItem(note).filter((ref) => {
|
||||
@@ -196,11 +253,11 @@ export class AppState {
|
||||
|
||||
/** Returns the notes this tag references */
|
||||
getTagNotes(tag: SNTag) {
|
||||
if(tag.isSmartTag()) {
|
||||
if (tag.isSmartTag()) {
|
||||
return this.application.notesMatchingSmartTag(tag as SNSmartTag);
|
||||
} else {
|
||||
return this.application.referencesForItem(tag).filter((ref) => {
|
||||
return ref.content_type === tag.content_type;
|
||||
return ref.content_type === ContentType.Note;
|
||||
}) as SNNote[]
|
||||
}
|
||||
}
|
||||
@@ -209,10 +266,6 @@ export class AppState {
|
||||
return this.selectedTag;
|
||||
}
|
||||
|
||||
getSelectedNote() {
|
||||
return this.selectedNote;
|
||||
}
|
||||
|
||||
setUserPreferences(preferences: SNUserPrefs) {
|
||||
this.userPreferences = preferences;
|
||||
this.notifyEvent(
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { removeFromArray } from 'snjs';
|
||||
import { FooterStatus } from './../types';
|
||||
import { FooterStatus } from '@/types';
|
||||
|
||||
type StatusCallback = (string: string) => void
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
StorageValueModes,
|
||||
|
||||
@@ -14,7 +14,9 @@
|
||||
"paths": {
|
||||
"%/*": ["../templates/*"],
|
||||
"@/*": ["./*"],
|
||||
"@Controllers/*": ["./controllers/*"]
|
||||
"@Controllers/*": ["./controllers/*"],
|
||||
"@Views/*": ["./views/*"],
|
||||
"@Services/*": ["./services/*"],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { InputModalScope } from './directives/views/inputModal';
|
||||
import { PasswordWizardType, PasswordWizardScope } from './types';
|
||||
import { EditorGroup } from '@/ui_models/editor_group';
|
||||
import { InputModalScope } from '@/directives/views/inputModal';
|
||||
import { PasswordWizardType, PasswordWizardScope } from '@/types';
|
||||
import {
|
||||
Environment,
|
||||
SNApplication,
|
||||
@@ -23,7 +24,7 @@ import {
|
||||
ThemeManager,
|
||||
PreferencesManager,
|
||||
KeyboardManager
|
||||
} from './services';
|
||||
} from '@/services';
|
||||
|
||||
type WebServices = {
|
||||
appState: AppState
|
||||
@@ -44,6 +45,7 @@ export class WebApplication extends SNApplication {
|
||||
private onDeinit?: (app: WebApplication) => void
|
||||
private webServices!: WebServices
|
||||
private currentAuthenticationElement?: JQLite
|
||||
public editorGroup: EditorGroup
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
@@ -71,6 +73,7 @@ export class WebApplication extends SNApplication {
|
||||
this.scope = scope;
|
||||
this.onDeinit = onDeinit;
|
||||
deviceInterface.setApplication(this);
|
||||
this.editorGroup = new EditorGroup(this);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
@@ -86,6 +89,7 @@ export class WebApplication extends SNApplication {
|
||||
this.onDeinit!(this);
|
||||
this.onDeinit = undefined;
|
||||
this.$compile = undefined;
|
||||
this.editorGroup.deinit();
|
||||
(this.scope! as any).application = undefined;
|
||||
this.scope!.$destroy();
|
||||
this.scope = undefined;
|
||||
@@ -10,11 +10,11 @@ import {
|
||||
StatusManager,
|
||||
ThemeManager,
|
||||
AppState
|
||||
} from './services';
|
||||
} from '@/services';
|
||||
|
||||
type AppManagerChangeCallback = () => void
|
||||
|
||||
export class ApplicationManager {
|
||||
export class ApplicationGroup {
|
||||
|
||||
$compile: ng.ICompileService
|
||||
$rootScope: ng.IRootScopeService
|
||||
104
app/assets/javascripts/ui_models/editor.ts
Normal file
104
app/assets/javascripts/ui_models/editor.ts
Normal file
@@ -0,0 +1,104 @@
|
||||
import { SNNote, ContentType, PayloadSource } from 'snjs';
|
||||
import { WebApplication } from './application';
|
||||
|
||||
export class Editor {
|
||||
|
||||
public note!: SNNote
|
||||
private application: WebApplication
|
||||
private _onNoteChange?: () => void
|
||||
private _onNoteValueChange?: (note: SNNote, source?: PayloadSource) => void
|
||||
private removeStreamObserver: () => void
|
||||
public isTemplateNote = true
|
||||
|
||||
constructor(
|
||||
application: WebApplication,
|
||||
noteUuid?: string,
|
||||
noteTitle?: string
|
||||
) {
|
||||
this.application = application;
|
||||
if (noteUuid) {
|
||||
this.note = application.findItem(noteUuid) as SNNote;
|
||||
} else {
|
||||
this.reset(noteTitle);
|
||||
}
|
||||
|
||||
this.removeStreamObserver = this.application.streamItems(
|
||||
ContentType.Note,
|
||||
async (items, source) => {
|
||||
await this.handleNoteStream(items as SNNote[], source);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private async handleNoteStream(notes: SNNote[], source?: PayloadSource) {
|
||||
/** Update our note object reference whenever it changes */
|
||||
const matchingNote = notes.find((item) => {
|
||||
return item.uuid === this.note.uuid;
|
||||
}) as SNNote;
|
||||
if (matchingNote) {
|
||||
this.isTemplateNote = false;
|
||||
this.note = matchingNote;
|
||||
this._onNoteValueChange!(matchingNote, source);
|
||||
}
|
||||
}
|
||||
|
||||
async insertTemplatedNote() {
|
||||
return this.application.insertItem(this.note);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverts the editor to a blank state, removing any existing note from view,
|
||||
* and creating a placeholder note.
|
||||
*/
|
||||
async reset(noteTitle?: string) {
|
||||
const note = await this.application.createTemplateItem(
|
||||
ContentType.Note,
|
||||
{
|
||||
text: '',
|
||||
title: noteTitle || '',
|
||||
references: []
|
||||
}
|
||||
);
|
||||
this.isTemplateNote = true;
|
||||
this.setNote(note as SNNote);
|
||||
}
|
||||
|
||||
deinit() {
|
||||
this.removeStreamObserver();
|
||||
(this.removeStreamObserver as any) = undefined;
|
||||
this._onNoteChange = undefined;
|
||||
(this.application as any) = undefined;
|
||||
this._onNoteChange = undefined;
|
||||
this._onNoteValueChange = undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Register to be notified when the editor's note changes.
|
||||
*/
|
||||
public onNoteChange(onNoteChange: () => void) {
|
||||
this._onNoteChange = onNoteChange;
|
||||
if (this.note) {
|
||||
onNoteChange();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register to be notified when the editor's note's values change
|
||||
* (and thus a new object reference is created)
|
||||
*/
|
||||
public onNoteValueChange(
|
||||
onNoteValueChange: (note: SNNote, source?: PayloadSource) => void
|
||||
) {
|
||||
this._onNoteValueChange = onNoteValueChange;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the editor contents by setting its note.
|
||||
*/
|
||||
public setNote(note: SNNote) {
|
||||
this.note = note;
|
||||
if (this._onNoteChange) {
|
||||
this._onNoteChange();
|
||||
}
|
||||
}
|
||||
}
|
||||
69
app/assets/javascripts/ui_models/editor_group.ts
Normal file
69
app/assets/javascripts/ui_models/editor_group.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { removeFromArray } from 'snjs';
|
||||
import { Editor } from './editor';
|
||||
import { WebApplication } from './application';
|
||||
|
||||
type EditorGroupChangeCallback = () => void
|
||||
|
||||
export class EditorGroup {
|
||||
|
||||
public editors: Editor[] = []
|
||||
private application: WebApplication
|
||||
changeObservers: EditorGroupChangeCallback[] = []
|
||||
|
||||
constructor(application: WebApplication) {
|
||||
this.application = application;
|
||||
}
|
||||
|
||||
public deinit() {
|
||||
(this.application as any) = undefined;
|
||||
for (const editor of this.editors) {
|
||||
this.deleteEditor(editor);
|
||||
}
|
||||
}
|
||||
|
||||
createEditor(noteUuid?: string, noteTitle?: string) {
|
||||
const editor = new Editor(this.application, noteUuid, noteTitle);
|
||||
this.editors.push(editor);
|
||||
this.notifyObservers();
|
||||
}
|
||||
|
||||
deleteEditor(editor: Editor) {
|
||||
editor.deinit();
|
||||
removeFromArray(this.editors, editor);
|
||||
}
|
||||
|
||||
closeEditor(editor: Editor) {
|
||||
this.deleteEditor(editor);
|
||||
this.notifyObservers();
|
||||
}
|
||||
|
||||
closeActiveEditor() {
|
||||
this.deleteEditor(this.editors[0]);
|
||||
}
|
||||
|
||||
closeAllEditors() {
|
||||
for(const editor of this.editors) {
|
||||
this.deleteEditor(editor);
|
||||
}
|
||||
}
|
||||
|
||||
get activeEditor() {
|
||||
return this.editors[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies observer when the active editor has changed.
|
||||
*/
|
||||
public addChangeObserver(callback: EditorGroupChangeCallback) {
|
||||
this.changeObservers.push(callback);
|
||||
if (this.activeEditor) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
|
||||
private notifyObservers() {
|
||||
for (const observer of this.changeObservers) {
|
||||
observer();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import { AppStateEvent } from '@/services/state';
|
||||
import { WebApplication } from './../../application';
|
||||
import { ApplicationEvent } from 'snjs';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
|
||||
export type CtrlState = Partial<Record<string, any>>
|
||||
export type CtrlProps = Partial<Record<string, any>>
|
||||
|
||||
export class PureCtrl {
|
||||
export class PureViewCtrl {
|
||||
$timeout: ng.ITimeoutService
|
||||
/** Passed through templates */
|
||||
application?: WebApplication
|
||||
@@ -5,11 +5,13 @@
|
||||
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')
|
||||
tags-view(application='self.application')
|
||||
notes-view(application='self.application')
|
||||
editor-group-view(
|
||||
application='self.application'
|
||||
)
|
||||
|
||||
footer(
|
||||
footer-view(
|
||||
ng-if='!self.state.needsUnlock && self.state.ready'
|
||||
application='self.application'
|
||||
)
|
||||
@@ -1,21 +1,21 @@
|
||||
import { PanelPuppet, WebDirective, PermissionsModalScope, ModalComponentScope } from './../types';
|
||||
import { WebDirective, PermissionsModalScope, ModalComponentScope } from '@/types';
|
||||
import { getPlatformString } from '@/utils';
|
||||
import template from '%/application-view.pug';
|
||||
import template from './application-view.pug';
|
||||
import { AppStateEvent } from '@/services/state';
|
||||
import { ApplicationEvent, SNComponent } from 'snjs';
|
||||
import angular from 'angular';
|
||||
import {
|
||||
PANEL_NAME_NOTES,
|
||||
PANEL_NAME_TAGS
|
||||
} from '@/controllers/constants';
|
||||
} from '@/views/constants';
|
||||
import {
|
||||
STRING_SESSION_EXPIRED,
|
||||
STRING_DEFAULT_FILE_ERROR
|
||||
} from '@/strings';
|
||||
import { PureCtrl } from './abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { PermissionDialog } from '@/../../../../snjs/dist/@types/services/component_manager';
|
||||
|
||||
class ApplicationViewCtrl extends PureCtrl {
|
||||
class ApplicationViewCtrl extends PureViewCtrl {
|
||||
private $compile?: ng.ICompileService
|
||||
private $location?: ng.ILocationService
|
||||
private $rootScope?: ng.IRootScopeService
|
||||
@@ -47,7 +47,7 @@ class ApplicationViewCtrl extends PureCtrl {
|
||||
this.presentPermissionsDialog = this.presentPermissionsDialog.bind(this);
|
||||
this.addDragDropHandlers();
|
||||
}
|
||||
|
||||
|
||||
deinit() {
|
||||
this.$location = undefined;
|
||||
this.$rootScope = undefined;
|
||||
@@ -61,7 +61,7 @@ class ApplicationViewCtrl extends PureCtrl {
|
||||
(this.presentPermissionsDialog as any) = undefined;
|
||||
super.deinit();
|
||||
}
|
||||
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
this.loadApplication();
|
||||
@@ -226,7 +226,7 @@ class ApplicationViewCtrl extends PureCtrl {
|
||||
scope.component = dialog.component;
|
||||
scope.callback = dialog.callback;
|
||||
const el = this.$compile!(
|
||||
"<permissions-modal component='component' permissions-string='permissionsString'"
|
||||
"<permissions-modal component='component' permissions-string='permissionsString'"
|
||||
+ " callback='callback' class='sk-modal'></permissions-modal>"
|
||||
)(scope as any);
|
||||
angular.element(document.body).append(el);
|
||||
@@ -310,7 +310,8 @@ export class ApplicationView extends WebDirective {
|
||||
this.controller = ApplicationViewCtrl;
|
||||
this.replace = true;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = {
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { ApplicationGroup } from '@/ui_models/application_group';
|
||||
import { WebDirective } from '@/types';
|
||||
import template from './application-group-view.pug';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
|
||||
class ApplicationGroupViewCtrl {
|
||||
|
||||
private $timeout: ng.ITimeoutService
|
||||
private applicationGroup: ApplicationGroup
|
||||
public applications: WebApplication[] = []
|
||||
|
||||
/* @ngInject */
|
||||
constructor(
|
||||
$timeout: ng.ITimeoutService,
|
||||
mainApplicationGroup: ApplicationGroup
|
||||
) {
|
||||
this.$timeout = $timeout;
|
||||
this.applicationGroup = mainApplicationGroup;
|
||||
this.applicationGroup.addApplicationChangeObserver(() => {
|
||||
this.reload();
|
||||
});
|
||||
}
|
||||
|
||||
reload() {
|
||||
this.$timeout(() => {
|
||||
this.applications = this.applicationGroup.getApplications();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export class ApplicationGroupView extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.template = template;
|
||||
this.controller = ApplicationGroupViewCtrl;
|
||||
this.replace = true;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
}
|
||||
}
|
||||
@@ -13,7 +13,7 @@
|
||||
| {{self.lockText}}
|
||||
#editor-title-bar.section-title-bar(
|
||||
ng-class="{'locked' : self.noteLocked}",
|
||||
ng-show='self.state.note && !self.state.note.errorDecrypting'
|
||||
ng-show='self.note && !self.note.errorDecrypting'
|
||||
)
|
||||
.title
|
||||
input#note-title-editor.input(
|
||||
@@ -48,7 +48,7 @@
|
||||
spellcheck='false',
|
||||
type='text'
|
||||
)
|
||||
.sn-component(ng-if='self.state.note')
|
||||
.sn-component(ng-if='self.note')
|
||||
#editor-menu-bar.sk-app-bar.no-edges
|
||||
.left
|
||||
.sk-app-bar-item(
|
||||
@@ -65,12 +65,12 @@
|
||||
menu-row(
|
||||
action='self.selectedMenuItem(true); self.togglePin()',
|
||||
desc="'Pin or unpin a note from the top of your list'",
|
||||
label="self.state.note.pinned ? 'Unpin' : 'Pin'"
|
||||
label="self.note.pinned ? 'Unpin' : 'Pin'"
|
||||
)
|
||||
menu-row(
|
||||
action='self.selectedMenuItem(true); self.toggleArchiveNote()',
|
||||
desc="'Archive or unarchive a note from your Archived system tag'",
|
||||
label="self.state.note.archived ? 'Unarchive' : 'Archive'"
|
||||
label="self.note.archived ? 'Unarchive' : 'Archive'"
|
||||
)
|
||||
menu-row(
|
||||
action='self.selectedMenuItem(true); self.toggleLockNote()',
|
||||
@@ -81,11 +81,11 @@
|
||||
action='self.selectedMenuItem(true); self.toggleProtectNote()',
|
||||
desc=`'Protecting a note will require credentials to view
|
||||
it (Manage Privileges via Account menu)'`,
|
||||
label="self.state.note.protected ? 'Unprotect' : 'Protect'"
|
||||
label="self.note.protected ? 'Unprotect' : 'Protect'"
|
||||
)
|
||||
menu-row(
|
||||
action='self.selectedMenuItem(true); self.toggleNotePreview()',
|
||||
circle="self.state.note.hidePreview ? 'danger' : 'success'",
|
||||
circle="self.note.hidePreview ? 'danger' : 'success'",
|
||||
circle-align="'right'",
|
||||
desc="'Hide or unhide the note preview from the list of notes'",
|
||||
label="'Preview'"
|
||||
@@ -94,22 +94,22 @@
|
||||
action='self.selectedMenuItem(); self.deleteNote()',
|
||||
desc="'Send this note to the trash'",
|
||||
label="'Move to Trash'",
|
||||
ng-show='!self.state.altKeyDown && !self.state.note.trashed && !self.state.note.errorDecrypting',
|
||||
ng-show='!self.state.altKeyDown && !self.note.trashed && !self.note.errorDecrypting',
|
||||
stylekit-class="'warning'"
|
||||
)
|
||||
menu-row(
|
||||
action='self.selectedMenuItem(); self.deleteNotePermanantely()',
|
||||
desc="'Delete this note permanently from all your devices'",
|
||||
label="'Delete Permanently'",
|
||||
ng-show='!self.state.note.trashed && self.state.note.errorDecrypting',
|
||||
ng-show='!self.note.trashed && self.note.errorDecrypting',
|
||||
stylekit-class="'danger'"
|
||||
)
|
||||
div(ng-if='self.state.note.trashed || self.state.altKeyDown')
|
||||
div(ng-if='self.note.trashed || self.state.altKeyDown')
|
||||
menu-row(
|
||||
action='self.selectedMenuItem(true); self.restoreTrashedNote()',
|
||||
desc="'Undelete this note and restore it back into your notes'",
|
||||
label="'Restore'",
|
||||
ng-show='self.state.note.trashed',
|
||||
ng-show='self.note.trashed',
|
||||
stylekit-class="'info'"
|
||||
)
|
||||
menu-row(
|
||||
@@ -122,7 +122,7 @@
|
||||
action='self.selectedMenuItem(true); self.emptyTrash()',
|
||||
desc="'Permanently delete all notes in the trash'",
|
||||
label="'Empty Trash'",
|
||||
ng-show='self.state.note.trashed || !self.state.altKeyDown',
|
||||
ng-show='self.note.trashed || !self.state.altKeyDown',
|
||||
stylekit-class="'danger'",
|
||||
subtitle="self.getTrashCount() + ' notes in trash'"
|
||||
)
|
||||
@@ -164,7 +164,7 @@
|
||||
.sk-label Editor
|
||||
editor-menu(
|
||||
callback='self.editorMenuOnSelect()',
|
||||
current-item='self.state.note',
|
||||
current-item='self.note',
|
||||
ng-if='self.state.showEditorMenu',
|
||||
selected-editor='self.state.selectedEditor',
|
||||
application='self.application'
|
||||
@@ -177,7 +177,7 @@
|
||||
)
|
||||
.sk-label Actions
|
||||
actions-menu(
|
||||
item='self.state.note',
|
||||
item='self.note',
|
||||
ng-if='self.state.showExtensions',
|
||||
application='self.application'
|
||||
)
|
||||
@@ -188,12 +188,12 @@
|
||||
)
|
||||
.sk-label Session History
|
||||
session-history-menu(
|
||||
item='self.state.note',
|
||||
item='self.note',
|
||||
ng-if='self.state.showSessionHistory',
|
||||
application='self.application'
|
||||
)
|
||||
#editor-content.editor-content(
|
||||
ng-if='self.state.noteReady && !self.state.note.errorDecrypting'
|
||||
ng-if='self.state.noteReady && !self.note.errorDecrypting'
|
||||
)
|
||||
panel-resizer.left(
|
||||
control='self.leftPanelPuppet',
|
||||
@@ -231,11 +231,11 @@
|
||||
panel-id="'editor-content'",
|
||||
property="'right'"
|
||||
)
|
||||
.section(ng-show='self.state.note.errorDecrypting')
|
||||
.section(ng-show='self.note.errorDecrypting')
|
||||
p.medium-padding(style='padding-top: 0 !important;')
|
||||
| There was an error decrypting this item. Ensure you are running the
|
||||
| latest version of this app, then sign out and sign back in to try again.
|
||||
#editor-pane-component-stack(ng-show='self.state.note')
|
||||
#editor-pane-component-stack(ng-show='self.note')
|
||||
#component-stack-menu-bar.sk-app-bar.no-edges(ng-if='self.state.componentStack.length')
|
||||
.left
|
||||
.sk-app-bar-item(
|
||||
@@ -1,5 +1,6 @@
|
||||
import { WebApplication } from './../application';
|
||||
import { PanelPuppet, WebDirective } from './../types';
|
||||
import { Editor } from '@/ui_models/editor';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { PanelPuppet, WebDirective } from '@/types';
|
||||
import angular from 'angular';
|
||||
import {
|
||||
ApplicationEvent,
|
||||
@@ -19,8 +20,8 @@ import {
|
||||
import find from 'lodash/find';
|
||||
import { isDesktopApplication } from '@/utils';
|
||||
import { KeyboardModifier, KeyboardKey } from '@/services/keyboardManager';
|
||||
import template from '%/editor.pug';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import template from './editor-view.pug';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { AppStateEvent, EventSource } from '@/services/state';
|
||||
import {
|
||||
STRING_DELETED_NOTE,
|
||||
@@ -39,12 +40,6 @@ const SAVE_TIMEOUT_DEBOUNCE = 350;
|
||||
const SAVE_TIMEOUT_NO_DEBOUNCE = 100;
|
||||
const EDITOR_DEBOUNCE = 200;
|
||||
|
||||
const AppDataKeys = {
|
||||
Pinned: 'pinned',
|
||||
Locked: 'locked',
|
||||
Archived: 'archived',
|
||||
PrefersPlainEditor: 'prefersPlainEditor'
|
||||
};
|
||||
const ElementIds = {
|
||||
NoteTextEditor: 'note-text-editor',
|
||||
NoteTitleEditor: 'note-title-editor',
|
||||
@@ -63,9 +58,8 @@ type NoteStatus = {
|
||||
}
|
||||
|
||||
type EditorState = {
|
||||
note: SNNote
|
||||
saveError?: any
|
||||
selectedEditor?: SNComponent
|
||||
editorComponent?: SNComponent
|
||||
noteStatus?: NoteStatus
|
||||
tagsAsStrings?: string
|
||||
marginResizersEnabled?: boolean
|
||||
@@ -73,6 +67,12 @@ type EditorState = {
|
||||
isDesktop?: boolean
|
||||
tagsComponent?: SNComponent
|
||||
componentStack?: SNComponent[]
|
||||
syncTakingTooLong: boolean
|
||||
showExtensions: boolean
|
||||
noteReady: boolean
|
||||
showOptionsMenu: boolean
|
||||
altKeyDown: boolean
|
||||
spellcheck: boolean
|
||||
/** Fields that can be directly mutated by the template */
|
||||
mutable: {}
|
||||
}
|
||||
@@ -83,9 +83,16 @@ type EditorValues = {
|
||||
tagsInputValue?: string
|
||||
}
|
||||
|
||||
class EditorCtrl extends PureCtrl {
|
||||
interface EditorViewScope {
|
||||
application: WebApplication
|
||||
editor: Editor
|
||||
}
|
||||
|
||||
class EditorViewCtrl extends PureViewCtrl implements EditorViewScope {
|
||||
/** Passed through template */
|
||||
readonly application!: WebApplication
|
||||
readonly editor!: Editor
|
||||
|
||||
private leftPanelPuppet?: PanelPuppet
|
||||
private rightPanelPuppet?: PanelPuppet
|
||||
private unregisterComponent: any
|
||||
@@ -150,9 +157,23 @@ class EditorCtrl extends PureCtrl {
|
||||
return this.state as EditorState;
|
||||
}
|
||||
|
||||
get note() {
|
||||
return this.editor.note;
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
super.$onInit();
|
||||
this.registerKeyboardShortcuts();
|
||||
this.editor.onNoteChange(() => {
|
||||
this.handleEditorNoteChange();
|
||||
})
|
||||
this.editor.onNoteValueChange((note, source) => {
|
||||
if (isPayloadSourceRetrieved(source!)) {
|
||||
this.editorValues.title = note.title;
|
||||
this.editorValues.text = note.text;
|
||||
this.reloadTagsString();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** @override */
|
||||
@@ -168,6 +189,10 @@ class EditorCtrl extends PureCtrl {
|
||||
};
|
||||
}
|
||||
|
||||
async setEditorState(state: Partial<EditorState>) {
|
||||
return this.setState(state);
|
||||
}
|
||||
|
||||
async onAppLaunch() {
|
||||
await super.onAppLaunch();
|
||||
this.streamItems();
|
||||
@@ -176,29 +201,21 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
/** @override */
|
||||
onAppStateEvent(eventName: AppStateEvent, data: any) {
|
||||
if (eventName === AppStateEvent.NoteChanged) {
|
||||
this.handleNoteSelectionChange(
|
||||
this.application.getAppState().getSelectedNote()!,
|
||||
data.previousNote
|
||||
);
|
||||
} else if (eventName === AppStateEvent.PreferencesChanged) {
|
||||
if (eventName === AppStateEvent.PreferencesChanged) {
|
||||
this.reloadPreferences();
|
||||
}
|
||||
}
|
||||
|
||||
/** @override */
|
||||
onAppEvent(eventName: ApplicationEvent) {
|
||||
if (!this.getState().note) {
|
||||
return;
|
||||
}
|
||||
if (eventName === ApplicationEvent.HighLatencySync) {
|
||||
this.setState({ syncTakingTooLong: true });
|
||||
this.setEditorState({ syncTakingTooLong: true });
|
||||
} else if (eventName === ApplicationEvent.CompletedSync) {
|
||||
this.setState({ syncTakingTooLong: false });
|
||||
if (this.getState().note.dirty) {
|
||||
this.setEditorState({ syncTakingTooLong: false });
|
||||
if (this.note.dirty) {
|
||||
/** if we're still dirty, don't change status, a sync is likely upcoming. */
|
||||
} else {
|
||||
const saved = this.getState().note.lastSyncEnd! > this.getState().note.lastSyncBegan!;
|
||||
const saved = this.note.lastSyncEnd! > this.note.lastSyncBegan!;
|
||||
const isInErrorState = this.getState().saveError;
|
||||
if (isInErrorState || saved) {
|
||||
this.showAllChangesSavedStatus();
|
||||
@@ -210,7 +227,7 @@ class EditorCtrl extends PureCtrl {
|
||||
* Otherwise, it means the originating sync came from somewhere else
|
||||
* and we don't want to display an error here.
|
||||
*/
|
||||
if (this.getState().note.dirty) {
|
||||
if (this.note.dirty) {
|
||||
this.showErrorStatus();
|
||||
}
|
||||
} else if (eventName === ApplicationEvent.LocalDatabaseWriteError) {
|
||||
@@ -221,6 +238,50 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
async handleEditorNoteChange() {
|
||||
const note = this.editor.note;
|
||||
await this.setEditorState({
|
||||
showExtensions: false,
|
||||
showOptionsMenu: false,
|
||||
altKeyDown: false,
|
||||
noteStatus: undefined
|
||||
});
|
||||
this.editorValues.title = note.title;
|
||||
this.editorValues.text = note.text;
|
||||
if (!note) {
|
||||
this.setEditorState({
|
||||
noteReady: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
const associatedEditor = this.editorForNote(note);
|
||||
if (associatedEditor && associatedEditor !== this.getState().editorComponent) {
|
||||
/**
|
||||
* Setting note to not ready will remove the editor from view in a flash,
|
||||
* so we only want to do this if switching between external editors
|
||||
*/
|
||||
this.setEditorState({
|
||||
noteReady: false,
|
||||
editorComponent: associatedEditor
|
||||
});
|
||||
} else if (!associatedEditor) {
|
||||
/** No editor */
|
||||
this.setEditorState({
|
||||
editorComponent: undefined
|
||||
});
|
||||
}
|
||||
await this.setEditorState({
|
||||
noteReady: true,
|
||||
});
|
||||
this.reloadTagsString();
|
||||
this.reloadPreferences();
|
||||
if (note.safeText().length === 0) {
|
||||
this.focusTitle();
|
||||
}
|
||||
this.reloadComponentContext();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Because note.locked accesses note.content.appData,
|
||||
* we do not want to expose the template to direct access to note.locked,
|
||||
@@ -230,57 +291,24 @@ class EditorCtrl extends PureCtrl {
|
||||
* on a deleted note.
|
||||
*/
|
||||
get noteLocked() {
|
||||
if (!this.getState().note || this.getState().note.deleted) {
|
||||
if (!this.note || this.note.deleted) {
|
||||
return false;
|
||||
}
|
||||
return this.getState().note.locked;
|
||||
return this.note.locked;
|
||||
}
|
||||
|
||||
streamItems() {
|
||||
this.application.streamItems(
|
||||
ContentType.Note,
|
||||
async (items, source) => {
|
||||
const currentNote = this.getState().note;
|
||||
if (!currentNote) {
|
||||
return;
|
||||
}
|
||||
const matchingNote = items.find((item) => {
|
||||
return item.uuid === currentNote.uuid;
|
||||
}) as SNNote;
|
||||
if (!matchingNote) {
|
||||
return;
|
||||
}
|
||||
if (matchingNote?.deleted) {
|
||||
await this.setState({
|
||||
note: undefined,
|
||||
noteReady: false
|
||||
});
|
||||
return;
|
||||
} else {
|
||||
await this.setState({
|
||||
note: matchingNote
|
||||
});
|
||||
}
|
||||
if (!isPayloadSourceRetrieved(source!)) {
|
||||
return;
|
||||
}
|
||||
this.editorValues.title = matchingNote.title;
|
||||
this.editorValues.text = matchingNote.text;
|
||||
this.reloadTagsString();
|
||||
}
|
||||
);
|
||||
|
||||
this.application.streamItems(
|
||||
ContentType.Tag,
|
||||
(items) => {
|
||||
if (!this.getState().note) {
|
||||
if (!this.note) {
|
||||
return;
|
||||
}
|
||||
for (const tag of items) {
|
||||
if (
|
||||
!this.editorValues.tagsInputValue ||
|
||||
tag.deleted ||
|
||||
tag.hasRelationshipWithItem(this.getState().note)
|
||||
tag.hasRelationshipWithItem(this.note)
|
||||
) {
|
||||
this.reloadTagsString();
|
||||
break;
|
||||
@@ -293,7 +321,7 @@ class EditorCtrl extends PureCtrl {
|
||||
ContentType.Component,
|
||||
async (items) => {
|
||||
const components = items as SNComponent[];
|
||||
if (!this.getState().note) {
|
||||
if (!this.note) {
|
||||
return;
|
||||
}
|
||||
/** Reload componentStack in case new ones were added or removed */
|
||||
@@ -306,9 +334,9 @@ class EditorCtrl extends PureCtrl {
|
||||
return;
|
||||
}
|
||||
/** Find the most recent editor for note */
|
||||
const editor = this.editorForNote(this.getState().note);
|
||||
this.setState({
|
||||
selectedEditor: editor
|
||||
const editor = this.editorForNote(this.note);
|
||||
this.setEditorState({
|
||||
editorComponent: editor
|
||||
});
|
||||
if (!editor) {
|
||||
this.reloadFont();
|
||||
@@ -317,62 +345,12 @@ class EditorCtrl extends PureCtrl {
|
||||
);
|
||||
}
|
||||
|
||||
async handleNoteSelectionChange(note: SNNote, previousNote?: SNNote) {
|
||||
await this.setState({
|
||||
note: note,
|
||||
showExtensions: false,
|
||||
showOptionsMenu: false,
|
||||
altKeyDown: false,
|
||||
noteStatus: null
|
||||
});
|
||||
this.editorValues.title = note.title;
|
||||
this.editorValues.text = note.text;
|
||||
if (!note) {
|
||||
this.setState({
|
||||
noteReady: false
|
||||
});
|
||||
return;
|
||||
}
|
||||
const associatedEditor = this.editorForNote(note);
|
||||
if (associatedEditor && associatedEditor !== this.getState().selectedEditor) {
|
||||
/**
|
||||
* Setting note to not ready will remove the editor from view in a flash,
|
||||
* so we only want to do this if switching between external editors
|
||||
*/
|
||||
this.setState({
|
||||
noteReady: false,
|
||||
selectedEditor: associatedEditor
|
||||
});
|
||||
} else if (!associatedEditor) {
|
||||
/** No editor */
|
||||
this.setState({
|
||||
selectedEditor: null
|
||||
});
|
||||
}
|
||||
await this.setState({
|
||||
noteReady: true,
|
||||
});
|
||||
this.reloadTagsString();
|
||||
this.reloadPreferences();
|
||||
|
||||
if (note.dummy) {
|
||||
this.focusTitle();
|
||||
}
|
||||
if (previousNote && previousNote !== note) {
|
||||
if (previousNote.dummy) {
|
||||
this.performNoteDeletion(previousNote);
|
||||
}
|
||||
}
|
||||
|
||||
this.reloadComponentContext();
|
||||
}
|
||||
|
||||
editorForNote(note: SNNote) {
|
||||
return this.application.componentManager!.editorForNote(note);
|
||||
}
|
||||
|
||||
setMenuState(menu: string, state: boolean) {
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
[menu]: state
|
||||
});
|
||||
this.closeAllMenus(menu);
|
||||
@@ -395,7 +373,7 @@ class EditorCtrl extends PureCtrl {
|
||||
menuState[candidate] = false;
|
||||
}
|
||||
}
|
||||
this.setState(menuState);
|
||||
this.setEditorState(menuState);
|
||||
}
|
||||
|
||||
editorMenuOnSelect(component: SNComponent) {
|
||||
@@ -403,10 +381,10 @@ class EditorCtrl extends PureCtrl {
|
||||
/** If plain editor or other editor */
|
||||
this.setMenuState('showEditorMenu', false);
|
||||
const editor = component;
|
||||
if (this.getState().selectedEditor && editor !== this.getState().selectedEditor) {
|
||||
this.disassociateComponentWithCurrentNote(this.getState().selectedEditor!);
|
||||
if (this.getState().editorComponent && editor !== this.getState().editorComponent) {
|
||||
this.disassociateComponentWithCurrentNote(this.getState().editorComponent!);
|
||||
}
|
||||
const note = this.getState().note;
|
||||
const note = this.note;
|
||||
if (editor) {
|
||||
const prefersPlain = note.prefersPlainEditor;
|
||||
if (prefersPlain) {
|
||||
@@ -427,8 +405,8 @@ class EditorCtrl extends PureCtrl {
|
||||
this.reloadFont();
|
||||
}
|
||||
|
||||
this.setState({
|
||||
selectedEditor: editor
|
||||
this.setEditorState({
|
||||
editorComponent: editor
|
||||
});
|
||||
} else if (component.area === 'editor-stack') {
|
||||
this.toggleStackComponentForCurrentItem(component);
|
||||
@@ -440,7 +418,7 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
hasAvailableExtensions() {
|
||||
return this.application.actionsManager!.
|
||||
extensionsInContextOfItem(this.getState().note).length > 0;
|
||||
extensionsInContextOfItem(this.note).length > 0;
|
||||
}
|
||||
|
||||
performFirefoxPinnedTabFix() {
|
||||
@@ -454,14 +432,14 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
saveNote(
|
||||
async saveNote(
|
||||
bypassDebouncer = false,
|
||||
isUserModified = false,
|
||||
dontUpdatePreviews = false,
|
||||
customMutate?: (mutator: NoteMutator) => void
|
||||
) {
|
||||
this.performFirefoxPinnedTabFix();
|
||||
const note = this.getState().note;
|
||||
const note = this.note;
|
||||
|
||||
if (note.deleted) {
|
||||
this.application.alertService!.alert(
|
||||
@@ -469,15 +447,16 @@ class EditorCtrl extends PureCtrl {
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (this.editor.isTemplateNote) {
|
||||
await this.editor.insertTemplatedNote();
|
||||
}
|
||||
if (!this.application.findItem(note.uuid)) {
|
||||
this.application.alertService!.alert(
|
||||
STRING_INVALID_NOTE
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
this.showSavingStatus();
|
||||
|
||||
this.application.changeItem(note.uuid, (mutator) => {
|
||||
const noteMutator = mutator as NoteMutator;
|
||||
if (customMutate) {
|
||||
@@ -516,7 +495,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
showAllChangesSavedStatus() {
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
saveError: false,
|
||||
syncTakingTooLong: false
|
||||
});
|
||||
@@ -532,7 +511,7 @@ class EditorCtrl extends PureCtrl {
|
||||
desc: "Changes saved offline"
|
||||
};
|
||||
}
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
saveError: true,
|
||||
syncTakingTooLong: false
|
||||
});
|
||||
@@ -541,11 +520,11 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
setStatus(status: { message: string, date?: Date }, wait = true) {
|
||||
let waitForMs;
|
||||
if (!this.getState().noteStatus || !this.getState().noteStatus!.date) {
|
||||
if (!this.state.noteStatus || !this.state.noteStatus!.date) {
|
||||
waitForMs = 0;
|
||||
} else {
|
||||
waitForMs = MINIMUM_STATUS_DURATION - (
|
||||
new Date().getTime() - this.getState().noteStatus!.date!.getTime()
|
||||
new Date().getTime() - this.state.noteStatus!.date!.getTime()
|
||||
);
|
||||
}
|
||||
if (!wait || waitForMs < 0) {
|
||||
@@ -556,7 +535,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
this.statusTimeout = this.$timeout(() => {
|
||||
status.date = new Date();
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
noteStatus: status
|
||||
});
|
||||
}, waitForMs);
|
||||
@@ -619,21 +598,21 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
async deleteNote(permanently: boolean) {
|
||||
if (this.getState().note.dummy) {
|
||||
if (this.editor.isTemplateNote) {
|
||||
this.application.alertService!.alert(
|
||||
STRING_DELETE_PLACEHOLDER_ATTEMPT
|
||||
);
|
||||
return;
|
||||
}
|
||||
const run = () => {
|
||||
if (this.getState().note.locked) {
|
||||
if (this.note.locked) {
|
||||
this.application.alertService!.alert(
|
||||
STRING_DELETE_LOCKED_ATTEMPT
|
||||
);
|
||||
return;
|
||||
}
|
||||
const title = this.getState().note.safeTitle().length
|
||||
? `'${this.getState().note.title}'`
|
||||
const title = this.note.safeTitle().length
|
||||
? `'${this.note.title}'`
|
||||
: "this note";
|
||||
const text = StringDeleteNote(
|
||||
title,
|
||||
@@ -646,7 +625,7 @@ class EditorCtrl extends PureCtrl {
|
||||
undefined,
|
||||
() => {
|
||||
if (permanently) {
|
||||
this.performNoteDeletion(this.getState().note);
|
||||
this.performNoteDeletion(this.note);
|
||||
} else {
|
||||
this.saveNote(
|
||||
true,
|
||||
@@ -657,8 +636,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
);
|
||||
}
|
||||
this.application.getAppState().setSelectedNote(undefined);
|
||||
this.setMenuState('showOptionsMenu', false);
|
||||
this.appState.closeEditor(this.editor);
|
||||
},
|
||||
undefined,
|
||||
true,
|
||||
@@ -681,16 +659,6 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
performNoteDeletion(note: SNNote) {
|
||||
this.application.deleteItem(note);
|
||||
if (note === this.getState().note) {
|
||||
this.setState({
|
||||
note: null
|
||||
});
|
||||
}
|
||||
if (note.dummy) {
|
||||
this.application.deleteItemLocally(note);
|
||||
return;
|
||||
}
|
||||
this.application.sync();
|
||||
}
|
||||
|
||||
restoreTrashedNote() {
|
||||
@@ -702,7 +670,7 @@ class EditorCtrl extends PureCtrl {
|
||||
mutator.trashed = false;
|
||||
}
|
||||
);
|
||||
this.application.getAppState().setSelectedNote(undefined);
|
||||
this.appState.closeEditor(this.editor);
|
||||
}
|
||||
|
||||
deleteNotePermanantely() {
|
||||
@@ -735,7 +703,7 @@ class EditorCtrl extends PureCtrl {
|
||||
false,
|
||||
true,
|
||||
(mutator) => {
|
||||
mutator.pinned = !this.getState().note.pinned
|
||||
mutator.pinned = !this.note.pinned
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -746,7 +714,7 @@ class EditorCtrl extends PureCtrl {
|
||||
false,
|
||||
true,
|
||||
(mutator) => {
|
||||
mutator.locked = !this.getState().note.locked
|
||||
mutator.locked = !this.note.locked
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -757,7 +725,7 @@ class EditorCtrl extends PureCtrl {
|
||||
false,
|
||||
true,
|
||||
(mutator) => {
|
||||
mutator.protected = !this.getState().note.protected
|
||||
mutator.protected = !this.note.protected
|
||||
}
|
||||
);
|
||||
/** Show privileges manager if protection is not yet set up */
|
||||
@@ -776,7 +744,7 @@ class EditorCtrl extends PureCtrl {
|
||||
false,
|
||||
true,
|
||||
(mutator) => {
|
||||
mutator.hidePreview = !this.getState().note.hidePreview
|
||||
mutator.hidePreview = !this.note.hidePreview
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -787,21 +755,21 @@ class EditorCtrl extends PureCtrl {
|
||||
false,
|
||||
true,
|
||||
(mutator) => {
|
||||
mutator.archived = !this.getState().note.archived
|
||||
mutator.archived = !this.note.archived
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
reloadTagsString() {
|
||||
const tags = this.appState.getNoteTags(this.getState().note);
|
||||
const tags = this.appState.getNoteTags(this.note);
|
||||
const string = SNTag.arrayToDisplayString(tags);
|
||||
this.updateUI(() => {
|
||||
this.editorValues.tagsInputValue = string;
|
||||
})
|
||||
}
|
||||
|
||||
addTag(tag: SNTag) {
|
||||
const tags = this.appState.getNoteTags(this.getState().note);
|
||||
private addTag(tag: SNTag) {
|
||||
const tags = this.appState.getNoteTags(this.note);
|
||||
const strings = tags.map((currentTag) => {
|
||||
return currentTag.title;
|
||||
});
|
||||
@@ -810,7 +778,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
removeTag(tag: SNTag) {
|
||||
const tags = this.appState.getNoteTags(this.getState().note);
|
||||
const tags = this.appState.getNoteTags(this.note);
|
||||
const strings = tags.map((currentTag) => {
|
||||
return currentTag.title;
|
||||
}).filter((title) => {
|
||||
@@ -819,7 +787,7 @@ class EditorCtrl extends PureCtrl {
|
||||
this.saveTagsFromStrings(strings);
|
||||
}
|
||||
|
||||
async saveTagsFromStrings(strings?: string[]) {
|
||||
public async saveTagsFromStrings(strings?: string[]) {
|
||||
if (
|
||||
!strings
|
||||
&& this.editorValues.tagsInputValue === this.getState().tagsAsStrings
|
||||
@@ -836,10 +804,8 @@ class EditorCtrl extends PureCtrl {
|
||||
return string.trim();
|
||||
});
|
||||
}
|
||||
|
||||
const note = this.getState().note;
|
||||
const note = this.note;
|
||||
const currentTags = this.appState.getNoteTags(note);
|
||||
|
||||
const removeTags = [];
|
||||
for (const tag of currentTags) {
|
||||
if (strings.indexOf(tag.title) === -1) {
|
||||
@@ -907,7 +873,7 @@ class EditorCtrl extends PureCtrl {
|
||||
WebPrefKey.EditorResizersEnabled,
|
||||
true
|
||||
);
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
monospaceEnabled,
|
||||
spellcheck,
|
||||
marginResizersEnabled
|
||||
@@ -973,10 +939,10 @@ class EditorCtrl extends PureCtrl {
|
||||
|
||||
if (key === WebPrefKey.EditorSpellcheck) {
|
||||
/** Allows textarea to reload */
|
||||
await this.setState({
|
||||
await this.setEditorState({
|
||||
noteReady: false
|
||||
});
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
noteReady: true
|
||||
});
|
||||
this.reloadFont();
|
||||
@@ -1000,42 +966,42 @@ class EditorCtrl extends PureCtrl {
|
||||
],
|
||||
activationHandler: (component) => {
|
||||
if (component.area === 'note-tags') {
|
||||
this.setState({
|
||||
tagsComponent: component.active ? component : null
|
||||
this.setEditorState({
|
||||
tagsComponent: component.active ? component : undefined
|
||||
});
|
||||
} else if (component.area === 'editor-editor') {
|
||||
if (
|
||||
component === this.getState().selectedEditor &&
|
||||
component === this.getState().editorComponent &&
|
||||
!component.active
|
||||
) {
|
||||
this.setState({ selectedEditor: null });
|
||||
this.setEditorState({ editorComponent: undefined });
|
||||
}
|
||||
else if (this.getState().selectedEditor) {
|
||||
if (this.getState().selectedEditor!.active && this.getState().note) {
|
||||
else if (this.getState().editorComponent) {
|
||||
if (this.getState().editorComponent!.active && this.note) {
|
||||
if (
|
||||
component.isExplicitlyEnabledForItem(this.getState().note)
|
||||
&& !this.getState().selectedEditor!.isExplicitlyEnabledForItem(this.getState().note)
|
||||
component.isExplicitlyEnabledForItem(this.note)
|
||||
&& !this.getState().editorComponent!.isExplicitlyEnabledForItem(this.note)
|
||||
) {
|
||||
this.setState({ selectedEditor: component });
|
||||
this.setEditorState({ editorComponent: component });
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (this.getState().note) {
|
||||
else if (this.note) {
|
||||
const enableable = (
|
||||
component.isExplicitlyEnabledForItem(this.getState().note)
|
||||
component.isExplicitlyEnabledForItem(this.note)
|
||||
|| component.isDefaultEditor()
|
||||
);
|
||||
if (
|
||||
component.active
|
||||
&& enableable
|
||||
) {
|
||||
this.setState({ selectedEditor: component });
|
||||
this.setEditorState({ editorComponent: component });
|
||||
} else {
|
||||
/**
|
||||
* Not a candidate, and no qualified editor.
|
||||
* Disable the current editor.
|
||||
*/
|
||||
this.setState({ selectedEditor: null });
|
||||
this.setEditorState({ editorComponent: undefined });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1045,11 +1011,11 @@ class EditorCtrl extends PureCtrl {
|
||||
},
|
||||
contextRequestHandler: (component) => {
|
||||
if (
|
||||
component === this.getState().selectedEditor ||
|
||||
component === this.getState().editorComponent ||
|
||||
component === this.getState().tagsComponent ||
|
||||
this.getState().componentStack!.includes(component)
|
||||
) {
|
||||
return this.getState().note;
|
||||
return this.note;
|
||||
}
|
||||
},
|
||||
focusHandler: (component, focused) => {
|
||||
@@ -1093,7 +1059,7 @@ class EditorCtrl extends PureCtrl {
|
||||
else if (action === ComponentAction.SaveItems) {
|
||||
const includesNote = data.items.map((item: RawPayload) => {
|
||||
return item.uuid;
|
||||
}).includes(this.getState().note.uuid);
|
||||
}).includes(this.note.uuid);
|
||||
if (includesNote) {
|
||||
this.showSavingStatus();
|
||||
}
|
||||
@@ -1109,19 +1075,19 @@ class EditorCtrl extends PureCtrl {
|
||||
return a.name.toLowerCase() < b.name.toLowerCase() ? -1 : 1;
|
||||
});
|
||||
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
componentStack: components
|
||||
});
|
||||
}
|
||||
|
||||
reloadComponentContext() {
|
||||
this.reloadComponentStackArray();
|
||||
if (this.getState().note) {
|
||||
if (this.note) {
|
||||
for (const component of this.getState().componentStack!) {
|
||||
if (component.active) {
|
||||
this.application.componentManager!.setComponentHidden(
|
||||
component,
|
||||
!component.isExplicitlyEnabledForItem(this.getState().note)
|
||||
!component.isExplicitlyEnabledForItem(this.note)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1148,7 +1114,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
disassociateComponentWithCurrentNote(component: SNComponent) {
|
||||
const note = this.getState().note;
|
||||
const note = this.note;
|
||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.removeAssociatedItemId(note.uuid);
|
||||
@@ -1157,7 +1123,7 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
associateComponentWithCurrentNote(component: SNComponent) {
|
||||
const note = this.getState().note;
|
||||
const note = this.note;
|
||||
this.application.changeAndSaveItem(component.uuid, (m) => {
|
||||
const mutator = m as ComponentMutator;
|
||||
mutator.removeDisassociatedItemId(note.uuid);
|
||||
@@ -1171,12 +1137,12 @@ class EditorCtrl extends PureCtrl {
|
||||
KeyboardModifier.Alt
|
||||
],
|
||||
onKeyDown: () => {
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
altKeyDown: true
|
||||
});
|
||||
},
|
||||
onKeyUp: () => {
|
||||
this.setState({
|
||||
this.setEditorState({
|
||||
altKeyDown: false
|
||||
});
|
||||
}
|
||||
@@ -1223,7 +1189,7 @@ class EditorCtrl extends PureCtrl {
|
||||
element: editor,
|
||||
key: KeyboardKey.Tab,
|
||||
onKeyDown: (event) => {
|
||||
if (this.getState().note.locked || event.shiftKey) {
|
||||
if (this.note.locked || event.shiftKey) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
@@ -1260,16 +1226,17 @@ class EditorCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
export class EditorPanel extends WebDirective {
|
||||
export class EditorView extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.restrict = 'E';
|
||||
this.scope = {
|
||||
editor: '=',
|
||||
application: '='
|
||||
};
|
||||
this.template = template;
|
||||
this.replace = true;
|
||||
this.controller = EditorCtrl;
|
||||
this.controller = EditorViewCtrl;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
editor-view(
|
||||
ng-repeat='editor in self.editors'
|
||||
application='self.application'
|
||||
editor='editor'
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { WebDirective } from './../../types';
|
||||
import template from './editor-group-view.pug';
|
||||
import { Editor } from '@/ui_models/editor';
|
||||
|
||||
class EditorGroupViewCtrl {
|
||||
|
||||
private application!: WebApplication
|
||||
public editors: Editor[] = []
|
||||
|
||||
/* @ngInject */
|
||||
constructor() {
|
||||
|
||||
}
|
||||
|
||||
$onInit() {
|
||||
this.application.editorGroup.addChangeObserver(() => {
|
||||
this.editors = this.application.editorGroup.editors;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
export class EditorGroupView extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.template = template;
|
||||
this.controller = EditorGroupViewCtrl;
|
||||
this.replace = true;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FooterStatus, WebDirective } from './../types';
|
||||
import { FooterStatus, WebDirective } from '@/types';
|
||||
import { dateToLocalizedString } from '@/utils';
|
||||
import {
|
||||
ApplicationEvent,
|
||||
@@ -10,13 +10,13 @@ import {
|
||||
ComponentArea,
|
||||
ComponentAction
|
||||
} from 'snjs';
|
||||
import template from '%/footer.pug';
|
||||
import template from './footer-view.pug';
|
||||
import { AppStateEvent, EventSource } from '@/services/state';
|
||||
import {
|
||||
STRING_GENERIC_SYNC_ERROR,
|
||||
STRING_NEW_UPDATE_READY
|
||||
} from '@/strings';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { ComponentMutator } from '@/../../../../snjs/dist/@types/models';
|
||||
|
||||
type DockShortcut = {
|
||||
@@ -29,7 +29,7 @@ type DockShortcut = {
|
||||
}
|
||||
}
|
||||
|
||||
class FooterCtrl extends PureCtrl {
|
||||
class FooterViewCtrl extends PureViewCtrl {
|
||||
|
||||
private $rootScope: ng.IRootScopeService
|
||||
private rooms: SNComponent[] = []
|
||||
@@ -427,15 +427,16 @@ class FooterCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
export class Footer extends WebDirective {
|
||||
export class FooterView extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.restrict = 'E';
|
||||
this.template = template;
|
||||
this.controller = FooterCtrl;
|
||||
this.controller = FooterViewCtrl;
|
||||
this.replace = true;
|
||||
this.controllerAs = 'ctrl';
|
||||
this.bindToController = {
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
application: '='
|
||||
};
|
||||
}
|
||||
11
app/assets/javascripts/views/index.ts
Normal file
11
app/assets/javascripts/views/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
export { PureViewCtrl } from './abstract/pure_view_ctrl';
|
||||
|
||||
export { ApplicationGroupView } from './application_group/application_group_view';
|
||||
export { ApplicationView } from './application/application_view';
|
||||
|
||||
export { EditorGroupView } from './editor_group/editor_group_view';
|
||||
export { EditorView } from './editor/editor_view';
|
||||
|
||||
export { FooterView } from './footer/footer_view';
|
||||
export { NotesView } from './notes/notes_view';
|
||||
export { TagsView } from './tags/tags_view';
|
||||
@@ -111,10 +111,8 @@ export function sortNotes(
|
||||
notes: SNNote[] = [],
|
||||
sortBy: string,
|
||||
reverse: boolean
|
||||
) {
|
||||
) {
|
||||
const sortValueFn = (a: SNNote, b: SNNote, pinCheck = false): number => {
|
||||
if (a.dummy) { return -1; }
|
||||
if (b.dummy) { return 1; }
|
||||
if (!pinCheck) {
|
||||
if (a.pinned && b.pinned) {
|
||||
return sortValueFn(a, b, true);
|
||||
@@ -123,7 +121,7 @@ export function sortNotes(
|
||||
if (b.pinned) { return 1; }
|
||||
}
|
||||
let aValue = (a as any)[sortBy] || '';
|
||||
let bValue = (a as any)[sortBy] || '';
|
||||
let bValue = (b as any)[sortBy] || '';
|
||||
let vector = 1;
|
||||
if (reverse) {
|
||||
vector *= -1;
|
||||
@@ -109,8 +109,8 @@
|
||||
)
|
||||
.note(
|
||||
ng-repeat='note in self.state.renderedNotes track by note.uuid'
|
||||
ng-class="{'selected' : self.selectedNote == note}"
|
||||
ng-click='self.selectNote(note, true)'
|
||||
ng-class="{'selected' : self.activeEditorNote == note}"
|
||||
ng-click='self.selectNote(note)'
|
||||
)
|
||||
.note-flags(ng-show='self.noteFlags[note.uuid].length > 0')
|
||||
.flag(ng-class='flag.class', ng-repeat='flag in self.noteFlags[note.uuid]')
|
||||
@@ -138,6 +138,7 @@
|
||||
| Modified {{note.updatedAtString || 'Now'}}
|
||||
span(ng-show="self.state.sortBy != 'client_updated_at'")
|
||||
| {{note.createdAtString || 'Now'}}
|
||||
|
||||
panel-resizer(
|
||||
collapsable="true"
|
||||
control="self.panelPuppet"
|
||||
@@ -1,13 +1,20 @@
|
||||
import { PanelPuppet, WebDirective } from './../../types';
|
||||
import angular from 'angular';
|
||||
import template from '%/notes.pug';
|
||||
import { ApplicationEvent, ContentType, removeFromArray, SNNote, SNTag, WebPrefKey } from 'snjs';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import template from './notes-view.pug';
|
||||
import {
|
||||
ApplicationEvent,
|
||||
ContentType,
|
||||
removeFromArray,
|
||||
SNNote,
|
||||
SNTag,
|
||||
WebPrefKey
|
||||
} from 'snjs';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { AppStateEvent } from '@/services/state';
|
||||
import { KeyboardModifier, KeyboardKey } from '@/services/keyboardManager';
|
||||
import {
|
||||
PANEL_NAME_NOTES
|
||||
} from '@/controllers/constants';
|
||||
} from '@/views/constants';
|
||||
import {
|
||||
NoteSortKey,
|
||||
filterAndSortNotes
|
||||
@@ -15,6 +22,7 @@ import {
|
||||
import { UuidString } from '@/../../../../snjs/dist/@types/types';
|
||||
|
||||
type NotesState = {
|
||||
panelTitle: string
|
||||
tag?: SNTag
|
||||
notes?: SNNote[]
|
||||
renderedNotes?: SNNote[]
|
||||
@@ -43,7 +51,7 @@ const DEFAULT_LIST_NUM_NOTES = 20;
|
||||
const ELEMENT_ID_SEARCH_BAR = 'search-bar';
|
||||
const ELEMENT_ID_SCROLL_CONTAINER = 'notes-scrollable';
|
||||
|
||||
class NotesCtrl extends PureCtrl {
|
||||
class NotesViewCtrl extends PureViewCtrl {
|
||||
|
||||
private panelPuppet?: PanelPuppet
|
||||
private reloadNotesPromise?: any
|
||||
@@ -101,13 +109,17 @@ class NotesCtrl extends PureCtrl {
|
||||
return this.state as NotesState;
|
||||
}
|
||||
|
||||
async setNotesState(state: Partial<NotesState>) {
|
||||
return this.setState(state);
|
||||
}
|
||||
|
||||
getInitialState() {
|
||||
return {
|
||||
notes: [],
|
||||
renderedNotes: [],
|
||||
mutable: { showMenu: false },
|
||||
noteFilter: { text: '' },
|
||||
} as NotesState;
|
||||
} as Partial<NotesState>;
|
||||
}
|
||||
|
||||
async onAppLaunch() {
|
||||
@@ -120,13 +132,10 @@ class NotesCtrl extends PureCtrl {
|
||||
onAppStateEvent(eventName: AppStateEvent, data?: any) {
|
||||
if (eventName === AppStateEvent.TagChanged) {
|
||||
this.handleTagChange(
|
||||
this.application!.getAppState().getSelectedTag()!,
|
||||
data.previousTag
|
||||
);
|
||||
} else if (eventName === AppStateEvent.NoteChanged) {
|
||||
this.handleNoteSelection(
|
||||
this.application!.getAppState().getSelectedNote()!
|
||||
this.application!.getAppState().getSelectedTag()!
|
||||
);
|
||||
} else if (eventName === AppStateEvent.ActiveEditorChanged) {
|
||||
this.handleEditorChange();
|
||||
} else if (eventName === AppStateEvent.PreferencesChanged) {
|
||||
this.reloadPreferences();
|
||||
this.reloadNotes();
|
||||
@@ -135,19 +144,19 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
get selectedNote() {
|
||||
return this.appState.getSelectedNote();
|
||||
get activeEditorNote() {
|
||||
const activeEditor = this.appState.getActiveEditor();
|
||||
return activeEditor && activeEditor.note;
|
||||
}
|
||||
|
||||
public get editorNotes() {
|
||||
return this.appState.getEditors().map((editor) => editor.note);
|
||||
}
|
||||
|
||||
/** @override */
|
||||
async onAppEvent(eventName: ApplicationEvent) {
|
||||
if (eventName === ApplicationEvent.SignedIn) {
|
||||
/** Delete dummy note if applicable */
|
||||
if (this.selectedNote && this.selectedNote!.dummy) {
|
||||
this.application!.deleteItemLocally(this.selectedNote!);
|
||||
await this.selectNote(undefined);
|
||||
await this.reloadNotes();
|
||||
}
|
||||
this.appState.closeAllEditors();
|
||||
} else if (eventName === ApplicationEvent.CompletedSync) {
|
||||
this.getMostValidNotes().then((notes) => {
|
||||
if (notes.length === 0) {
|
||||
@@ -196,9 +205,9 @@ class NotesCtrl extends PureCtrl {
|
||||
[ContentType.Note, ContentType.Tag],
|
||||
async (items) => {
|
||||
await this.reloadNotes();
|
||||
const selectedNote = this.selectedNote;
|
||||
if (selectedNote) {
|
||||
const discarded = selectedNote.deleted || selectedNote.trashed;
|
||||
const activeNote = this.activeEditorNote;
|
||||
if (activeNote) {
|
||||
const discarded = activeNote.deleted || activeNote.trashed;
|
||||
if (discarded) {
|
||||
this.selectNextOrCreateNew();
|
||||
}
|
||||
@@ -218,51 +227,20 @@ class NotesCtrl extends PureCtrl {
|
||||
);
|
||||
}
|
||||
|
||||
async selectNote(note?: SNNote) {
|
||||
return this.application!.getAppState().setSelectedNote(note);
|
||||
async selectNote(note: SNNote) {
|
||||
this.appState.openEditor(note.uuid);
|
||||
}
|
||||
|
||||
async createNewNote() {
|
||||
const selectedTag = this.application!.getAppState().getSelectedTag();
|
||||
if (!selectedTag) {
|
||||
throw 'Attempting to create note with no selected tag';
|
||||
}
|
||||
let title;
|
||||
let isDummyNote = true;
|
||||
let title = `Note ${this.getState().notes!.length + 1}`;
|
||||
if (this.isFiltering()) {
|
||||
title = this.getState().noteFilter.text;
|
||||
isDummyNote = false;
|
||||
} else if (this.selectedNote && this.selectedNote!.dummy) {
|
||||
return;
|
||||
} else {
|
||||
title = `Note ${this.getState().notes!.length + 1}`;
|
||||
}
|
||||
const newNote = await this.application!.createManagedItem(
|
||||
ContentType.Note,
|
||||
{
|
||||
text: '',
|
||||
title: title,
|
||||
references: []
|
||||
},
|
||||
true,
|
||||
{
|
||||
dummy: isDummyNote
|
||||
}
|
||||
) as SNNote;
|
||||
if (!selectedTag.isSmartTag()) {
|
||||
this.application!.changeItem(selectedTag.uuid, (mutator) => {
|
||||
mutator.addItemAsRelationship(newNote);
|
||||
});
|
||||
}
|
||||
this.selectNote(newNote);
|
||||
this.appState.createEditor(title);
|
||||
}
|
||||
|
||||
async handleTagChange(tag: SNTag, previousTag?: SNTag) {
|
||||
if (this.selectedNote && this.selectedNote!.dummy) {
|
||||
await this.application!.deleteItemLocally(this.selectedNote!);
|
||||
await this.selectNote(undefined);
|
||||
}
|
||||
await this.setState({ tag: tag });
|
||||
async handleTagChange(tag: SNTag) {
|
||||
await this.setNotesState({ tag });
|
||||
|
||||
this.resetScrollPosition();
|
||||
this.setShowMenuFalse();
|
||||
@@ -270,7 +248,8 @@ class NotesCtrl extends PureCtrl {
|
||||
this.application!.getDesktopService().searchText();
|
||||
this.resetPagination();
|
||||
|
||||
/* Capture db load state before beginning reloadNotes, since this status may change during reload */
|
||||
/* Capture db load state before beginning reloadNotes,
|
||||
since this status may change during reload */
|
||||
const dbLoaded = this.application!.isDatabaseLoaded();
|
||||
await this.reloadNotes();
|
||||
|
||||
@@ -280,10 +259,10 @@ class NotesCtrl extends PureCtrl {
|
||||
if (!tag.isSmartTag() || tag.isAllTag) {
|
||||
this.createPlaceholderNote();
|
||||
} else if (
|
||||
this.selectedNote &&
|
||||
!this.getState().notes!.includes(this.selectedNote!)
|
||||
this.activeEditorNote &&
|
||||
!this.getState().notes!.includes(this.activeEditorNote!)
|
||||
) {
|
||||
this.selectNote(undefined);
|
||||
this.appState.closeActiveEditor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,7 +278,7 @@ class NotesCtrl extends PureCtrl {
|
||||
async removeNoteFromList(note: SNNote) {
|
||||
const notes = this.getState().notes!;
|
||||
removeFromArray(notes, note);
|
||||
await this.setState({
|
||||
await this.setNotesState({
|
||||
notes: notes,
|
||||
renderedNotes: notes.slice(0, this.notesToDisplay)
|
||||
});
|
||||
@@ -330,7 +309,7 @@ class NotesCtrl extends PureCtrl {
|
||||
this.loadFlagsForNote(note);
|
||||
}
|
||||
}
|
||||
await this.setState({
|
||||
await this.setNotesState({
|
||||
notes: notes,
|
||||
renderedNotes: notes.slice(0, this.notesToDisplay)
|
||||
});
|
||||
@@ -338,7 +317,7 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
setShowMenuFalse() {
|
||||
this.setState({
|
||||
this.setNotesState({
|
||||
mutable: {
|
||||
...this.getState().mutable,
|
||||
showMenu: false
|
||||
@@ -346,20 +325,10 @@ class NotesCtrl extends PureCtrl {
|
||||
});
|
||||
}
|
||||
|
||||
async handleNoteSelection(note: SNNote) {
|
||||
const previousNote = this.selectedNote;
|
||||
if (previousNote === note) {
|
||||
return;
|
||||
}
|
||||
if (previousNote && previousNote.dummy) {
|
||||
await this.application!.deleteItemLocally(previousNote);
|
||||
this.removeNoteFromList(previousNote);
|
||||
}
|
||||
if (!note) {
|
||||
return;
|
||||
}
|
||||
if (note.conflictOf) {
|
||||
this.application!.changeAndSaveItem(note.uuid, (mutator) => {
|
||||
async handleEditorChange() {
|
||||
const activeNote = this.appState.getActiveEditor().note;
|
||||
if (activeNote && activeNote.conflictOf) {
|
||||
this.application!.changeAndSaveItem(activeNote.uuid, (mutator) => {
|
||||
mutator.conflictOf = undefined;
|
||||
})
|
||||
}
|
||||
@@ -404,7 +373,7 @@ class NotesCtrl extends PureCtrl {
|
||||
WebPrefKey.NotesHideTags,
|
||||
false
|
||||
);
|
||||
this.setState({
|
||||
this.setNotesState({
|
||||
...viewOptions
|
||||
});
|
||||
if (prevSortValue && prevSortValue !== sortBy) {
|
||||
@@ -469,7 +438,7 @@ class NotesCtrl extends PureCtrl {
|
||||
} else if (this.getState().tag) {
|
||||
title = `${this.getState().tag!.title}`;
|
||||
}
|
||||
this.setState({
|
||||
this.setNotesState({
|
||||
panelTitle: title
|
||||
});
|
||||
}
|
||||
@@ -584,7 +553,7 @@ class NotesCtrl extends PureCtrl {
|
||||
selectNextNote() {
|
||||
const displayableNotes = this.displayableNotes();
|
||||
const currentIndex = displayableNotes.findIndex((candidate) => {
|
||||
return candidate.uuid === this.selectedNote!.uuid
|
||||
return candidate.uuid === this.activeEditorNote!.uuid
|
||||
});
|
||||
if (currentIndex + 1 < displayableNotes.length) {
|
||||
this.selectNote(displayableNotes[currentIndex + 1]);
|
||||
@@ -598,13 +567,13 @@ class NotesCtrl extends PureCtrl {
|
||||
} else if (!this.getState().tag || !this.getState().tag!.isSmartTag()) {
|
||||
this.createPlaceholderNote();
|
||||
} else {
|
||||
this.selectNote(undefined);
|
||||
this.appState.closeActiveEditor();
|
||||
}
|
||||
}
|
||||
|
||||
selectPreviousNote() {
|
||||
const displayableNotes = this.displayableNotes();
|
||||
const currentIndex = displayableNotes.indexOf(this.selectedNote!);
|
||||
const currentIndex = displayableNotes.indexOf(this.activeEditorNote!);
|
||||
if (currentIndex - 1 >= 0) {
|
||||
this.selectNote(displayableNotes[currentIndex - 1]);
|
||||
return true;
|
||||
@@ -619,7 +588,7 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
|
||||
async setNoteFilterText(text: string) {
|
||||
await this.setState({
|
||||
await this.setNotesState({
|
||||
noteFilter: {
|
||||
...this.getState().noteFilter,
|
||||
text: text
|
||||
@@ -748,12 +717,12 @@ class NotesCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
export class NotesPanel extends WebDirective {
|
||||
export class NotesView extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.template = template;
|
||||
this.replace = true;
|
||||
this.controller = NotesCtrl;
|
||||
this.controller = NotesViewCtrl;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
this.scope = {
|
||||
@@ -1,7 +1,6 @@
|
||||
import { WebDirective, PanelPuppet } from './../types';
|
||||
import { WebApplication } from './../application';
|
||||
import { WebDirective, PanelPuppet } from '@/types';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import {
|
||||
SNNote,
|
||||
SNTag,
|
||||
ContentType,
|
||||
ApplicationEvent,
|
||||
@@ -11,17 +10,17 @@ import {
|
||||
SNComponent,
|
||||
WebPrefKey
|
||||
} from 'snjs';
|
||||
import template from '%/tags.pug';
|
||||
import template from './tags-view.pug';
|
||||
import { AppStateEvent } from '@/services/state';
|
||||
import { PANEL_NAME_TAGS } from '@/controllers/constants';
|
||||
import { PANEL_NAME_TAGS } from '@/views/constants';
|
||||
import { STRING_DELETE_TAG } from '@/strings';
|
||||
import { PureCtrl } from '@Controllers/abstract/pure_ctrl';
|
||||
import { PureViewCtrl } from '@Views/abstract/pure_view_ctrl';
|
||||
import { UuidString } from '@/../../../../snjs/dist/@types/types';
|
||||
import { TagMutator } from '@/../../../../snjs/dist/@types/models/app/tag';
|
||||
|
||||
type NoteCounts = Partial<Record<string, number>>
|
||||
|
||||
class TagsPanelCtrl extends PureCtrl {
|
||||
class TagsViewCtrl extends PureViewCtrl {
|
||||
|
||||
/** Passed through template */
|
||||
readonly application!: WebApplication
|
||||
@@ -106,6 +105,10 @@ class TagsPanelCtrl extends PureCtrl {
|
||||
});
|
||||
if (!matchingTag || matchingTag.deleted) {
|
||||
this.selectTag(this.state.smartTags[0]);
|
||||
} else {
|
||||
this.setState({
|
||||
selectedTag: matchingTag
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -342,7 +345,7 @@ class TagsPanelCtrl extends PureCtrl {
|
||||
}
|
||||
}
|
||||
|
||||
export class TagsPanel extends WebDirective {
|
||||
export class TagsView extends WebDirective {
|
||||
constructor() {
|
||||
super();
|
||||
this.restrict = 'E';
|
||||
@@ -351,7 +354,7 @@ export class TagsPanel extends WebDirective {
|
||||
};
|
||||
this.template = template;
|
||||
this.replace = true;
|
||||
this.controller = TagsPanelCtrl;
|
||||
this.controller = TagsViewCtrl;
|
||||
this.controllerAs = 'self';
|
||||
this.bindToController = true;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#lock-screen.sn-component
|
||||
.sk-panel
|
||||
.sk-panel-header
|
||||
.sk-panel-header-title Passcode Required
|
||||
.sk-panel-content
|
||||
.sk-panel-section
|
||||
form.sk-panel-form.sk-panel-row(ng-submit='ctrl.submitPasscodeForm($event)')
|
||||
.sk-panel-column.stretch
|
||||
input#passcode-input.center-text.sk-input.contrast(
|
||||
autocomplete='new-password',
|
||||
autofocus='true',
|
||||
ng-model='ctrl.formData.passcode',
|
||||
placeholder='Enter Passcode',
|
||||
should-focus='true',
|
||||
sn-autofocus='true',
|
||||
type='password'
|
||||
)
|
||||
.sk-button-group.stretch.sk-panel-row.form-submit
|
||||
button.sk-button.info(type='submit')
|
||||
.sk-label Unlock
|
||||
.sk-panel-footer
|
||||
#passcode-reset
|
||||
a.sk-a.neutral(
|
||||
ng-click='ctrl.forgotPasscode()',
|
||||
ng-if='!ctrl.formData.showRecovery'
|
||||
) Forgot?
|
||||
div(ng-if='ctrl.formData.showRecovery')
|
||||
.sk-p
|
||||
| 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(
|
||||
ng-click='ctrl.beginDeleteData()'
|
||||
) Delete Local Data
|
||||
@@ -44,7 +44,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<root />
|
||||
<application-group-view />
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/// <reference types="angular" />
|
||||
import { WebApplication } from './../../application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { SNComponent } from 'snjs';
|
||||
import { WebDirective } from './../../types';
|
||||
declare type ComponentModalScope = {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { SNAlertService } from 'snjs';
|
||||
export declare class AlertService extends SNAlertService {
|
||||
alert(title: string, text: string, closeButtonText: string | undefined, onClose: () => void): Promise<unknown>;
|
||||
confirm(title: string, text: string, confirmButtonText: string | undefined, cancelButtonText: string | undefined, onConfirm: () => void, onCancel: () => void, destructive?: boolean): Promise<unknown>;
|
||||
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>;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { SNItem } from 'snjs';
|
||||
export declare class ArchiveManager {
|
||||
private readonly application;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/// <reference types="angular" />
|
||||
import { SNComponent, PurePayload } from 'snjs';
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { ApplicationService, ApplicationEvent } from 'snjs';
|
||||
declare type UpdateObserverCallback = (component: SNComponent) => void;
|
||||
declare type ComponentActivationCallback = (payload: PurePayload) => void;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from './../application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
export declare class LockManager {
|
||||
private application;
|
||||
private unsubState;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { ApplicationService, WebPrefKey } from 'snjs';
|
||||
export declare class PreferencesManager extends ApplicationService {
|
||||
private userPreferences;
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
/// <reference types="angular" />
|
||||
import { WebApplication } from './../application';
|
||||
import { SNTag, SNNote, SNUserPrefs } from 'snjs';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { Editor } from '@/ui_models/editor';
|
||||
export declare enum AppStateEvent {
|
||||
TagChanged = 1,
|
||||
NoteChanged = 2,
|
||||
ActiveEditorChanged = 2,
|
||||
PreferencesChanged = 3,
|
||||
PanelResized = 4,
|
||||
EditorFocused = 5,
|
||||
@@ -29,10 +30,22 @@ export declare class AppState {
|
||||
rootScopeCleanup2: any;
|
||||
onVisibilityChange: any;
|
||||
selectedTag?: SNTag;
|
||||
selectedNote?: SNNote;
|
||||
userPreferences?: SNUserPrefs;
|
||||
multiEditorEnabled: boolean;
|
||||
constructor($rootScope: ng.IRootScopeService, $timeout: ng.ITimeoutService, application: WebApplication);
|
||||
deinit(): void;
|
||||
/**
|
||||
* Creates a new editor if one doesn't exist. If one does, we'll replace the
|
||||
* editor's note with an empty one.
|
||||
*/
|
||||
createEditor(title?: string): void;
|
||||
openEditor(noteUuid: string): Promise<unknown>;
|
||||
getActiveEditor(): Editor;
|
||||
getEditors(): Editor[];
|
||||
closeEditor(editor: Editor): void;
|
||||
closeActiveEditor(): void;
|
||||
closeAllEditors(): void;
|
||||
editorForNote(note: SNNote): Editor | undefined;
|
||||
streamNotesAndTags(): void;
|
||||
addAppEventObserver(): void;
|
||||
isLocked(): boolean;
|
||||
@@ -41,13 +54,11 @@ export declare class AppState {
|
||||
addObserver(callback: ObserverCallback): () => void;
|
||||
notifyEvent(eventName: AppStateEvent, data?: any): Promise<unknown>;
|
||||
setSelectedTag(tag: SNTag): void;
|
||||
setSelectedNote(note?: SNNote): Promise<unknown>;
|
||||
/** Returns the tags that are referncing this note */
|
||||
getNoteTags(note: SNNote): SNTag[];
|
||||
/** Returns the notes this tag references */
|
||||
getTagNotes(tag: SNTag): SNNote[];
|
||||
getSelectedTag(): SNTag | undefined;
|
||||
getSelectedNote(): SNNote | undefined;
|
||||
setUserPreferences(preferences: SNUserPrefs): void;
|
||||
panelDidResize(name: string, collapsed: boolean): void;
|
||||
editorDidFocus(eventSource: EventSource): void;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { FooterStatus } from './../types';
|
||||
import { FooterStatus } from '@/types';
|
||||
declare type StatusCallback = (string: string) => void;
|
||||
export declare class StatusManager {
|
||||
private statuses;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { WebApplication } from '@/application';
|
||||
import { WebApplication } from '@/ui_models/application';
|
||||
import { ApplicationService } from 'snjs';
|
||||
export declare class ThemeManager extends ApplicationService {
|
||||
private activeThemes;
|
||||
|
||||
56
dist/@types/app/assets/javascripts/ui_models/application.d.ts
vendored
Normal file
56
dist/@types/app/assets/javascripts/ui_models/application.d.ts
vendored
Normal file
@@ -0,0 +1,56 @@
|
||||
/// <reference types="angular" />
|
||||
import { EditorGroup } from '@/ui_models/editor_group';
|
||||
import { PasswordWizardType } from '@/types';
|
||||
import { SNApplication, Challenge, ChallengeOrchestrator, ProtectedAction } from 'snjs';
|
||||
import { AppState, DesktopManager, LockManager, ArchiveManager, NativeExtManager, StatusManager, ThemeManager, PreferencesManager, KeyboardManager } from '@/services';
|
||||
declare type WebServices = {
|
||||
appState: AppState;
|
||||
desktopService: DesktopManager;
|
||||
lockService: LockManager;
|
||||
archiveService: ArchiveManager;
|
||||
nativeExtService: NativeExtManager;
|
||||
statusService: StatusManager;
|
||||
themeService: ThemeManager;
|
||||
prefsService: PreferencesManager;
|
||||
keyboardService: KeyboardManager;
|
||||
};
|
||||
export declare class WebApplication extends SNApplication {
|
||||
private $compile?;
|
||||
private scope?;
|
||||
private onDeinit?;
|
||||
private webServices;
|
||||
private currentAuthenticationElement?;
|
||||
editorGroup: EditorGroup;
|
||||
constructor($compile: ng.ICompileService, $timeout: ng.ITimeoutService, scope: ng.IScope, onDeinit: (app: WebApplication) => void);
|
||||
/** @override */
|
||||
deinit(): void;
|
||||
setWebServices(services: WebServices): void;
|
||||
/** @access public */
|
||||
getAppState(): AppState;
|
||||
/** @access public */
|
||||
getDesktopService(): DesktopManager;
|
||||
/** @access public */
|
||||
getLockService(): LockManager;
|
||||
/** @access public */
|
||||
getArchiveService(): ArchiveManager;
|
||||
/** @access public */
|
||||
getNativeExtService(): NativeExtManager;
|
||||
/** @access public */
|
||||
getStatusService(): StatusManager;
|
||||
/** @access public */
|
||||
getThemeService(): ThemeManager;
|
||||
/** @access public */
|
||||
getPrefsService(): PreferencesManager;
|
||||
/** @access public */
|
||||
getKeyboardService(): KeyboardManager;
|
||||
checkForSecurityUpdate(): Promise<boolean>;
|
||||
presentPasswordWizard(type: PasswordWizardType): void;
|
||||
promptForChallenge(challenge: Challenge, orchestrator: ChallengeOrchestrator): void;
|
||||
performProtocolUpgrade(): Promise<void>;
|
||||
presentPrivilegesModal(action: ProtectedAction, onSuccess?: any, onCancel?: any): Promise<void>;
|
||||
presentPrivilegesManagementModal(): void;
|
||||
authenticationInProgress(): boolean;
|
||||
presentPasswordModal(callback: () => void): void;
|
||||
presentRevisionPreviewModal(uuid: string, content: any): void;
|
||||
}
|
||||
export {};
|
||||
26
dist/@types/app/assets/javascripts/ui_models/application_group.d.ts
vendored
Normal file
26
dist/@types/app/assets/javascripts/ui_models/application_group.d.ts
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/// <reference types="angular" />
|
||||
import { WebApplication } from './application';
|
||||
declare type AppManagerChangeCallback = () => void;
|
||||
export declare class ApplicationGroup {
|
||||
$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);
|
||||
private createDefaultApplication;
|
||||
/** @callback */
|
||||
onApplicationDeinit(application: WebApplication): void;
|
||||
private createNewApplication;
|
||||
get application(): WebApplication | undefined;
|
||||
getApplications(): WebApplication[];
|
||||
/**
|
||||
* Notifies observer when the active application has changed.
|
||||
* Any application which is no longer active is destroyed, and
|
||||
* must be removed from the interface.
|
||||
*/
|
||||
addApplicationChangeObserver(callback: AppManagerChangeCallback): void;
|
||||
private notifyObserversOfAppChange;
|
||||
}
|
||||
export {};
|
||||
32
dist/@types/app/assets/javascripts/ui_models/editor.d.ts
vendored
Normal file
32
dist/@types/app/assets/javascripts/ui_models/editor.d.ts
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
import { SNNote, PayloadSource } from 'snjs';
|
||||
import { WebApplication } from './application';
|
||||
export declare class Editor {
|
||||
note: SNNote;
|
||||
private application;
|
||||
private _onNoteChange?;
|
||||
private _onNoteValueChange?;
|
||||
private removeStreamObserver;
|
||||
isTemplateNote: boolean;
|
||||
constructor(application: WebApplication, noteUuid?: string, noteTitle?: string);
|
||||
private handleNoteStream;
|
||||
insertTemplatedNote(): Promise<import("../../../../../snjs/dist/@types").SNItem>;
|
||||
/**
|
||||
* Reverts the editor to a blank state, removing any existing note from view,
|
||||
* and creating a placeholder note.
|
||||
*/
|
||||
reset(noteTitle?: string): Promise<void>;
|
||||
deinit(): void;
|
||||
/**
|
||||
* Register to be notified when the editor's note changes.
|
||||
*/
|
||||
onNoteChange(onNoteChange: () => void): void;
|
||||
/**
|
||||
* Register to be notified when the editor's note's values change
|
||||
* (and thus a new object reference is created)
|
||||
*/
|
||||
onNoteValueChange(onNoteValueChange: (note: SNNote, source?: PayloadSource) => void): void;
|
||||
/**
|
||||
* Sets the editor contents by setting its note.
|
||||
*/
|
||||
setNote(note: SNNote): void;
|
||||
}
|
||||
22
dist/@types/app/assets/javascripts/ui_models/editor_group.d.ts
vendored
Normal file
22
dist/@types/app/assets/javascripts/ui_models/editor_group.d.ts
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { Editor } from './editor';
|
||||
import { WebApplication } from './application';
|
||||
declare type EditorGroupChangeCallback = () => void;
|
||||
export declare class EditorGroup {
|
||||
editors: Editor[];
|
||||
private application;
|
||||
changeObservers: EditorGroupChangeCallback[];
|
||||
constructor(application: WebApplication);
|
||||
deinit(): void;
|
||||
createEditor(noteUuid?: string, noteTitle?: string): void;
|
||||
deleteEditor(editor: Editor): void;
|
||||
closeEditor(editor: Editor): void;
|
||||
closeActiveEditor(): void;
|
||||
closeAllEditors(): void;
|
||||
get activeEditor(): Editor;
|
||||
/**
|
||||
* Notifies observer when the active editor has changed.
|
||||
*/
|
||||
addChangeObserver(callback: EditorGroupChangeCallback): void;
|
||||
private notifyObservers;
|
||||
}
|
||||
export {};
|
||||
36
dist/@types/app/assets/javascripts/views/abstract/pure_view_ctrl.d.ts
vendored
Normal file
36
dist/@types/app/assets/javascripts/views/abstract/pure_view_ctrl.d.ts
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
/// <reference types="angular" />
|
||||
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 {
|
||||
$timeout: ng.ITimeoutService;
|
||||
/** Passed through templates */
|
||||
application?: WebApplication;
|
||||
props: CtrlProps;
|
||||
state: CtrlState;
|
||||
private unsubApp;
|
||||
private unsubState;
|
||||
private stateTimeout;
|
||||
constructor($timeout: ng.ITimeoutService);
|
||||
$onInit(): void;
|
||||
deinit(): void;
|
||||
$onDestroy(): void;
|
||||
get appState(): import("../../services").AppState;
|
||||
/** @private */
|
||||
resetState(): Promise<void>;
|
||||
/** @override */
|
||||
getInitialState(): {};
|
||||
setState(state: CtrlState): Promise<unknown>;
|
||||
updateUI(func: () => void): Promise<void>;
|
||||
initProps(props: CtrlProps): void;
|
||||
addAppStateObserver(): void;
|
||||
onAppStateEvent(eventName: any, data: any): void;
|
||||
addAppEventObserver(): void;
|
||||
onAppEvent(eventName: ApplicationEvent): void;
|
||||
/** @override */
|
||||
onAppStart(): Promise<void>;
|
||||
onAppLaunch(): Promise<void>;
|
||||
onAppKeyChange(): Promise<void>;
|
||||
onAppSync(): void;
|
||||
}
|
||||
4
dist/@types/app/assets/javascripts/views/application/application_view.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/application/application_view.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from '@/types';
|
||||
export declare class ApplicationView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
4
dist/@types/app/assets/javascripts/views/application_group/application_group.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/application_group/application_group.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from '@/types';
|
||||
export declare class ApplicationGroupView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
4
dist/@types/app/assets/javascripts/views/application_group/application_group_view.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/application_group/application_group_view.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from '@/types';
|
||||
export declare class ApplicationGroupView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
2
dist/@types/app/assets/javascripts/views/constants.d.ts
vendored
Normal file
2
dist/@types/app/assets/javascripts/views/constants.d.ts
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export declare const PANEL_NAME_NOTES = "notes";
|
||||
export declare const PANEL_NAME_TAGS = "tags";
|
||||
4
dist/@types/app/assets/javascripts/views/editor/editor_view.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/editor/editor_view.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from '@/types';
|
||||
export declare class EditorView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
4
dist/@types/app/assets/javascripts/views/editor_group/editor_group.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/editor_group/editor_group.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from './../../types';
|
||||
export declare class EditorGroupView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
4
dist/@types/app/assets/javascripts/views/editor_group/editor_group_view.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/editor_group/editor_group_view.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from './../../types';
|
||||
export declare class EditorGroupView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
4
dist/@types/app/assets/javascripts/views/footer/footer_view.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/footer/footer_view.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from '@/types';
|
||||
export declare class FooterView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
8
dist/@types/app/assets/javascripts/views/index.d.ts
vendored
Normal file
8
dist/@types/app/assets/javascripts/views/index.d.ts
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
export { PureViewCtrl } from './abstract/pure_view_ctrl';
|
||||
export { ApplicationGroupView } from './application_group/application_group_view';
|
||||
export { ApplicationView } from './application/application_view';
|
||||
export { EditorGroupView } from './editor_group/editor_group_view';
|
||||
export { EditorView } from './editor/editor_view';
|
||||
export { FooterView } from './footer/footer_view';
|
||||
export { NotesView } from './notes/notes_view';
|
||||
export { TagsView } from './tags/tags_view';
|
||||
10
dist/@types/app/assets/javascripts/views/notes/note_utils.d.ts
vendored
Normal file
10
dist/@types/app/assets/javascripts/views/notes/note_utils.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
import { SNNote, SNTag } from 'snjs';
|
||||
export declare enum NoteSortKey {
|
||||
CreatedAt = "created_at",
|
||||
UpdatedAt = "updated_at",
|
||||
ClientUpdatedAt = "client_updated_at",
|
||||
Title = "title"
|
||||
}
|
||||
export declare function filterAndSortNotes(notes: SNNote[], selectedTag: SNTag, showArchived: boolean, hidePinned: boolean, filterText: string, sortBy: string, reverse: boolean): SNNote[];
|
||||
export declare function filterNotes(notes: SNNote[], selectedTag: SNTag, showArchived: boolean, hidePinned: boolean, filterText: string): SNNote[];
|
||||
export declare function sortNotes(notes: SNNote[] | undefined, sortBy: string, reverse: boolean): SNNote[];
|
||||
4
dist/@types/app/assets/javascripts/views/notes/notes_view.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/notes/notes_view.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from './../../types';
|
||||
export declare class NotesView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
4
dist/@types/app/assets/javascripts/views/tags/tags_view.d.ts
vendored
Normal file
4
dist/@types/app/assets/javascripts/views/tags/tags_view.d.ts
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import { WebDirective } from '@/types';
|
||||
export declare class TagsView extends WebDirective {
|
||||
constructor();
|
||||
}
|
||||
13795
dist/javascripts/app.js
vendored
13795
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
@@ -36,7 +36,7 @@
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<root />
|
||||
<application-group-view />
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
@@ -36,7 +36,9 @@ module.exports = {
|
||||
alias: {
|
||||
'%': path.resolve(__dirname, 'app/assets/templates'),
|
||||
'@': path.resolve(__dirname, 'app/assets/javascripts'),
|
||||
'@Controllers': path.resolve(__dirname, 'app/assets/javascripts/controllers')
|
||||
'@Controllers': path.resolve(__dirname, 'app/assets/javascripts/controllers'),
|
||||
'@Views': path.resolve(__dirname, 'app/assets/javascripts/views'),
|
||||
'@Services': path.resolve(__dirname, 'app/assets/javascripts/services'),
|
||||
}
|
||||
},
|
||||
module: {
|
||||
|
||||
Reference in New Issue
Block a user