diff --git a/app/assets/javascripts/app.ts b/app/assets/javascripts/app.ts index f93fd2414..7b7273056 100644 --- a/app/assets/javascripts/app.ts +++ b/app/assets/javascripts/app.ts @@ -43,6 +43,7 @@ import { MenuRow, PanelResizer, PasswordWizard, + PermissionsModal, RevisionPreviewModal, HistoryMenu, SyncResolutionMenu, @@ -138,6 +139,7 @@ const startApplication: StartApplication = async function startApplication( .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()) diff --git a/app/assets/javascripts/directives/views/index.ts b/app/assets/javascripts/directives/views/index.ts index 386e123d1..99931e2bb 100644 --- a/app/assets/javascripts/directives/views/index.ts +++ b/app/assets/javascripts/directives/views/index.ts @@ -7,6 +7,7 @@ export { InputModal } from './inputModal'; export { MenuRow } from './menuRow'; export { PanelResizer } from './panelResizer'; export { PasswordWizard } from './passwordWizard'; +export { PermissionsModal } from './permissionsModal'; export { RevisionPreviewModal } from './revisionPreviewModal'; export { HistoryMenu } from './historyMenu'; export { SyncResolutionMenu } from './syncResolutionMenu'; diff --git a/app/assets/javascripts/directives/views/permissionsModal.ts b/app/assets/javascripts/directives/views/permissionsModal.ts new file mode 100644 index 000000000..b547fec05 --- /dev/null +++ b/app/assets/javascripts/directives/views/permissionsModal.ts @@ -0,0 +1,47 @@ +import { WebDirective } from './../../types'; +import template from '%/directives/permissions-modal.pug'; + +class PermissionsModalCtrl { + + $element: JQLite + callback!: (success: boolean) => void + + /* @ngInject */ + constructor($element: JQLite) { + this.$element = $element; + } + + dismiss() { + const elem = this.$element; + const scope = elem.scope(); + scope.$destroy(); + elem.remove(); + } + + accept() { + this.callback(true); + this.dismiss(); + } + + deny() { + this.callback(false); + this.dismiss(); + } +} + +export class PermissionsModal extends WebDirective { + constructor() { + super(); + this.restrict = 'E'; + this.template = template; + this.controller = PermissionsModalCtrl; + this.controllerAs = 'ctrl'; + this.bindToController = true; + this.scope = { + show: '=', + component: '=', + permissionsString: '=', + callback: '=' + }; + } +} diff --git a/app/assets/javascripts/services/archiveManager.ts b/app/assets/javascripts/services/archiveManager.ts index e8f5f6de1..d80635a1d 100644 --- a/app/assets/javascripts/services/archiveManager.ts +++ b/app/assets/javascripts/services/archiveManager.ts @@ -7,25 +7,21 @@ import { PayloadContent, } from '@standardnotes/snjs'; -function sanitizeFileName(name: string) { - return name - .replace(/\//g, '') - .replace(/\\+/g, '') - .replace(/:/g, ' ') - .replace(/\|/g, ' ') - .replace(/\./g, ' '); -} - -function zippableTxtName(name: string, suffix = ''): string { - const sanitizedName = sanitizeFileName(name); - const nameEnd = suffix + '.txt'; +function zippableTxtName(name: string, suffix = ""): string { + const sanitizedName = name + .replace(/\//g, '') + .replace(/\\+/g, '') + .replace(/:/g, ' ') + .replace(/\./g, ' '); + const nameEnd = suffix + ".txt"; const maxFileNameLength = 255; return sanitizedName.slice(0, maxFileNameLength - nameEnd.length) + nameEnd; } export class ArchiveManager { - private readonly application: WebApplication; - private textFile?: string; + + private readonly application: WebApplication + private textFile?: string constructor(application: WebApplication) { this.application = application; @@ -40,9 +36,10 @@ export class ArchiveManager { if (!data) { return; } - const blobData = new Blob([JSON.stringify(data, null, 2)], { - type: 'text/json', - }); + const blobData = new Blob( + [JSON.stringify(data, null, 2)], + { type: 'text/json' } + ); if (encrypted) { this.downloadData( blobData, @@ -88,18 +85,21 @@ export class ArchiveManager { }); } - private async downloadZippedDecryptedItems(data: BackupFile) { + private async downloadZippedDecryptedItems( + data: BackupFile + ) { await this.loadZip(); const items = data.items; this.zip.createWriter( new this.zip.BlobWriter('application/zip'), async (zipWriter: any) => { await new Promise((resolve) => { - const blob = new Blob([JSON.stringify(data, null, 2)], { - type: 'text/plain', - }); + const blob = new Blob( + [JSON.stringify(data, null, 2)], + { type: 'text/plain' } + ); const fileName = zippableTxtName( - 'Standard Notes Backup and Import File' + 'Standard Notes Backup and Import File.txt' ); zipWriter.add(fileName, new this.zip.BlobReader(blob), resolve); }); @@ -120,8 +120,7 @@ export class ArchiveManager { name = ''; } const blob = new Blob([contents], { type: 'text/plain' }); - const fileName = - `Items/${sanitizeFileName(item.content_type)}/` + + const fileName = `Items/${item.content_type}/` + zippableTxtName(name, `-${item.uuid.split('-')[0]}`); zipWriter.add(fileName, new this.zip.BlobReader(blob), () => { index++; @@ -139,9 +138,7 @@ export class ArchiveManager { }); }; nextFile(); - }, - onerror - ); + }, onerror); } private hrefForData(data: Blob) { diff --git a/app/assets/templates/directives/permissions-modal.pug b/app/assets/templates/directives/permissions-modal.pug new file mode 100644 index 000000000..52f452083 --- /dev/null +++ b/app/assets/templates/directives/permissions-modal.pug @@ -0,0 +1,26 @@ +.sk-modal-background(ng-click='ctrl.deny()') +#permissions-modal.sk-modal-content + .sn-component + .sk-panel + .sk-panel-header + .sk-panel-header-title Activate Extension + a.sk-a.info.close-button(ng-click='ctrl.deny()') Cancel + .sk-panel-content + .sk-panel-section + .sk-panel-row + .sk-h2 + strong {{ctrl.component.name}} + | would like to interact with your + | {{ctrl.permissionsString}} + .sk-panel-row + p.sk-p + | Extensions use an offline messaging system to communicate. Learn more at + a.sk-a.info( + href='https://standardnotes.org/permissions', + rel='noopener', + target='_blank' + ) https://standardnotes.org/permissions. + .sk-panel-footer + button.sn-button.info.block.w-full.text-base.py-3( + ng-click='ctrl.accept()' + ) Continue diff --git a/package.json b/package.json index 869209923..bdfa4a1a1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "standard-notes-web", - "version": "3.6.3", + "version": "3.6.4", "license": "AGPL-3.0-or-later", "repository": { "type": "git",