mirror of
https://github.com/nasa/openmct.git
synced 2025-06-25 18:50:11 +00:00
Compare commits
16 Commits
troublesho
...
notebook-p
Author | SHA1 | Date | |
---|---|---|---|
e0ce4832f7 | |||
cc947de500 | |||
46701d8dd5 | |||
adc2326429 | |||
97eded21da | |||
670795201f | |||
cdcd4bb27e | |||
5be3d7c091 | |||
7fd83ea817 | |||
dfb57327ed | |||
9819eba586 | |||
ba84028fad | |||
000a9d36ef | |||
c43518fb55 | |||
f850c3c649 | |||
1f6476ec09 |
@ -30,7 +30,6 @@ define([
|
||||
"./src/controllers/CompositeController",
|
||||
"./src/controllers/ColorController",
|
||||
"./src/controllers/DialogButtonController",
|
||||
"./src/controllers/SnapshotPreviewController",
|
||||
"./res/templates/controls/autocomplete.html",
|
||||
"./res/templates/controls/checkbox.html",
|
||||
"./res/templates/controls/datetime.html",
|
||||
@ -44,8 +43,7 @@ define([
|
||||
"./res/templates/controls/menu-button.html",
|
||||
"./res/templates/controls/dialog.html",
|
||||
"./res/templates/controls/radio.html",
|
||||
"./res/templates/controls/file-input.html",
|
||||
"./res/templates/controls/snap-view.html"
|
||||
"./res/templates/controls/file-input.html"
|
||||
], function (
|
||||
MCTForm,
|
||||
MCTControl,
|
||||
@ -56,7 +54,6 @@ define([
|
||||
CompositeController,
|
||||
ColorController,
|
||||
DialogButtonController,
|
||||
SnapshotPreviewController,
|
||||
autocompleteTemplate,
|
||||
checkboxTemplate,
|
||||
datetimeTemplate,
|
||||
@ -70,8 +67,7 @@ define([
|
||||
menuButtonTemplate,
|
||||
dialogTemplate,
|
||||
radioTemplate,
|
||||
fileInputTemplate,
|
||||
snapViewTemplate
|
||||
fileInputTemplate
|
||||
) {
|
||||
|
||||
return {
|
||||
@ -157,10 +153,6 @@ define([
|
||||
{
|
||||
"key": "file-input",
|
||||
"template": fileInputTemplate
|
||||
},
|
||||
{
|
||||
"key": "snap-view",
|
||||
"template": snapViewTemplate
|
||||
}
|
||||
],
|
||||
"controllers": [
|
||||
@ -194,14 +186,6 @@ define([
|
||||
"$scope",
|
||||
"dialogService"
|
||||
]
|
||||
},
|
||||
{
|
||||
"key": "SnapshotPreviewController",
|
||||
"implementation": SnapshotPreviewController,
|
||||
"depends": [
|
||||
"$scope",
|
||||
"openmct"
|
||||
]
|
||||
}
|
||||
],
|
||||
"components": [
|
||||
|
@ -1,36 +0,0 @@
|
||||
<!--
|
||||
Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
as represented by the Administrator of the National Aeronautics and Space
|
||||
Administration. All rights reserved.
|
||||
|
||||
Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
http://www.apache.org/licenses/LICENSE-2.0.
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
License for the specific language governing permissions and limitations
|
||||
under the License.
|
||||
|
||||
Open MCT includes source code licensed under additional open source
|
||||
licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
this source code distribution or the Licensing information page available
|
||||
at runtime from the About dialog for additional information.
|
||||
-->
|
||||
<span ng-controller="SnapshotPreviewController"
|
||||
class='form-control shell'>
|
||||
<span class='field control {{structure.cssClass}}'>
|
||||
<image
|
||||
class="c-ne__embed__snap-thumb"
|
||||
src="{{imageUrl || structure.src}}"
|
||||
ng-click="previewImage(imageUrl || structure.src)"
|
||||
name="mctControl">
|
||||
</image>
|
||||
<br>
|
||||
<a title="Annotate" class="s-button icon-pencil" ng-click="annotateImage(ngModel, field, imageUrl || structure.src)">
|
||||
<span class="title-label">Annotate</span>
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
@ -1,131 +0,0 @@
|
||||
/*****************************************************************************
|
||||
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||
* as represented by the Administrator of the National Aeronautics and Space
|
||||
* Administration. All rights reserved.
|
||||
*
|
||||
* Open MCT is licensed under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
* Open MCT includes source code licensed under additional open source
|
||||
* licenses. See the Open Source Licenses file (LICENSES.md) included with
|
||||
* this source code distribution or the Licensing information page available
|
||||
* at runtime from the About dialog for additional information.
|
||||
*****************************************************************************/
|
||||
|
||||
define(
|
||||
[
|
||||
'painterro'
|
||||
],
|
||||
function (Painterro) {
|
||||
|
||||
function SnapshotPreviewController($scope, openmct) {
|
||||
|
||||
$scope.previewImage = function (imageUrl) {
|
||||
let imageDiv = document.createElement('div');
|
||||
imageDiv.classList = 'image-main s-image-main';
|
||||
imageDiv.style.backgroundImage = `url(${imageUrl})`;
|
||||
|
||||
let previewImageOverlay = openmct.overlays.overlay(
|
||||
{
|
||||
element: imageDiv,
|
||||
size: 'large',
|
||||
buttons: [
|
||||
{
|
||||
label: 'Done',
|
||||
callback: function () {
|
||||
previewImageOverlay.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
$scope.annotateImage = function (ngModel, field, imageUrl) {
|
||||
$scope.imageUrl = imageUrl;
|
||||
|
||||
let div = document.createElement('div'),
|
||||
painterroInstance = {},
|
||||
save = false;
|
||||
|
||||
div.id = 'snap-annotation';
|
||||
|
||||
let annotateImageOverlay = openmct.overlays.overlay(
|
||||
{
|
||||
element: div,
|
||||
size: 'large',
|
||||
buttons: [
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: function () {
|
||||
save = false;
|
||||
painterroInstance.save();
|
||||
annotateImageOverlay.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Save',
|
||||
callback: function () {
|
||||
save = true;
|
||||
painterroInstance.save();
|
||||
annotateImageOverlay.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
);
|
||||
|
||||
painterroInstance = Painterro({
|
||||
id: 'snap-annotation',
|
||||
activeColor: '#ff0000',
|
||||
activeColorAlpha: 1.0,
|
||||
activeFillColor: '#fff',
|
||||
activeFillColorAlpha: 0.0,
|
||||
backgroundFillColor: '#000',
|
||||
backgroundFillColorAlpha: 0.0,
|
||||
defaultFontSize: 16,
|
||||
defaultLineWidth: 2,
|
||||
defaultTool: 'ellipse',
|
||||
hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
|
||||
translation: {
|
||||
name: 'en',
|
||||
strings: {
|
||||
lineColor: 'Line',
|
||||
fillColor: 'Fill',
|
||||
lineWidth: 'Size',
|
||||
textColor: 'Color',
|
||||
fontSize: 'Size',
|
||||
fontStyle: 'Style'
|
||||
}
|
||||
},
|
||||
saveHandler: function (image, done) {
|
||||
if (save) {
|
||||
let url = image.asBlob(),
|
||||
reader = new window.FileReader();
|
||||
|
||||
reader.readAsDataURL(url);
|
||||
reader.onloadend = function () {
|
||||
$scope.imageUrl = reader.result;
|
||||
ngModel[field] = reader.result;
|
||||
};
|
||||
} else {
|
||||
ngModel.field = imageUrl;
|
||||
console.warn('You cancelled the annotation!!!');
|
||||
}
|
||||
done(true);
|
||||
}
|
||||
}).show(imageUrl);
|
||||
};
|
||||
}
|
||||
|
||||
return SnapshotPreviewController;
|
||||
}
|
||||
);
|
21
src/plugins/notebook/components/menu-items.vue
Normal file
21
src/plugins/notebook/components/menu-items.vue
Normal file
@ -0,0 +1,21 @@
|
||||
<template>
|
||||
<div class="c-menu">
|
||||
<ul>
|
||||
<li
|
||||
v-for="(item, index) in popupMenuItems"
|
||||
:key="index"
|
||||
:class="item.cssClass"
|
||||
:title="item.name"
|
||||
@click="item.callback"
|
||||
>
|
||||
{{ item.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
inject: ['popupMenuItems']
|
||||
}
|
||||
</script>
|
@ -12,29 +12,12 @@
|
||||
:class="embed.cssClass"
|
||||
@click="changeLocation"
|
||||
>{{ embed.name }}</a>
|
||||
<a class="c-ne__embed__context-available icon-arrow-down"
|
||||
@click="toggleActionMenu"
|
||||
></a>
|
||||
</div>
|
||||
<div class="hide-menu hidden">
|
||||
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
||||
<div class="c-menu">
|
||||
<ul>
|
||||
<li v-for="action in actions"
|
||||
:key="action.name"
|
||||
:class="action.cssClass"
|
||||
@click="action.perform(embed)"
|
||||
>
|
||||
{{ action.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<PopupMenu :popup-menu-items="popupMenuItems" />
|
||||
</div>
|
||||
<div v-if="embed.snapshot"
|
||||
class="c-ne__embed__time"
|
||||
>
|
||||
{{ formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss') }}
|
||||
{{ createdOn }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -42,15 +25,17 @@
|
||||
|
||||
<script>
|
||||
import Moment from 'moment';
|
||||
import PopupMenu from './popup-menu.vue';
|
||||
import PreviewAction from '../../../ui/preview/PreviewAction';
|
||||
import Painterro from 'painterro';
|
||||
import PainterroInstance from '../utils/painterroInstance';
|
||||
import RemoveDialog from '../utils/removeDialog';
|
||||
import SnapshotTemplate from './snapshot-template.html';
|
||||
import { togglePopupMenu } from '../utils/popup-menu';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
PopupMenu
|
||||
},
|
||||
props: {
|
||||
embed: {
|
||||
@ -62,107 +47,75 @@ export default {
|
||||
removeActionString: {
|
||||
type: String,
|
||||
default() {
|
||||
return 'Remove Embed';
|
||||
return 'Remove This Embed';
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actions: [this.removeEmbedAction()],
|
||||
agentService: this.openmct.$injector.get('agentService'),
|
||||
popupService: this.openmct.$injector.get('popupService')
|
||||
popupMenuItems: []
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
computed: {
|
||||
createdOn() {
|
||||
return this.formatTime(this.embed.createdOn, 'YYYY-MM-DD HH:mm:ss');
|
||||
}
|
||||
},
|
||||
beforeMount() {
|
||||
this.populateActionMenu();
|
||||
mounted() {
|
||||
this.addPopupMenuItems();
|
||||
},
|
||||
methods: {
|
||||
annotateSnapshot() {
|
||||
const self = this;
|
||||
addPopupMenuItems() {
|
||||
const removeEmbed = {
|
||||
cssClass: 'icon-trash',
|
||||
name: this.removeActionString,
|
||||
callback: this.getRemoveDialog.bind(this)
|
||||
}
|
||||
const preview = {
|
||||
cssClass: 'icon-eye-open',
|
||||
name: 'Preview',
|
||||
callback: this.previewEmbed.bind(this)
|
||||
}
|
||||
|
||||
let save = false;
|
||||
let painterroInstance = {};
|
||||
this.popupMenuItems = [removeEmbed, preview];
|
||||
},
|
||||
annotateSnapshot() {
|
||||
let painterroInstance = null;
|
||||
const annotateVue = new Vue({
|
||||
template: '<div id="snap-annotation"></div>'
|
||||
});
|
||||
|
||||
let annotateOverlay = self.openmct.overlays.overlay({
|
||||
const annotateOverlay = this.openmct.overlays.overlay({
|
||||
element: annotateVue.$mount().$el,
|
||||
size: 'large',
|
||||
dismissable: false,
|
||||
buttons: [
|
||||
{
|
||||
label: 'Cancel',
|
||||
callback: function () {
|
||||
save = false;
|
||||
painterroInstance.save();
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
painterroInstance.dismiss();
|
||||
annotateOverlay.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: 'Save',
|
||||
callback: function () {
|
||||
|
||||
save = true;
|
||||
callback: () => {
|
||||
painterroInstance.save();
|
||||
annotateOverlay.dismiss();
|
||||
this.snapshotOverlay.dismiss();
|
||||
this.openSnapshot();
|
||||
}
|
||||
}
|
||||
],
|
||||
onDestroy: function () {
|
||||
onDestroy: () => {
|
||||
annotateVue.$destroy(true);
|
||||
}
|
||||
});
|
||||
|
||||
painterroInstance = Painterro({
|
||||
id: 'snap-annotation',
|
||||
activeColor: '#ff0000',
|
||||
activeColorAlpha: 1.0,
|
||||
activeFillColor: '#fff',
|
||||
activeFillColorAlpha: 0.0,
|
||||
backgroundFillColor: '#000',
|
||||
backgroundFillColorAlpha: 0.0,
|
||||
defaultFontSize: 16,
|
||||
defaultLineWidth: 2,
|
||||
defaultTool: 'ellipse',
|
||||
hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
|
||||
translation: {
|
||||
name: 'en',
|
||||
strings: {
|
||||
lineColor: 'Line',
|
||||
fillColor: 'Fill',
|
||||
lineWidth: 'Size',
|
||||
textColor: 'Color',
|
||||
fontSize: 'Size',
|
||||
fontStyle: 'Style'
|
||||
}
|
||||
},
|
||||
saveHandler: function (image, done) {
|
||||
if (save) {
|
||||
const url = image.asBlob();
|
||||
const reader = new window.FileReader();
|
||||
reader.readAsDataURL(url);
|
||||
reader.onloadend = function () {
|
||||
const snapshot = reader.result;
|
||||
const snapshotObject = {
|
||||
src: snapshot,
|
||||
type: url.type,
|
||||
size: url.size,
|
||||
modified: Date.now()
|
||||
};
|
||||
|
||||
self.embed.snapshot = snapshotObject;
|
||||
self.updateEmbed(self.embed);
|
||||
};
|
||||
} else {
|
||||
console.log('You cancelled the annotation!!!');
|
||||
}
|
||||
|
||||
done(true);
|
||||
}
|
||||
}).show(this.embed.snapshot.src);
|
||||
painterroInstance = new PainterroInstance();
|
||||
painterroInstance.callback = this.updateSnapshot;
|
||||
painterroInstance.show(this.embed.snapshot.src);
|
||||
},
|
||||
changeLocation() {
|
||||
this.openmct.time.stopClock();
|
||||
@ -172,9 +125,6 @@ export default {
|
||||
});
|
||||
|
||||
const link = this.embed.historicLink;
|
||||
if (!link) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.location.href = link;
|
||||
const message = 'Time bounds changed to fixed timespan mode';
|
||||
@ -183,23 +133,30 @@ export default {
|
||||
formatTime(unixTime, timeFormat) {
|
||||
return Moment.utc(unixTime).format(timeFormat);
|
||||
},
|
||||
getRemoveDialog() {
|
||||
const options = {
|
||||
name: this.removeActionString,
|
||||
callback: this.removeEmbed.bind(this)
|
||||
}
|
||||
const removeDialog = new RemoveDialog(this.openmct, options);
|
||||
removeDialog.show();
|
||||
},
|
||||
openSnapshot() {
|
||||
const self = this;
|
||||
const snapshot = new Vue({
|
||||
data: () => {
|
||||
return {
|
||||
embed: self.embed
|
||||
createdOn: this.createdOn,
|
||||
embed: this.embed
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
formatTime: self.formatTime,
|
||||
annotateSnapshot: self.annotateSnapshot
|
||||
annotateSnapshot: this.annotateSnapshot.bind(this)
|
||||
},
|
||||
template: SnapshotTemplate
|
||||
});
|
||||
}).$mount();
|
||||
|
||||
const snapshotOverlay = this.openmct.overlays.overlay({
|
||||
element: snapshot.$mount().$el,
|
||||
this.snapshotOverlay = this.openmct.overlays.overlay({
|
||||
element: snapshot.$el,
|
||||
onDestroy: () => { snapshot.$destroy(true) },
|
||||
size: 'large',
|
||||
dismissable: true,
|
||||
@ -208,62 +165,30 @@ export default {
|
||||
label: 'Done',
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
snapshotOverlay.dismiss();
|
||||
this.snapshotOverlay.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
},
|
||||
populateActionMenu() {
|
||||
previewEmbed() {
|
||||
const self = this;
|
||||
const actions = [new PreviewAction(self.openmct)];
|
||||
const previewAction = new PreviewAction(self.openmct);
|
||||
previewAction.invoke(JSON.parse(self.embed.objectPath));
|
||||
},
|
||||
removeEmbed(success) {
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
actions.forEach((action) => {
|
||||
self.actions.push({
|
||||
cssClass: action.cssClass,
|
||||
name: action.name,
|
||||
perform: () => {
|
||||
action.invoke(JSON.parse(self.embed.objectPath));
|
||||
}
|
||||
});
|
||||
});
|
||||
},
|
||||
removeEmbed(id) {
|
||||
this.$emit('removeEmbed', id);
|
||||
},
|
||||
removeEmbedAction() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
name: self.removeActionString,
|
||||
cssClass: 'icon-trash',
|
||||
perform: function (embed) {
|
||||
const dialog = self.openmct.overlays.dialog({
|
||||
iconClass: "error",
|
||||
message: `This action will permanently ${self.removeActionString.toLowerCase()}. Do you wish to continue?`,
|
||||
buttons: [{
|
||||
label: "No",
|
||||
callback: function () {
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Yes",
|
||||
emphasis: true,
|
||||
callback: function () {
|
||||
dialog.dismiss();
|
||||
self.removeEmbed(embed.id);
|
||||
}
|
||||
}]
|
||||
});
|
||||
}
|
||||
};
|
||||
},
|
||||
toggleActionMenu(event) {
|
||||
togglePopupMenu(event, this.openmct);
|
||||
this.$emit('removeEmbed', this.embed.id);
|
||||
},
|
||||
updateEmbed(embed) {
|
||||
this.$emit('updateEmbed', embed);
|
||||
},
|
||||
updateSnapshot(snapshotObject) {
|
||||
this.embed.snapshot = snapshotObject;
|
||||
this.updateEmbed(this.embed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
<template>
|
||||
<div class="c-notebook__entry c-ne has-local-controls"
|
||||
@dragover="dragover"
|
||||
@drop.capture="dropCapture"
|
||||
@drop.prevent="dropOnEntry(entry.id, $event)"
|
||||
@dragover="changeCursor"
|
||||
@drop.capture="cancelEditMode"
|
||||
@drop.prevent="dropOnEntry"
|
||||
>
|
||||
<div class="c-ne__time-and-content">
|
||||
<div class="c-ne__time">
|
||||
<span>{{ formatTime(entry.createdOn, 'YYYY-MM-DD') }}</span>
|
||||
<span>{{ formatTime(entry.createdOn, 'HH:mm:ss') }}</span>
|
||||
<span>{{ createdOnDate }}</span>
|
||||
<span>{{ createdOnTime }}</span>
|
||||
</div>
|
||||
<div class="c-ne__content">
|
||||
<div :id="entry.id"
|
||||
@ -15,8 +15,8 @@
|
||||
:class="{'c-input-inline' : !readOnly }"
|
||||
:contenteditable="!readOnly"
|
||||
:style="!entry.text.length ? defaultEntryStyle : ''"
|
||||
@blur="textBlur($event, entry.id)"
|
||||
@focus="textFocus($event, entry.id)"
|
||||
@blur="updateEntryValue($event, entry.id)"
|
||||
@focus="updateCurrentEntryValue($event, entry.id)"
|
||||
>{{ entry.text.length ? entry.text : defaultText }}</div>
|
||||
<div class="c-snapshots c-ne__embeds">
|
||||
<NotebookEmbed v-for="embed in entry.embeds"
|
||||
@ -114,29 +114,32 @@ export default {
|
||||
defaultText: 'add description'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
entry() {
|
||||
computed : {
|
||||
createdOnDate() {
|
||||
return this.formatTime(this.entry.createdOn, 'YYYY-MM-DD');
|
||||
},
|
||||
readOnly(readOnly) {
|
||||
},
|
||||
selectedSection(selectedSection) {
|
||||
},
|
||||
selectedPage(selectedSection) {
|
||||
createdOnTime() {
|
||||
return this.formatTime(this.entry.createdOn, 'HH:mm:ss');
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.updateEntries = this.updateEntries.bind(this);
|
||||
},
|
||||
beforeDestory() {
|
||||
this.dropOnEntry = this.dropOnEntry.bind(this);
|
||||
},
|
||||
methods: {
|
||||
cancelEditMode(event) {
|
||||
const isEditing = this.openmct.editor.isEditing();
|
||||
if (isEditing) {
|
||||
this.openmct.editor.cancel();
|
||||
}
|
||||
},
|
||||
changeCursor() {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
},
|
||||
deleteEntry() {
|
||||
const self = this;
|
||||
if (!self.domainObject || !self.selectedSection || !self.selectedPage || !self.entry.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entryPosById = this.entryPosById(this.entry.id);
|
||||
const entryPosById = self.entryPosById(self.entry.id);
|
||||
if (entryPosById === -1) {
|
||||
return;
|
||||
}
|
||||
@ -151,7 +154,7 @@ export default {
|
||||
callback: () => {
|
||||
const entries = getNotebookEntries(self.domainObject, self.selectedSection, self.selectedPage);
|
||||
entries.splice(entryPosById, 1);
|
||||
this.updateEntries(entries);
|
||||
self.updateEntries(entries);
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
@ -164,24 +167,10 @@ export default {
|
||||
]
|
||||
});
|
||||
},
|
||||
dragover() {
|
||||
event.preventDefault();
|
||||
event.dataTransfer.dropEffect = "copy";
|
||||
},
|
||||
dropCapture(event) {
|
||||
const isEditing = this.openmct.editor.isEditing();
|
||||
if (isEditing) {
|
||||
this.openmct.editor.cancel();
|
||||
}
|
||||
},
|
||||
dropOnEntry(entryId, $event) {
|
||||
dropOnEntry($event) {
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
if (!this.domainObject || !this.selectedSection || !this.selectedPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const snapshotId = $event.dataTransfer.getData('snapshot/id');
|
||||
const snapshotId = $event.dataTransfer.getData('openmct/snapshot/id');
|
||||
if (snapshotId.length) {
|
||||
this.moveSnapshot(snapshotId);
|
||||
|
||||
@ -190,7 +179,7 @@ export default {
|
||||
|
||||
const data = $event.dataTransfer.getData('openmct/domain-object-path');
|
||||
const objectPath = JSON.parse(data);
|
||||
const entryPos = this.entryPosById(entryId);
|
||||
const entryPos = this.entryPosById(this.entry.id);
|
||||
const bounds = this.openmct.time.bounds();
|
||||
const snapshotMeta = {
|
||||
bounds,
|
||||
@ -253,7 +242,44 @@ export default {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
},
|
||||
textBlur($event, entryId) {
|
||||
updateCurrentEntryValue($event) {
|
||||
if (this.readOnly) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = $event.target
|
||||
this.currentEntryValue = target ? target.innerText : '';
|
||||
|
||||
if (!this.entry.text.length) {
|
||||
this.selectTextInsideElement(target);
|
||||
}
|
||||
},
|
||||
updateEmbed(newEmbed) {
|
||||
this.entry.embeds.some(e => {
|
||||
const found = (e.id === newEmbed.id);
|
||||
if (found) {
|
||||
e = newEmbed;
|
||||
}
|
||||
|
||||
return found;
|
||||
});
|
||||
|
||||
this.updateEntry(this.entry);
|
||||
},
|
||||
updateEntry(newEntry) {
|
||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
||||
entries.some(entry => {
|
||||
const found = (entry.id === newEntry.id);
|
||||
if (found) {
|
||||
entry = newEntry;
|
||||
}
|
||||
|
||||
return found;
|
||||
});
|
||||
|
||||
this.updateEntries(entries);
|
||||
},
|
||||
updateEntryValue($event, entryId) {
|
||||
if (!this.domainObject || !this.selectedSection || !this.selectedPage) {
|
||||
return;
|
||||
}
|
||||
@ -272,42 +298,6 @@ export default {
|
||||
this.updateEntries(entries);
|
||||
}
|
||||
},
|
||||
textFocus($event) {
|
||||
if (this.readOnly || !this.domainObject || !this.selectedSection || !this.selectedPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const target = $event.target
|
||||
this.currentEntryValue = target ? target.innerText : '';
|
||||
|
||||
if (!this.entry.text.length) {
|
||||
this.selectTextInsideElement(target);
|
||||
}
|
||||
},
|
||||
updateEmbed(newEmbed) {
|
||||
let embed = this.entry.embeds.find(e => e.id === newEmbed.id);
|
||||
|
||||
if (!embed) {
|
||||
return;
|
||||
}
|
||||
|
||||
embed = newEmbed;
|
||||
this.updateEntry(this.entry);
|
||||
},
|
||||
updateEntry(newEntry) {
|
||||
if (!this.domainObject || !this.selectedSection || !this.selectedPage) {
|
||||
return;
|
||||
}
|
||||
|
||||
const entries = getNotebookEntries(this.domainObject, this.selectedSection, this.selectedPage);
|
||||
entries.forEach(entry => {
|
||||
if (entry.id === newEntry.id) {
|
||||
entry = newEntry;
|
||||
}
|
||||
});
|
||||
|
||||
this.updateEntries(entries);
|
||||
},
|
||||
updateEntries(entries) {
|
||||
this.$emit('updateEntries', entries);
|
||||
}
|
||||
|
@ -64,9 +64,7 @@ export default {
|
||||
const defaultNotebook = getDefaultNotebook();
|
||||
|
||||
if (defaultNotebook) {
|
||||
const domainObject = await this.openmct.objects.get(defaultNotebook.notebookMeta.identifier)
|
||||
.then(d => d);
|
||||
|
||||
const domainObject = await this.openmct.objects.get(defaultNotebook.notebookMeta.identifier);
|
||||
if (!domainObject.location) {
|
||||
clearDefaultNotebook();
|
||||
} else {
|
||||
|
@ -10,24 +10,9 @@
|
||||
> {{ snapshots.length }} of {{ getNotebookSnapshotMaxCount() }}
|
||||
</span>
|
||||
</div>
|
||||
<a class="l-browse-bar__context-actions c-disclosure-button"
|
||||
@click="toggleActionMenu"
|
||||
></a>
|
||||
<div class="hide-menu hidden">
|
||||
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
||||
<div class="c-menu">
|
||||
<ul>
|
||||
<li v-for="action in actions"
|
||||
:key="action.name"
|
||||
:class="action.cssClass"
|
||||
@click="action.perform()"
|
||||
>
|
||||
{{ action.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PopupMenu v-if="snapshots.length > 0"
|
||||
:popup-menu-items="popupMenuItems"
|
||||
/>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -46,7 +31,7 @@
|
||||
<NotebookEmbed ref="notebookEmbed"
|
||||
:key="snapshot.id"
|
||||
:embed="snapshot"
|
||||
:remove-action-string="'Delete Snapshot'"
|
||||
:remove-action-string="'Delete This Snapshot'"
|
||||
@updateEmbed="updateSnapshot"
|
||||
@removeEmbed="removeSnapshot"
|
||||
/>
|
||||
@ -62,14 +47,16 @@
|
||||
|
||||
<script>
|
||||
import NotebookEmbed from './notebook-embed.vue';
|
||||
import PopupMenu from './popup-menu.vue';
|
||||
import RemoveDialog from '../utils/removeDialog';
|
||||
import { NOTEBOOK_SNAPSHOT_MAX_COUNT } from '../snapshot-container';
|
||||
import { EVENT_SNAPSHOTS_UPDATED } from '../notebook-constants';
|
||||
import { togglePopupMenu } from '../utils/popup-menu';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'snapshotContainer'],
|
||||
components: {
|
||||
NotebookEmbed
|
||||
NotebookEmbed,
|
||||
PopupMenu
|
||||
},
|
||||
props: {
|
||||
toggleSnapshot: {
|
||||
@ -81,54 +68,45 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actions: [this.removeAllSnapshotAction()],
|
||||
popupMenuItems: [],
|
||||
removeActionString: 'Delete All Snapshots',
|
||||
snapshots: []
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.addPopupMenuItems();
|
||||
this.snapshotContainer.on(EVENT_SNAPSHOTS_UPDATED, this.snapshotsUpdated);
|
||||
this.snapshots = this.snapshotContainer.getSnapshots();
|
||||
},
|
||||
beforeDestory() {
|
||||
},
|
||||
methods: {
|
||||
addPopupMenuItems() {
|
||||
const removeSnapshot = {
|
||||
cssClass: 'icon-trash',
|
||||
name: this.removeActionString,
|
||||
callback: this.getRemoveDialog.bind(this)
|
||||
}
|
||||
|
||||
this.popupMenuItems = [removeSnapshot];
|
||||
},
|
||||
close() {
|
||||
this.toggleSnapshot();
|
||||
},
|
||||
getNotebookSnapshotMaxCount() {
|
||||
return NOTEBOOK_SNAPSHOT_MAX_COUNT;
|
||||
},
|
||||
removeAllSnapshotAction() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
name: 'Delete All Snapshots',
|
||||
cssClass: 'icon-trash',
|
||||
perform: function (embed) {
|
||||
const dialog = self.openmct.overlays.dialog({
|
||||
iconClass: "error",
|
||||
message: 'This action will delete all notebook snapshots. Do you want to continue?',
|
||||
buttons: [
|
||||
{
|
||||
label: "No",
|
||||
callback: () => {
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Yes",
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
self.removeAllSnapshots();
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
};
|
||||
getRemoveDialog() {
|
||||
const options = {
|
||||
name: this.removeActionString,
|
||||
callback: this.removeAllSnapshots.bind(this)
|
||||
}
|
||||
const removeDialog = new RemoveDialog(this.openmct, options);
|
||||
removeDialog.show();
|
||||
},
|
||||
removeAllSnapshots() {
|
||||
removeAllSnapshots(success) {
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.snapshotContainer.removeAllSnapshots();
|
||||
},
|
||||
removeSnapshot(id) {
|
||||
@ -139,10 +117,7 @@ export default {
|
||||
},
|
||||
startEmbedDrag(snapshot, event) {
|
||||
event.dataTransfer.setData('text/plain', snapshot.id);
|
||||
event.dataTransfer.setData('snapshot/id', snapshot.id);
|
||||
},
|
||||
toggleActionMenu(event) {
|
||||
togglePopupMenu(event, this.openmct);
|
||||
event.dataTransfer.setData('openmct/snapshot/id', snapshot.id);
|
||||
},
|
||||
updateSnapshot(snapshot) {
|
||||
this.snapshotContainer.updateSnapshot(snapshot);
|
||||
|
@ -9,8 +9,10 @@
|
||||
</div>
|
||||
<SearchResults v-if="search.length"
|
||||
ref="searchResults"
|
||||
:results="getSearchResults()"
|
||||
:domain-object="internalDomainObject"
|
||||
:results="searchedEntries"
|
||||
@changeSectionPage="changeSelectedSection"
|
||||
@updateEntries="updateEntries"
|
||||
/>
|
||||
|
||||
<div v-if="!search.length"
|
||||
@ -139,6 +141,9 @@ export default {
|
||||
pages() {
|
||||
return this.getPages() || [];
|
||||
},
|
||||
searchedEntries() {
|
||||
return this.getSearchResults();
|
||||
},
|
||||
sections() {
|
||||
return this.internalDomainObject.configuration.sections || [];
|
||||
},
|
||||
@ -158,8 +163,6 @@ export default {
|
||||
return this.sections.find(section => section.isSelected);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
beforeMount() {
|
||||
this.throttledSearchItem = throttle(this.searchItem, 500);
|
||||
},
|
||||
@ -244,7 +247,7 @@ export default {
|
||||
event.preventDefault();
|
||||
event.stopImmediatePropagation();
|
||||
|
||||
const snapshotId = event.dataTransfer.getData('snapshot/id');
|
||||
const snapshotId = event.dataTransfer.getData('openmct/snapshot/id');
|
||||
if (snapshotId.length) {
|
||||
const snapshot = this.snapshotContainer.getSnapshot(snapshotId);
|
||||
this.newEntry(snapshot);
|
||||
|
@ -70,12 +70,6 @@ export default {
|
||||
return {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
deletePage(id) {
|
||||
const selectedSection = this.sections.find(s => s.isSelected);
|
||||
|
@ -9,32 +9,19 @@
|
||||
@keydown.enter="updateName"
|
||||
@blur="updateName"
|
||||
>{{ page.name.length ? page.name : `Unnamed ${pageTitle}` }}</span>
|
||||
<a class="c-list__item__menu-indicator icon-arrow-down"
|
||||
@click="toggleActionMenu"
|
||||
></a>
|
||||
<div class="hide-menu hidden">
|
||||
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
||||
<div class="c-menu">
|
||||
<ul>
|
||||
<li v-for="action in actions"
|
||||
:key="action.name"
|
||||
:class="action.cssClass"
|
||||
@click="action.perform(page.id)"
|
||||
>
|
||||
{{ action.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PopupMenu :popup-menu-items="popupMenuItems" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { togglePopupMenu } from '../utils/popup-menu';
|
||||
import PopupMenu from './popup-menu.vue';
|
||||
import RemoveDialog from '../utils/removeDialog';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
PopupMenu
|
||||
},
|
||||
props: {
|
||||
defaultPageId: {
|
||||
type: String,
|
||||
@ -55,7 +42,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actions: [this.deletePage()]
|
||||
popupMenuItems: [],
|
||||
removeActionString: `Delete ${this.pageTitle}`
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -64,40 +52,35 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.addPopupMenuItems();
|
||||
this.toggleContentEditable();
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
deletePage() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
name: `Delete ${this.pageTitle}`,
|
||||
addPopupMenuItems() {
|
||||
const removePage = {
|
||||
cssClass: 'icon-trash',
|
||||
perform: function (id) {
|
||||
const dialog = self.openmct.overlays.dialog({
|
||||
iconClass: "error",
|
||||
message: 'This action will delete this page and all of its entries. Do you want to continue?',
|
||||
buttons: [
|
||||
{
|
||||
label: "No",
|
||||
callback: () => {
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Yes",
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
self.$emit('deletePage', id);
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
};
|
||||
name: this.removeActionString,
|
||||
callback: this.getRemoveDialog.bind(this)
|
||||
}
|
||||
|
||||
this.popupMenuItems = [removePage];
|
||||
},
|
||||
deletePage(success) {
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('deletePage', this.page.id);
|
||||
},
|
||||
getRemoveDialog() {
|
||||
const message = 'This action will delete this page and all of its entries. Do you want to continue?';
|
||||
const options = {
|
||||
name: this.removeActionString,
|
||||
callback: this.deletePage.bind(this),
|
||||
message
|
||||
}
|
||||
const removeDialog = new RemoveDialog(this.openmct, options);
|
||||
removeDialog.show();
|
||||
},
|
||||
selectPage(event) {
|
||||
const target = event.target;
|
||||
@ -117,10 +100,6 @@ export default {
|
||||
|
||||
this.$emit('selectPage', id);
|
||||
},
|
||||
toggleActionMenu(event) {
|
||||
event.preventDefault();
|
||||
togglePopupMenu(event, this.openmct);
|
||||
},
|
||||
toggleContentEditable(page = this.page) {
|
||||
const pageTitle = this.$el.querySelector('span');
|
||||
pageTitle.contentEditable = page.isSelected;
|
||||
|
96
src/plugins/notebook/components/popup-menu.vue
Normal file
96
src/plugins/notebook/components/popup-menu.vue
Normal file
@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<div class="l-browse-bar__view-switcher c-ctrl-wrapper c-ctrl-wrapper--menus-left">
|
||||
<button
|
||||
class="l-browse-bar__context-actions c-disclosure-button"
|
||||
title="popup menu"
|
||||
@click="showMenuItems"
|
||||
>
|
||||
<span class="c-button__label"></span>
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import MenuItems from './menu-items.vue';
|
||||
import Vue from 'vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
props: {
|
||||
domainObject: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
popupMenuItems: {
|
||||
type: Array,
|
||||
default() {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
menuItems: null
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
calculateMenuPosition(event, element) {
|
||||
let eventPosX = event.clientX;
|
||||
let eventPosY = event.clientY;
|
||||
|
||||
let menuDimensions = element.getBoundingClientRect();
|
||||
let overflowX = (eventPosX + menuDimensions.width) - document.body.clientWidth;
|
||||
let overflowY = (eventPosY + menuDimensions.height) - document.body.clientHeight;
|
||||
|
||||
if (overflowX > 0) {
|
||||
eventPosX = eventPosX - overflowX;
|
||||
}
|
||||
|
||||
if (overflowY > 0) {
|
||||
eventPosY = eventPosY - overflowY;
|
||||
}
|
||||
|
||||
return {
|
||||
x: eventPosX,
|
||||
y: eventPosY
|
||||
}
|
||||
},
|
||||
hideMenuItems() {
|
||||
document.body.removeChild(this.menuItems.$el);
|
||||
this.menuItems.$destroy();
|
||||
this.menuItems = null;
|
||||
document.removeEventListener('click', this.hideMenuItems);
|
||||
|
||||
return;
|
||||
},
|
||||
showMenuItems($event) {
|
||||
const menuItems = new Vue({
|
||||
components: {
|
||||
MenuItems
|
||||
},
|
||||
provide: {
|
||||
popupMenuItems: this.popupMenuItems
|
||||
},
|
||||
template: '<MenuItems />'
|
||||
});
|
||||
this.menuItems = menuItems;
|
||||
|
||||
menuItems.$mount();
|
||||
const element = this.menuItems.$el;
|
||||
document.body.appendChild(element);
|
||||
|
||||
const position = this.calculateMenuPosition($event, element);
|
||||
element.style.left = `${position.x}px`;
|
||||
element.style.top = `${position.y}px`;
|
||||
|
||||
setTimeout(() => {
|
||||
document.addEventListener('click', this.hideMenuItems);
|
||||
}, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
@ -4,12 +4,14 @@
|
||||
<div class="c-notebook__entries">
|
||||
<NotebookEntry v-for="(result, index) in results"
|
||||
:key="index"
|
||||
:domain-object="domainObject"
|
||||
:result="result"
|
||||
:entry="result.entry"
|
||||
:read-only="true"
|
||||
:selected-page="null"
|
||||
:selected-section="null"
|
||||
:selected-page="result.page"
|
||||
:selected-section="result.section"
|
||||
@changeSectionPage="changeSectionPage"
|
||||
@updateEntries="updateEntries"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@ -19,11 +21,17 @@
|
||||
import NotebookEntry from './notebook-entry.vue';
|
||||
|
||||
export default {
|
||||
inject: ['openmct', 'domainObject'],
|
||||
inject: ['openmct', 'snapshotContainer'],
|
||||
components: {
|
||||
NotebookEntry
|
||||
},
|
||||
props:{
|
||||
domainObject: {
|
||||
type: Object,
|
||||
default() {
|
||||
return {};
|
||||
}
|
||||
},
|
||||
results: {
|
||||
type: Array,
|
||||
default() {
|
||||
@ -31,19 +39,12 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {}
|
||||
},
|
||||
watch: {
|
||||
results(newResults) {}
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
methods: {
|
||||
changeSectionPage(data) {
|
||||
this.$emit('changeSectionPage', data);
|
||||
},
|
||||
updateEntries(entries) {
|
||||
this.$emit('updateEntries', entries);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -57,12 +57,6 @@ export default {
|
||||
return {
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
},
|
||||
mounted() {
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
deleteSection(id) {
|
||||
const section = this.sections.find(s => s.id === id);
|
||||
|
@ -9,24 +9,7 @@
|
||||
@keydown.enter="updateName"
|
||||
@blur="updateName"
|
||||
>{{ section.name.length ? section.name : `Unnamed ${sectionTitle}` }}</span>
|
||||
<a class="c-list__item__menu-indicator icon-arrow-down"
|
||||
@click="toggleActionMenu"
|
||||
></a>
|
||||
<div class="hide-menu hidden">
|
||||
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
||||
<div class="c-menu">
|
||||
<ul>
|
||||
<li v-for="action in actions"
|
||||
:key="action.name"
|
||||
:class="action.cssClass"
|
||||
@click="action.perform(section.id)"
|
||||
>
|
||||
{{ action.name }}
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<PopupMenu :popup-menu-items="popupMenuItems" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@ -34,10 +17,14 @@
|
||||
</style>
|
||||
|
||||
<script>
|
||||
import { togglePopupMenu } from '../utils/popup-menu';
|
||||
import PopupMenu from './popup-menu.vue';
|
||||
import RemoveDialog from '../utils/removeDialog';
|
||||
|
||||
export default {
|
||||
inject: ['openmct'],
|
||||
components: {
|
||||
PopupMenu
|
||||
},
|
||||
props: {
|
||||
defaultSectionId: {
|
||||
type: String,
|
||||
@ -58,7 +45,8 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
actions: [this.deleteSectionAction()]
|
||||
popupMenuItems: [],
|
||||
removeActionString: `Delete ${this.sectionTitle}`
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -67,40 +55,36 @@ export default {
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.addPopupMenuItems();
|
||||
this.toggleContentEditable();
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
deleteSectionAction() {
|
||||
const self = this;
|
||||
|
||||
return {
|
||||
name: `Delete ${this.sectionTitle}`,
|
||||
addPopupMenuItems() {
|
||||
const removeSection = {
|
||||
cssClass: 'icon-trash',
|
||||
perform: function (id) {
|
||||
const dialog = self.openmct.overlays.dialog({
|
||||
iconClass: "error",
|
||||
message: 'This action will delete this section and all of its pages and entries. Do you want to continue?',
|
||||
buttons: [
|
||||
{
|
||||
label: "No",
|
||||
callback: () => {
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Yes",
|
||||
emphasis: true,
|
||||
callback: () => {
|
||||
self.$emit('deleteSection', id);
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
};
|
||||
name: this.removeActionString,
|
||||
callback: this.getRemoveDialog.bind(this)
|
||||
}
|
||||
|
||||
this.popupMenuItems = [removeSection];
|
||||
},
|
||||
deleteSection(success) {
|
||||
if (!success) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.$emit('deleteSection', this.section.id);
|
||||
},
|
||||
getRemoveDialog() {
|
||||
const message = 'This action will delete this section and all of its pages and entries. Do you want to continue?';
|
||||
const options = {
|
||||
name: this.removeActionString,
|
||||
callback: this.deleteSection.bind(this),
|
||||
message
|
||||
}
|
||||
|
||||
const removeDialog = new RemoveDialog(this.openmct, options);
|
||||
removeDialog.show();
|
||||
},
|
||||
selectSection(event) {
|
||||
const target = event.target;
|
||||
@ -121,9 +105,6 @@ export default {
|
||||
|
||||
this.$emit('selectSection', id);
|
||||
},
|
||||
toggleActionMenu(event) {
|
||||
togglePopupMenu(event, this.openmct);
|
||||
},
|
||||
toggleContentEditable(section = this.section) {
|
||||
const sectionTitle = this.$el.querySelector('span');
|
||||
sectionTitle.contentEditable = section.isSelected;
|
||||
|
@ -139,8 +139,6 @@ export default {
|
||||
this.addSection();
|
||||
}
|
||||
},
|
||||
destroyed() {
|
||||
},
|
||||
methods: {
|
||||
addPage() {
|
||||
const pageTitle = this.pageTitle;
|
||||
|
@ -13,7 +13,7 @@
|
||||
|
||||
<div class="l-browse-bar__end">
|
||||
<div class="l-browse-bar__snapshot-datetime">
|
||||
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||
SNAPSHOT {{ createdOn }}
|
||||
</div>
|
||||
<a class="l-browse-bar__annotate-button c-button icon-pencil" title="Annotate" @click="annotateSnapshot">
|
||||
<span class="title-label">Annotate</span>
|
||||
|
75
src/plugins/notebook/utils/painterroInstance.js
Normal file
75
src/plugins/notebook/utils/painterroInstance.js
Normal file
@ -0,0 +1,75 @@
|
||||
import Painterro from 'painterro';
|
||||
|
||||
const defaultConfig = {
|
||||
id: 'snap-annotation',
|
||||
activeColor: '#ff0000',
|
||||
activeColorAlpha: 1.0,
|
||||
activeFillColor: '#fff',
|
||||
activeFillColorAlpha: 0.0,
|
||||
backgroundFillColor: '#000',
|
||||
backgroundFillColorAlpha: 0.0,
|
||||
defaultFontSize: 16,
|
||||
defaultLineWidth: 2,
|
||||
defaultTool: 'ellipse',
|
||||
hiddenTools: ['save', 'open', 'close', 'eraser', 'pixelize', 'rotate', 'settings', 'resize'],
|
||||
translation: {
|
||||
name: 'en',
|
||||
strings: {
|
||||
lineColor: 'Line',
|
||||
fillColor: 'Fill',
|
||||
lineWidth: 'Size',
|
||||
textColor: 'Color',
|
||||
fontSize: 'Size',
|
||||
fontStyle: 'Style'
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default class PainterroInstance {
|
||||
constructor() {
|
||||
this.callback = null;
|
||||
this.config = Object.assign({}, defaultConfig);
|
||||
this.config.id = this.config.id;
|
||||
this.config.saveHandler = this.saveHandler.bind(this);
|
||||
this.isSave = false;
|
||||
|
||||
this.painterro = Painterro(this.config);
|
||||
this.painterroInstance = null;
|
||||
}
|
||||
|
||||
dismiss() {
|
||||
this.isSave = false;
|
||||
this.painterroInstance.save();
|
||||
}
|
||||
|
||||
save() {
|
||||
this.isSave = true;
|
||||
this.painterroInstance.save();
|
||||
}
|
||||
|
||||
saveHandler(image, done) {
|
||||
if (this.isSave) {
|
||||
const self = this;
|
||||
const url = image.asBlob();
|
||||
const reader = new window.FileReader();
|
||||
reader.readAsDataURL(url);
|
||||
reader.onloadend = () => {
|
||||
const snapshot = reader.result;
|
||||
const snapshotObject = {
|
||||
src: snapshot,
|
||||
type: url.type,
|
||||
size: url.size,
|
||||
modified: Date.now()
|
||||
};
|
||||
|
||||
self.callback(snapshotObject);
|
||||
};
|
||||
}
|
||||
|
||||
done(true);
|
||||
}
|
||||
|
||||
show(src) {
|
||||
this.painterroInstance = this.painterro.show(src);
|
||||
}
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import $ from 'zepto';
|
||||
|
||||
export const togglePopupMenu = (event, openmct) => {
|
||||
event.preventDefault();
|
||||
|
||||
const body = $(document.body);
|
||||
const container = $(event.target.parentElement.parentElement);
|
||||
const classList = document.querySelector('body').classList;
|
||||
const isPhone = Array.from(classList).includes('phone');
|
||||
const isTablet = Array.from(classList).includes('tablet');
|
||||
|
||||
const initiatingEvent = isPhone || isTablet
|
||||
? 'touchstart'
|
||||
: 'mousedown';
|
||||
const menu = container.find('.menu-element');
|
||||
let dismissExistingMenu;
|
||||
|
||||
function dismiss() {
|
||||
container.find('.hide-menu').append(menu);
|
||||
body.off(initiatingEvent, menuClickHandler);
|
||||
dismissExistingMenu = undefined;
|
||||
}
|
||||
|
||||
function menuClickHandler(e) {
|
||||
window.setTimeout(() => {
|
||||
dismiss();
|
||||
}, 100);
|
||||
}
|
||||
|
||||
// Dismiss any menu which was already showing
|
||||
if (dismissExistingMenu) {
|
||||
dismissExistingMenu();
|
||||
}
|
||||
|
||||
// ...and record the presence of this menu.
|
||||
dismissExistingMenu = dismiss;
|
||||
|
||||
const popupService = openmct.$injector.get('popupService');
|
||||
popupService.display(menu, [event.pageX,event.pageY], {
|
||||
marginX: 0,
|
||||
marginY: -50
|
||||
});
|
||||
|
||||
body.on(initiatingEvent, menuClickHandler);
|
||||
}
|
36
src/plugins/notebook/utils/removeDialog.js
Normal file
36
src/plugins/notebook/utils/removeDialog.js
Normal file
@ -0,0 +1,36 @@
|
||||
export default class RemoveDialog {
|
||||
constructor(openmct, options) {
|
||||
this.name = options.name;
|
||||
this.openmct = openmct;
|
||||
|
||||
this.callback = options.callback;
|
||||
this.cssClass = options.cssClass || 'icon-trash';
|
||||
this.description = options.description || 'Remove action dialog';
|
||||
this.iconClass = "error";
|
||||
this.key = 'remove';
|
||||
this.message = options.message || `This action will permanently ${this.name.toLowerCase()}. Do you wish to continue?`;
|
||||
}
|
||||
|
||||
show() {
|
||||
const dialog = this.openmct.overlays.dialog({
|
||||
iconClass: this.iconClass,
|
||||
message: this.message,
|
||||
buttons: [
|
||||
{
|
||||
label: "Ok",
|
||||
callback: () => {
|
||||
this.callback(true);
|
||||
dialog.dismiss();
|
||||
}
|
||||
},
|
||||
{
|
||||
label: "Cancel",
|
||||
callback: () => {
|
||||
this.callback(false);
|
||||
dialog.dismiss();
|
||||
}
|
||||
}
|
||||
]
|
||||
});
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user