Files
standardnotes-app-web/app/assets/javascripts/app.ts
Aman Harwara b932e2a45e feat: Add new "Change Editor" option to note context menu (#823)
* feat: add editor icon

* refactor: remove 'any' type and format

* refactor: move NotesOptions and add ChangeEditorOption

* refactor: fix type for using regular RefObject<T>

* feat: add hide-if-last-child util class

* feat: add Change Editor option

* feat: make radio btn gray if not checked

* fix: accordion menu header and item sizing/spacing

* feat: add Escape key to KeyboardKey enum

* refactor: Remove Editor Menu

* feat: add editor select functionality

* refactor: move plain editor name to constant

* feat: add premium editors with modal if no subscription

refactor: simplify menu group creation

* feat: show alert when switching to non-interchangeable editor

* fix: change editor menu going out of bounds

* feat: increase group header & editor item size

* fix: change editor menu close on blur

* refactor: Use KeyboardKey enum & remove else statement

* feat: add keyboard navigation to change editor menu

* fix: editor menu separators

* feat: improve change editor menu sizing & spacing

* feat: show alert only if editor is not interchangeable

* feat: don't show alert when switching to/from plain editor

* chore: bump snjs version

* feat: temporarily remove change editor alert

* feat: dynamically get footer height

* refactor: move magic number to const

* refactor: move constants to constants file

* feat: use const instead of magic number
2022-01-28 14:23:39 -06:00

225 lines
7.5 KiB
TypeScript

'use strict';
declare global {
interface Window {
// eslint-disable-next-line camelcase
_bugsnag_api_key?: string;
// eslint-disable-next-line camelcase
_purchase_url?: string;
// eslint-disable-next-line camelcase
_plans_url?: string;
// eslint-disable-next-line camelcase
_dashboard_url?: string;
// eslint-disable-next-line camelcase
_default_sync_server: string;
// eslint-disable-next-line camelcase
_enable_unfinished_features: boolean;
// eslint-disable-next-line camelcase
_websocket_url: string;
startApplication?: StartApplication;
_devAccountEmail?: string;
_devAccountPassword?: string;
_devAccountServer?: string;
}
}
import { ComponentViewDirective } from '@/components/ComponentView';
import { NavigationDirective } from '@/components/Navigation';
import { PinNoteButtonDirective } from '@/components/PinNoteButton';
import { IsWebPlatform, WebAppVersion } from '@/version';
import {
ApplicationGroupView,
ApplicationView,
ChallengeModal,
FooterView,
NoteGroupViewDirective,
NoteViewDirective,
} from '@/views';
import { SNLog } from '@standardnotes/snjs';
import angular from 'angular';
import { AccountMenuDirective } from './components/AccountMenu';
import { ConfirmSignoutDirective } from './components/ConfirmSignoutModal';
import { IconDirective } from './components/Icon';
import { MultipleSelectedNotesDirective } from './components/MultipleSelectedNotes';
import { NoAccountWarningDirective } from './components/NoAccountWarning';
import { NotesContextMenuDirective } from './components/NotesContextMenu';
import { NotesListOptionsDirective } from './components/NotesListOptionsMenu';
import { NotesOptionsPanelDirective } from './components/NotesOptionsPanel';
import { NotesViewDirective } from './components/NotesView';
import { NoteTagsContainerDirective } from './components/NoteTagsContainer';
import { ProtectedNoteOverlayDirective } from './components/ProtectedNoteOverlay';
import { QuickSettingsMenuDirective } from './components/QuickSettingsMenu/QuickSettingsMenu';
import { SearchOptionsDirective } from './components/SearchOptions';
import { SessionsModalDirective } from './components/SessionsModal';
import {
autofocus,
clickOutside,
delayHide,
elemReady,
fileChange,
lowercase,
selectOnFocus,
snEnter,
} from './directives/functional';
import {
ActionsMenu,
HistoryMenu,
InputModal,
MenuRow,
PanelResizer,
PasswordWizard,
PermissionsModal,
RevisionPreviewModal,
SyncResolutionMenu,
} from './directives/views';
import { trusted } from './filters';
import { PreferencesDirective } from './preferences';
import { PurchaseFlowDirective } from './purchaseFlow';
import { configRoutes } from './routes';
import { Bridge } from './services/bridge';
import { BrowserBridge } from './services/browserBridge';
import { startErrorReporting } from './services/errorReporting';
import { StartApplication } from './startApplication';
import { ApplicationGroup } from './ui_models/application_group';
import { isDev } from './utils';
import { AccountSwitcher } from './views/account_switcher/account_switcher';
function reloadHiddenFirefoxTab(): boolean {
/**
* For Firefox pinned tab issue:
* When a new browser session is started, and SN is in a pinned tab,
* SN exhibits strange behavior until the tab is reloaded.
*/
if (
document.hidden &&
navigator.userAgent.toLowerCase().includes('firefox')
) {
document.addEventListener('visibilitychange', () => {
if (!document.hidden) {
location.reload();
}
});
return true;
} else {
return false;
}
}
const startApplication: StartApplication = async function startApplication(
defaultSyncServerHost: string,
bridge: Bridge,
enableUnfinishedFeatures: boolean,
webSocketUrl: string
) {
if (reloadHiddenFirefoxTab()) {
return;
}
SNLog.onLog = console.log;
startErrorReporting();
angular.module('app', []);
// Config
angular
.module('app')
.config(configRoutes)
.constant('bridge', bridge)
.constant('defaultSyncServerHost', defaultSyncServerHost)
.constant('appVersion', bridge.appVersion)
.constant('enableUnfinishedFeatures', enableUnfinishedFeatures)
.constant('webSocketUrl', webSocketUrl);
// Controllers
angular
.module('app')
.directive('applicationGroupView', () => new ApplicationGroupView())
.directive('applicationView', () => new ApplicationView())
.directive('noteGroupView', () => new NoteGroupViewDirective())
.directive('noteView', () => new NoteViewDirective())
.directive('footerView', () => new FooterView());
// Directives - Functional
angular
.module('app')
.directive('snAutofocus', ['$timeout', autofocus])
.directive('clickOutside', ['$document', clickOutside])
.directive('delayHide', delayHide)
.directive('elemReady', elemReady)
.directive('fileChange', fileChange)
.directive('lowercase', lowercase)
.directive('selectOnFocus', ['$window', selectOnFocus])
.directive('snEnter', snEnter);
// Directives - Views
angular
.module('app')
.directive('accountSwitcher', () => new AccountSwitcher())
.directive('actionsMenu', () => new ActionsMenu())
.directive('challengeModal', () => new ChallengeModal())
.directive('componentView', ComponentViewDirective)
.directive('inputModal', () => new InputModal())
.directive('menuRow', () => new MenuRow())
.directive('panelResizer', () => new PanelResizer())
.directive('passwordWizard', () => new PasswordWizard())
.directive('permissionsModal', () => new PermissionsModal())
.directive('revisionPreviewModal', () => new RevisionPreviewModal())
.directive('historyMenu', () => new HistoryMenu())
.directive('syncResolutionMenu', () => new SyncResolutionMenu())
.directive('sessionsModal', SessionsModalDirective)
.directive('accountMenu', AccountMenuDirective)
.directive('quickSettingsMenu', QuickSettingsMenuDirective)
.directive('noAccountWarning', NoAccountWarningDirective)
.directive('protectedNotePanel', ProtectedNoteOverlayDirective)
.directive('searchOptions', SearchOptionsDirective)
.directive('confirmSignout', ConfirmSignoutDirective)
.directive('multipleSelectedNotesPanel', MultipleSelectedNotesDirective)
.directive('notesContextMenu', NotesContextMenuDirective)
.directive('notesOptionsPanel', NotesOptionsPanelDirective)
.directive('notesListOptionsMenu', NotesListOptionsDirective)
.directive('icon', IconDirective)
.directive('noteTagsContainer', NoteTagsContainerDirective)
.directive('navigation', NavigationDirective)
.directive('preferences', PreferencesDirective)
.directive('purchaseFlow', PurchaseFlowDirective)
.directive('notesView', NotesViewDirective)
.directive('pinNoteButton', PinNoteButtonDirective);
// Filters
angular.module('app').filter('trusted', ['$sce', trusted]);
// Services
angular.module('app').service('mainApplicationGroup', ApplicationGroup);
// Debug
if (isDev) {
Object.defineProperties(window, {
application: {
get: () =>
(
angular
.element(document)
.injector()
.get('mainApplicationGroup') as any
).primaryApplication,
},
});
}
angular.element(document).ready(() => {
angular.bootstrap(document, ['app']);
});
};
if (IsWebPlatform) {
startApplication(
window._default_sync_server,
new BrowserBridge(WebAppVersion),
window._enable_unfinished_features,
window._websocket_url
);
} else {
window.startApplication = startApplication;
}