@oxygen-cms/ui 2.0.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -135,8 +135,8 @@
|
|
|
135
135
|
|
|
136
136
|
<!-- SLOT: Inline settings (shown between toolbar and editor) -->
|
|
137
137
|
<slot
|
|
138
|
-
name="inline-settings"
|
|
139
138
|
v-if="!isFullscreen"
|
|
139
|
+
name="inline-settings"
|
|
140
140
|
:model="model"
|
|
141
141
|
:is-dirty="isDirty"
|
|
142
142
|
:server-model="serverModel"
|
|
@@ -144,11 +144,12 @@
|
|
|
144
144
|
></slot>
|
|
145
145
|
|
|
146
146
|
<!-- Editor Toolbar -->
|
|
147
|
-
<div
|
|
147
|
+
<div class="has-background-white-bis px-4 py-3 is-flex is-align-items-center" style="border-bottom: 1px solid #dbdbdb; gap: 1rem;">
|
|
148
148
|
<b-field class="mb-0">
|
|
149
149
|
<p class="control">
|
|
150
150
|
<b-button
|
|
151
151
|
:type="editorMode === 'code' ? 'is-dark' : ''"
|
|
152
|
+
:disabled="loading"
|
|
152
153
|
@click="switchEditorMode('code')"
|
|
153
154
|
>
|
|
154
155
|
Code
|
|
@@ -156,6 +157,7 @@
|
|
|
156
157
|
<p class="control">
|
|
157
158
|
<b-button
|
|
158
159
|
:type="editorMode === 'split' ? 'is-dark' : ''"
|
|
160
|
+
:disabled="loading"
|
|
159
161
|
@click="switchEditorMode('split')"
|
|
160
162
|
>
|
|
161
163
|
Split
|
|
@@ -163,31 +165,32 @@
|
|
|
163
165
|
<p class="control">
|
|
164
166
|
<b-button
|
|
165
167
|
:type="editorMode === 'preview' ? 'is-dark' : ''"
|
|
168
|
+
:disabled="loading"
|
|
166
169
|
@click="switchEditorMode('preview')"
|
|
167
170
|
>
|
|
168
171
|
Preview
|
|
169
172
|
</b-button></p>
|
|
170
173
|
</b-field>
|
|
171
174
|
|
|
172
|
-
<b-button icon-left="image" :disabled="editorMode === 'preview'" @click="isMediaModalActive = true">
|
|
175
|
+
<b-button icon-left="image" :disabled="loading || editorMode === 'preview'" @click="isMediaModalActive = true">
|
|
173
176
|
Insert Photo or File
|
|
174
177
|
</b-button>
|
|
175
178
|
|
|
176
|
-
<b-switch v-if="hasFullPagePreview" :value="renderLayout" size="is-small" @input="updateQueryParam('fullPage', $event)">
|
|
179
|
+
<b-switch v-if="hasFullPagePreview" :value="renderLayout" :disabled="loading" size="is-small" @input="updateQueryParam('fullPage', $event)">
|
|
177
180
|
Preview full page
|
|
178
181
|
</b-switch>
|
|
179
182
|
|
|
180
183
|
<b-switch
|
|
181
|
-
:value="isFullscreen" size="is-small" @input="updateQueryParam('fullscreen', $event)"
|
|
184
|
+
:value="isFullscreen" :disabled="loading" size="is-small" @input="updateQueryParam('fullscreen', $event)"
|
|
182
185
|
>Focus</b-switch>
|
|
183
186
|
|
|
184
187
|
<div class="is-flex-grow-1"></div>
|
|
185
188
|
|
|
186
189
|
<b-field>
|
|
187
190
|
<p class="control">
|
|
188
|
-
<b-dropdown position="is-bottom-left" aria-role="menu">
|
|
191
|
+
<b-dropdown position="is-bottom-left" aria-role="menu" :disabled="loading">
|
|
189
192
|
<template #trigger>
|
|
190
|
-
<b-button :label="versionStrategyLabel" icon-right="caret-down" :disabled="!isDirty" />
|
|
193
|
+
<b-button :label="versionStrategyLabel" icon-right="caret-down" :disabled="loading || !isDirty" />
|
|
191
194
|
</template>
|
|
192
195
|
<b-dropdown-item aria-role="menuitem" @click="versionStrategy = 'guess'">
|
|
193
196
|
Create New Version if Needed
|
|
@@ -205,7 +208,7 @@
|
|
|
205
208
|
type="is-primary"
|
|
206
209
|
icon-left="save"
|
|
207
210
|
:loading="saving"
|
|
208
|
-
:disabled="!isDirty"
|
|
211
|
+
:disabled="loading || !isDirty"
|
|
209
212
|
@click="save"
|
|
210
213
|
>
|
|
211
214
|
Save
|
|
@@ -444,7 +447,8 @@ export default {
|
|
|
444
447
|
previewHtml: '',
|
|
445
448
|
previewDebounceTimer: null,
|
|
446
449
|
editingTitle: false,
|
|
447
|
-
editingTitleValue: ''
|
|
450
|
+
editingTitleValue: '',
|
|
451
|
+
isLoadingFromServer: false
|
|
448
452
|
}
|
|
449
453
|
},
|
|
450
454
|
computed: {
|
|
@@ -534,7 +538,12 @@ export default {
|
|
|
534
538
|
watch: {
|
|
535
539
|
'model.content': {
|
|
536
540
|
handler(newVal) {
|
|
537
|
-
console.log('model.content changed, length:', newVal ? newVal.length : 0, 'mode:', this.editorMode);
|
|
541
|
+
console.log('model.content changed, length:', newVal ? newVal.length : 0, 'mode:', this.editorMode, 'isLoadingFromServer:', this.isLoadingFromServer);
|
|
542
|
+
// Skip refresh if we're loading from server - the query watcher or mounted hook will handle it
|
|
543
|
+
if (this.isLoadingFromServer) {
|
|
544
|
+
console.log('Skipping refresh - loading from server');
|
|
545
|
+
return;
|
|
546
|
+
}
|
|
538
547
|
if (this.editorMode === 'split' || this.editorMode === 'preview') {
|
|
539
548
|
this.debouncedRefreshPreview();
|
|
540
549
|
}
|
|
@@ -577,12 +586,19 @@ export default {
|
|
|
577
586
|
},
|
|
578
587
|
async fetchData() {
|
|
579
588
|
this.loading = true;
|
|
589
|
+
this.isLoadingFromServer = true;
|
|
580
590
|
try {
|
|
581
591
|
const response = await this.resourceApi.get(this.resourceId);
|
|
582
592
|
this.setModel(response.item);
|
|
583
593
|
this.editingNonHead = !this.isHeadVersion;
|
|
594
|
+
// Trigger initial preview refresh after data loads
|
|
595
|
+
if (this.editorMode === 'split' || this.editorMode === 'preview') {
|
|
596
|
+
this.refreshPreview();
|
|
597
|
+
}
|
|
584
598
|
} catch (error) {
|
|
585
599
|
console.error('Failed to fetch resource:', error);
|
|
600
|
+
} finally {
|
|
601
|
+
this.isLoadingFromServer = false;
|
|
586
602
|
}
|
|
587
603
|
},
|
|
588
604
|
setModel(model) {
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
|
|
35
35
|
<b-button v-if="admin" @click="isUserPreferencesModalActive = true">Open User Preferences...</b-button>
|
|
36
36
|
|
|
37
|
-
<ShowIfPermitted v-if="!admin" :keys="['user.
|
|
37
|
+
<ShowIfPermitted v-if="!admin" :keys="['user.editor']">
|
|
38
38
|
<b-notification :closable="false" class="bottom-margin">
|
|
39
39
|
<h2 class="subtitle">User Preferences</h2>
|
|
40
40
|
<p>You can modify and personalize certain aspects of this administration interface to suit your own preferences.</p>
|
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
<template>
|
|
2
2
|
<div>
|
|
3
|
-
<h3 class="subtitle">General</h3>
|
|
4
|
-
<PreferencesField label="Font Size" data-key="user.general::fontSize" type="select" default-text="group"></PreferencesField>
|
|
5
3
|
<h3 class="subtitle">Editor</h3>
|
|
6
4
|
<PreferencesField label="Default Mode" data-key="user.editor::defaultMode" type="select" default-text="group"></PreferencesField>
|
|
7
|
-
<PreferencesField label="Overall Theme" data-key="user.editor::theme" type="select" default-text="group"></PreferencesField>
|
|
8
5
|
<h4 class="subtitle is-6">Code Editor</h4>
|
|
9
6
|
<PreferencesField label="Theme" data-key="user.editor::ace.theme" type="select" grouped default-text="group"></PreferencesField>
|
|
10
7
|
<PreferencesField label="Font Size" data-key="user.editor::ace.fontSize" type="select" default-text="group"></PreferencesField>
|
|
@@ -12,8 +9,6 @@
|
|
|
12
9
|
<PreferencesField label="Highlight Active Line" data-key="user.editor::ace.highlightActiveLine" type="switch" default-text="group"></PreferencesField>
|
|
13
10
|
<PreferencesField label="Show Print Margin" data-key="user.editor::ace.showPrintMargin" type="switch" default-text="group"></PreferencesField>
|
|
14
11
|
<PreferencesField label="Show Invisibles" data-key="user.editor::ace.showInvisibles" type="switch" default-text="group"></PreferencesField>
|
|
15
|
-
<h4 class="subtitle is-6">Design Editor</h4>
|
|
16
|
-
<PreferencesField label="Theme" data-key="user.editor::ckeditor.skin" type="select" grouped default-text="group"></PreferencesField>
|
|
17
12
|
</div>
|
|
18
13
|
</template>
|
|
19
14
|
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import LegacyPage from "../components/LegacyPage.vue";
|
|
2
1
|
import { WEB_CONTENT } from "../main.js";
|
|
3
2
|
import PageEdit from "../components/pages/PageEdit.vue";
|
|
4
3
|
import PartialEdit from "../components/partials/PartialEdit.vue";
|
|
@@ -42,17 +41,6 @@ export default function(ui) {
|
|
|
42
41
|
const pagesProps = { displayName: 'Pages', routePrefix: 'pages', inTrash: false, tableComponent: PageTable, actionsComponent: PageActions, singularDisplayName: 'Page', defaultSortField: 'title', defaultSortOrder: 'asc', resourceApi: new PagesApi(), createDropdownComponent: CreatePageDropdown }
|
|
43
42
|
|
|
44
43
|
ui.addAuthenticatedRoutes([
|
|
45
|
-
{
|
|
46
|
-
path: 'pages/:subpath/edit',
|
|
47
|
-
component: LegacyPage,
|
|
48
|
-
props: (route) => {
|
|
49
|
-
return {
|
|
50
|
-
fullPath: route.fullPath,
|
|
51
|
-
legacyPrefix: '/oxygen/view',
|
|
52
|
-
adminPrefix: '/oxygen'
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
},
|
|
56
44
|
{
|
|
57
45
|
path: 'partials/trash',
|
|
58
46
|
name: 'partials.trash',
|
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div class="full-height full-height-container legacy-container">
|
|
3
|
-
<transition name="fade">
|
|
4
|
-
<iframe v-show="!loading" ref="iframe" class="iframe" />
|
|
5
|
-
</transition>
|
|
6
|
-
|
|
7
|
-
<MediaInsertModal :active.sync="isInsertMediaItemModalActive" @close="closeInsertMediaItemModal" @select="onFilesSelected" />
|
|
8
|
-
</div>
|
|
9
|
-
</template>
|
|
10
|
-
|
|
11
|
-
<script>
|
|
12
|
-
import MediaInsertModal from "./media/MediaInsertModal.vue";
|
|
13
|
-
|
|
14
|
-
import {getApiHost, initCsrfCookie, morphToNotification} from "../api";
|
|
15
|
-
import MediaApi from "../MediaApi";
|
|
16
|
-
import {LOGIN_AGAIN_NOTIFICATION} from "../AuthApi";
|
|
17
|
-
|
|
18
|
-
// from https://gist.github.com/hdodov/a87c097216718655ead6cf2969b0dcfa
|
|
19
|
-
|
|
20
|
-
const iframeURLChange = (iframe, callback, legacyPage) => {
|
|
21
|
-
var unloadHandler = function() {
|
|
22
|
-
console.log('[LegacyPage] Starting load');
|
|
23
|
-
legacyPage.loadingPath = 'unknown';
|
|
24
|
-
};
|
|
25
|
-
|
|
26
|
-
function attachUnload() {
|
|
27
|
-
// Remove the unloadHandler in case it was already attached.
|
|
28
|
-
// Otherwise, the change will be dispatched twice.
|
|
29
|
-
iframe.contentWindow.removeEventListener("unload", unloadHandler);
|
|
30
|
-
iframe.contentWindow.addEventListener("unload", unloadHandler);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
iframe.addEventListener("load", attachUnload);
|
|
34
|
-
attachUnload();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// This component manages the tricky/hacky integration of two incompatible GUI systems.
|
|
38
|
-
// Legacy pages are rendered inside an iframe, and legacy pages can transition between each other using SmoothState.js
|
|
39
|
-
// When the iframe location is updated, so is the url of the parent page using this.$router.push()
|
|
40
|
-
|
|
41
|
-
export default {
|
|
42
|
-
name: "LegacyPage",
|
|
43
|
-
components: { MediaInsertModal },
|
|
44
|
-
beforeRouteLeave(to, from, next) {
|
|
45
|
-
window.document.body.style.overflowY = 'auto';
|
|
46
|
-
window.document.documentElement.style.overflowY = 'auto';
|
|
47
|
-
this.$parent.$data.requestedCollapsed = false;
|
|
48
|
-
next();
|
|
49
|
-
},
|
|
50
|
-
props: {
|
|
51
|
-
fullPath: { type: String, required: true },
|
|
52
|
-
legacyPrefix: { type: String, required: true },
|
|
53
|
-
adminPrefix: { type: String, required: true }
|
|
54
|
-
},
|
|
55
|
-
data() {
|
|
56
|
-
return {
|
|
57
|
-
loadingPath: null,
|
|
58
|
-
currentPath: null,
|
|
59
|
-
isInsertMediaItemModalActive: false,
|
|
60
|
-
resolveInsertMediaItems: null,
|
|
61
|
-
rejectInsertMediaItems: null
|
|
62
|
-
}
|
|
63
|
-
},
|
|
64
|
-
computed: {
|
|
65
|
-
loading() { return this.loadingPath !== null; },
|
|
66
|
-
userPreferences() { return this.$store.getters.userPreferences; }
|
|
67
|
-
},
|
|
68
|
-
'watch': {
|
|
69
|
-
'fullPath': 'onFullPathChanged'
|
|
70
|
-
},
|
|
71
|
-
async mounted() {
|
|
72
|
-
this.loadingPath = 'prefs';
|
|
73
|
-
|
|
74
|
-
window.document.body.style.overflowY = 'hidden';
|
|
75
|
-
window.document.documentElement.style.overflowY = 'hidden';
|
|
76
|
-
let iframe = this.$refs.iframe;
|
|
77
|
-
|
|
78
|
-
iframeURLChange(iframe, this.onNavigated.bind(this), this);
|
|
79
|
-
|
|
80
|
-
this.loadPath(this.$route.fullPath);
|
|
81
|
-
|
|
82
|
-
iframe.addEventListener('load', this.onLoaded.bind(this));
|
|
83
|
-
if(iframe.contentDocument.readyState === "complete") {
|
|
84
|
-
console.warn('[LegacyPage] mounted: page was already loaded - perhaps this page was cached?');
|
|
85
|
-
await this.onLoaded();
|
|
86
|
-
}
|
|
87
|
-
},
|
|
88
|
-
unmounted() {
|
|
89
|
-
this.$parent.$data.requestedCollapsed = false;
|
|
90
|
-
},
|
|
91
|
-
methods: {
|
|
92
|
-
onFullPathChanged(newFullPath) {
|
|
93
|
-
console.log('Route changed', );
|
|
94
|
-
this.loadPath(newFullPath);
|
|
95
|
-
},
|
|
96
|
-
setupIframeIntegrations() {
|
|
97
|
-
console.log('[LegacyPage] Setting up iframe integrations for', this.$refs.iframe.contentWindow.location.href);
|
|
98
|
-
let elem = this.$refs.iframe;
|
|
99
|
-
elem.contentWindow.Oxygen = elem.contentWindow.Oxygen || {};
|
|
100
|
-
elem.contentWindow.Oxygen.user = this.userPreferences.preferences;
|
|
101
|
-
elem.contentWindow.Oxygen.onNavigationBegin = this.onNavigated.bind(this);
|
|
102
|
-
elem.contentWindow.Oxygen.onNavigationEnd = this.onLoaded.bind(this);
|
|
103
|
-
elem.contentWindow.Oxygen.notify = this.showInnerNotification.bind(this);
|
|
104
|
-
elem.contentWindow.Oxygen.openAlertDialog = this.openAlertDialog.bind(this);
|
|
105
|
-
elem.contentWindow.Oxygen.hardRedirect = this.hardRedirect.bind(this);
|
|
106
|
-
elem.contentWindow.Oxygen.insertMediaItem = this.openInsertMediaItemModal.bind(this);
|
|
107
|
-
elem.contentWindow.Oxygen.openConfirmDialog = this.openConfirmDialog.bind(this);
|
|
108
|
-
elem.contentWindow.Oxygen.popState = this.popState.bind(this);
|
|
109
|
-
elem.contentWindow.Oxygen.onToggleFullscreen = this.onToggleFullscreen.bind(this);
|
|
110
|
-
|
|
111
|
-
if(elem.contentWindow.Oxygen.onLoadedInsideIFrame) {
|
|
112
|
-
elem.contentWindow.Oxygen.onLoadedInsideIFrame();
|
|
113
|
-
} else {
|
|
114
|
-
console.warn('[LegacyPage] no onLoadedInsideIFrame callback set');
|
|
115
|
-
}
|
|
116
|
-
},
|
|
117
|
-
fullURLToVuePath(url) {
|
|
118
|
-
let urlObj = new URL(url);
|
|
119
|
-
let urlString = urlObj.toString();
|
|
120
|
-
if(urlObj.pathname.startsWith(this.legacyPrefix)) {
|
|
121
|
-
let loc = urlString.split(this.legacyPrefix)[1];
|
|
122
|
-
return { loadInside: 'iframe', location: this.adminPrefix + loc, locationWithoutPrefix: loc };
|
|
123
|
-
} else if(urlObj.pathname.startsWith(this.adminPrefix)) {
|
|
124
|
-
return { loadInside: 'vue', location: urlString.split(this.adminPrefix)[1] };
|
|
125
|
-
} else {
|
|
126
|
-
return { loadInside: false, location: urlString };
|
|
127
|
-
}
|
|
128
|
-
},
|
|
129
|
-
vuePathToURL(path) {
|
|
130
|
-
return getApiHost() + this.legacyPrefix.replace(/^\//, '') + path;
|
|
131
|
-
},
|
|
132
|
-
// We detect when the iframe url changes, and update our window accordingly...
|
|
133
|
-
onNavigated(newURL) {
|
|
134
|
-
console.log('[LegacyPage] Navigated to ' + newURL);
|
|
135
|
-
},
|
|
136
|
-
showInnerNotification(data) {
|
|
137
|
-
this.$buefy.notification.open(morphToNotification(data));
|
|
138
|
-
},
|
|
139
|
-
openAlertDialog(message) {
|
|
140
|
-
this.$buefy.dialog.alert({
|
|
141
|
-
message: message,
|
|
142
|
-
size: 'is-small'
|
|
143
|
-
});
|
|
144
|
-
},
|
|
145
|
-
openConfirmDialog(options) {
|
|
146
|
-
this.$buefy.dialog.confirm(options);
|
|
147
|
-
},
|
|
148
|
-
popState() {
|
|
149
|
-
this.$router.back();
|
|
150
|
-
},
|
|
151
|
-
async onLoaded() {
|
|
152
|
-
let path = this.$refs.iframe.contentWindow.location.href;
|
|
153
|
-
if(path === 'about:blank') { return; }
|
|
154
|
-
console.log('[LegacyPage] Loaded', path);
|
|
155
|
-
|
|
156
|
-
if(path !== this.currentPath) {
|
|
157
|
-
let { loadInside, location } = this.fullURLToVuePath(path);
|
|
158
|
-
console.log('[LegacyPage] ', 'loadInside:', loadInside, 'location:', location);
|
|
159
|
-
if(loadInside === 'iframe') {
|
|
160
|
-
window.history.pushState({}, "", location);
|
|
161
|
-
} else if(loadInside === 'vue') {
|
|
162
|
-
if(location.startsWith('/auth/login?location=')) {
|
|
163
|
-
// If the legacy page is redirecting us to login,
|
|
164
|
-
// then that must be because our auth expired/failed.
|
|
165
|
-
// So we explicitly log ourselves out, and redirect to the login page.
|
|
166
|
-
let redirectTo = this.fullURLToVuePath(this.currentPath);
|
|
167
|
-
if(redirectTo.loadInside !== 'iframe') { throw new Error("this.currentPath was not inside iframe"); }
|
|
168
|
-
console.log("Requested redirect to /auth/login . Clearing user state first", redirectTo);
|
|
169
|
-
this.$store.commit('setUser', null);
|
|
170
|
-
this.$buefy.notification.open(LOGIN_AGAIN_NOTIFICATION);
|
|
171
|
-
await initCsrfCookie();
|
|
172
|
-
location = { name: 'login', query: { redirect: redirectTo.locationWithoutPrefix } };
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
await this.$router.push(location);
|
|
176
|
-
return;
|
|
177
|
-
} else {
|
|
178
|
-
// load outside of iframe
|
|
179
|
-
window.location = location;
|
|
180
|
-
return;
|
|
181
|
-
}
|
|
182
|
-
this.currentPath = path;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
document.title = this.$refs.iframe.contentDocument.title;
|
|
186
|
-
this.setupIframeIntegrations();
|
|
187
|
-
|
|
188
|
-
this.loadingPath = null;
|
|
189
|
-
},
|
|
190
|
-
loadPath(routePath) {
|
|
191
|
-
let path = this.vuePathToURL(routePath);
|
|
192
|
-
if(path.endsWith('/oxygen/view/auth/login')) {
|
|
193
|
-
console.log('[LegacyPage] Need to login again, redirecting...');
|
|
194
|
-
window.location.replace('/oxygen/auth/login');
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
console.log('[LegacyPage] Loading', path);
|
|
198
|
-
|
|
199
|
-
this.loadingPath = path;
|
|
200
|
-
|
|
201
|
-
let elem = this.$refs.iframe;
|
|
202
|
-
if(elem.src !== path) {
|
|
203
|
-
// load the page from scratch
|
|
204
|
-
elem.src = path;
|
|
205
|
-
}
|
|
206
|
-
},
|
|
207
|
-
hardRedirect(loc) {
|
|
208
|
-
window.location.replace(loc);
|
|
209
|
-
},
|
|
210
|
-
openInsertMediaItemModal() {
|
|
211
|
-
this.isInsertMediaItemModalActive = true;
|
|
212
|
-
return new Promise((resolve, reject) => {
|
|
213
|
-
this.resolveInsertMediaItems = resolve;
|
|
214
|
-
this.rejectInsertMediaItems = reject;
|
|
215
|
-
});
|
|
216
|
-
},
|
|
217
|
-
closeInsertMediaItemModal() {
|
|
218
|
-
this.rejectInsertMediaItems({ message: 'modal closed' });
|
|
219
|
-
this.isInsertMediaItemModalActive = false;
|
|
220
|
-
},
|
|
221
|
-
onFilesSelected(files) {
|
|
222
|
-
let include = files.map(item => MediaApi.generateIncludeStatement(item)).join("\n") + "\n";
|
|
223
|
-
let filenames = files.map(item => item.fullPath).join(",");
|
|
224
|
-
this.resolveInsertMediaItems(include);
|
|
225
|
-
this.isInsertMediaItemModalActive = false;
|
|
226
|
-
this.$buefy.toast.open({
|
|
227
|
-
message: 'Inserted ' + filenames,
|
|
228
|
-
type: 'is-info',
|
|
229
|
-
queue: false
|
|
230
|
-
});
|
|
231
|
-
},
|
|
232
|
-
onToggleFullscreen(mode) {
|
|
233
|
-
this.$parent.$data.requestedCollapsed = mode;
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
</script>
|
|
238
|
-
|
|
239
|
-
<style scoped lang="scss">
|
|
240
|
-
@import './util.css';
|
|
241
|
-
@import '../styles/_variables.scss';
|
|
242
|
-
|
|
243
|
-
.iframe {
|
|
244
|
-
flex: 1;
|
|
245
|
-
width: 100%;
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
.hidden {
|
|
249
|
-
transition: opacity 1s ease, visibility 1s ease;
|
|
250
|
-
opacity: 0;
|
|
251
|
-
visibility: hidden;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
.visible {
|
|
255
|
-
opacity: 1;
|
|
256
|
-
visibility: visible;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
.legacy-container {
|
|
260
|
-
position: relative;
|
|
261
|
-
background-color: $grey-lightest;
|
|
262
|
-
}
|
|
263
|
-
</style>
|