mirror of
https://github.com/nasa/openmct.git
synced 2025-06-26 11:09:22 +00:00
Compare commits
13 Commits
vue-main-s
...
table-fixe
Author | SHA1 | Date | |
---|---|---|---|
d2e064dc52 | |||
7483e886f1 | |||
ef92da4d9d | |||
80b02672a6 | |||
fbf1c68c7a | |||
5eac6e646b | |||
82e5bf2325 | |||
40b7117987 | |||
07ca60e13a | |||
08cd6b1d99 | |||
78ae7b334c | |||
3a28caac06 | |||
c883bbe6c2 |
21
copyright-notice.html
Normal file
21
copyright-notice.html
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<!--
|
||||||
|
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.
|
||||||
|
-->
|
@ -1,5 +1,5 @@
|
|||||||
/******************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -19,26 +19,3 @@
|
|||||||
* this source code distribution or the Licensing information page available
|
* this source code distribution or the Licensing information page available
|
||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/**
|
|
||||||
* This bundle implements "containment" rules, which determine which objects
|
|
||||||
* can be contained within a notebook.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
function CompositionPolicy() {
|
|
||||||
}
|
|
||||||
|
|
||||||
CompositionPolicy.prototype.allow = function (parent, child) {
|
|
||||||
var parentDef = parent.getCapability('type').getName();
|
|
||||||
|
|
||||||
if (parentDef === 'Notebook' && child.getCapability('status').list().length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
};
|
|
||||||
|
|
||||||
return CompositionPolicy;
|
|
||||||
}
|
|
||||||
);
|
|
@ -55,7 +55,7 @@ define(
|
|||||||
|
|
||||||
// A view is editable unless explicitly flagged as not
|
// A view is editable unless explicitly flagged as not
|
||||||
(views || []).forEach(function (view) {
|
(views || []).forEach(function (view) {
|
||||||
if (view.editable === true ||
|
if (isEditable(view) ||
|
||||||
(view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
|
(view.key === 'plot' && type.getKey() === 'telemetry.panel') ||
|
||||||
(view.key === 'table' && type.getKey() === 'table') ||
|
(view.key === 'table' && type.getKey() === 'table') ||
|
||||||
(view.key === 'rt-table' && type.getKey() === 'rttable')
|
(view.key === 'rt-table' && type.getKey() === 'rttable')
|
||||||
@ -64,6 +64,14 @@ define(
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function isEditable(view) {
|
||||||
|
if (typeof view.editable === Function) {
|
||||||
|
return view.editable(domainObject.useCapability('adapter'));
|
||||||
|
} else {
|
||||||
|
return view.editable === true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,294 +0,0 @@
|
|||||||
define([
|
|
||||||
"legacyRegistry",
|
|
||||||
"./src/controllers/NotebookController",
|
|
||||||
"./src/controllers/NewEntryController",
|
|
||||||
"./src/controllers/SelectSnapshotController",
|
|
||||||
"./src/controllers/LayoutNotebookController",
|
|
||||||
"./src/directives/MCTSnapshot",
|
|
||||||
"./src/directives/EntryDnd",
|
|
||||||
"./src/actions/ViewSnapshot",
|
|
||||||
"./src/actions/AnnotateSnapshot",
|
|
||||||
"./src/actions/RemoveEmbed",
|
|
||||||
"./src/actions/RemoveSnapshot",
|
|
||||||
"./src/actions/NewEntryContextual",
|
|
||||||
"./src/capabilities/NotebookCapability",
|
|
||||||
"./src/policies/CompositionPolicy",
|
|
||||||
"./res/templates/notebook.html",
|
|
||||||
"./res/templates/entry.html",
|
|
||||||
"./res/templates/annotation.html",
|
|
||||||
"./res/templates/notifications.html",
|
|
||||||
"../layout/res/templates/frame.html",
|
|
||||||
"./res/templates/controls/embedControl.html",
|
|
||||||
"./res/templates/controls/snapSelect.html"
|
|
||||||
], function (
|
|
||||||
legacyRegistry,
|
|
||||||
NotebookController,
|
|
||||||
NewEntryController,
|
|
||||||
SelectSnapshotController,
|
|
||||||
LayoutNotebookController,
|
|
||||||
MCTSnapshot,
|
|
||||||
MCTEntryDnd,
|
|
||||||
ViewSnapshotAction,
|
|
||||||
AnnotateSnapshotAction,
|
|
||||||
RemoveEmbedAction,
|
|
||||||
RemoveSnapshotAction,
|
|
||||||
newEntryAction,
|
|
||||||
NotebookCapability,
|
|
||||||
CompositionPolicy,
|
|
||||||
notebookTemplate,
|
|
||||||
entryTemplate,
|
|
||||||
annotationTemplate,
|
|
||||||
notificationsTemplate,
|
|
||||||
frameTemplate,
|
|
||||||
embedControlTemplate,
|
|
||||||
snapSelectTemplate
|
|
||||||
) {
|
|
||||||
legacyRegistry.register("platform/features/notebook", {
|
|
||||||
"name": "Notebook Plugin",
|
|
||||||
"description": "Create and save timestamped notes with embedded object snapshots.",
|
|
||||||
"extensions":
|
|
||||||
{
|
|
||||||
"types": [
|
|
||||||
{
|
|
||||||
"key": "notebook",
|
|
||||||
"name": "Notebook",
|
|
||||||
"cssClass": "icon-notebook",
|
|
||||||
"description": "Create and save timestamped notes with embedded object snapshots.",
|
|
||||||
"features": ["creation"],
|
|
||||||
"model": {
|
|
||||||
"entries": [],
|
|
||||||
"composition": [],
|
|
||||||
"entryTypes": [],
|
|
||||||
"defaultSort": "-createdOn"
|
|
||||||
},
|
|
||||||
"properties": [
|
|
||||||
{
|
|
||||||
"key": "defaultSort",
|
|
||||||
"name": "Default Sort",
|
|
||||||
"control": "select",
|
|
||||||
"options": [
|
|
||||||
{
|
|
||||||
"name": "Newest First",
|
|
||||||
"value": "-createdOn"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "Oldest First",
|
|
||||||
"value": "createdOn"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"cssClass": "l-inline"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"views": [
|
|
||||||
{
|
|
||||||
"key": "notebook.view",
|
|
||||||
"type": "notebook",
|
|
||||||
"cssClass": "icon-notebook",
|
|
||||||
"name": "notebook",
|
|
||||||
"template": notebookTemplate,
|
|
||||||
"editable": false,
|
|
||||||
"uses": [
|
|
||||||
"composition",
|
|
||||||
"action"
|
|
||||||
],
|
|
||||||
"gestures": [
|
|
||||||
"drop"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controllers": [
|
|
||||||
{
|
|
||||||
"key": "NotebookController",
|
|
||||||
"implementation": NotebookController,
|
|
||||||
"depends": [
|
|
||||||
"$scope",
|
|
||||||
"dialogService",
|
|
||||||
"popupService",
|
|
||||||
"agentService",
|
|
||||||
"objectService",
|
|
||||||
"navigationService",
|
|
||||||
"now",
|
|
||||||
"actionService",
|
|
||||||
"$timeout",
|
|
||||||
"$element",
|
|
||||||
"$sce"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "NewEntryController",
|
|
||||||
"implementation": NewEntryController,
|
|
||||||
"depends": ["$scope",
|
|
||||||
"$rootScope"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "selectSnapshotController",
|
|
||||||
"implementation": SelectSnapshotController,
|
|
||||||
"depends": ["$scope",
|
|
||||||
"$rootScope"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "LayoutNotebookController",
|
|
||||||
"implementation": LayoutNotebookController,
|
|
||||||
"depends": ["$scope"]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"representations": [
|
|
||||||
{
|
|
||||||
"key": "draggedEntry",
|
|
||||||
"template": entryTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "frameLayoutNotebook",
|
|
||||||
"template": frameTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"templates": [
|
|
||||||
{
|
|
||||||
"key": "annotate-snapshot",
|
|
||||||
"template": annotationTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "notificationTemplate",
|
|
||||||
"template": notificationsTemplate
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"directives": [
|
|
||||||
{
|
|
||||||
"key": "mctSnapshot",
|
|
||||||
"implementation": MCTSnapshot,
|
|
||||||
"depends": [
|
|
||||||
"$rootScope",
|
|
||||||
"$document",
|
|
||||||
"exportImageService",
|
|
||||||
"dialogService",
|
|
||||||
"notificationService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "mctEntryDnd",
|
|
||||||
"implementation": MCTEntryDnd,
|
|
||||||
"depends": [
|
|
||||||
"$rootScope",
|
|
||||||
"$compile",
|
|
||||||
"dndService",
|
|
||||||
"typeService",
|
|
||||||
"notificationService"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"actions": [
|
|
||||||
{
|
|
||||||
"key": "view-snapshot",
|
|
||||||
"implementation": ViewSnapshotAction,
|
|
||||||
"name": "View Snapshot",
|
|
||||||
"description": "View the large image in a modal",
|
|
||||||
"category": "embed",
|
|
||||||
"depends": [
|
|
||||||
"$compile"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "annotate-snapshot",
|
|
||||||
"implementation": AnnotateSnapshotAction,
|
|
||||||
"name": "Annotate Snapshot",
|
|
||||||
"cssClass": "icon-pencil labeled",
|
|
||||||
"description": "Annotate embed's snapshot",
|
|
||||||
"category": "embed",
|
|
||||||
"depends": [
|
|
||||||
"dialogService",
|
|
||||||
"dndService",
|
|
||||||
"$rootScope"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
"key": "remove-embed",
|
|
||||||
"implementation": RemoveEmbedAction,
|
|
||||||
"name": "Remove...",
|
|
||||||
"cssClass": "icon-trash labeled",
|
|
||||||
"description": "Remove this embed",
|
|
||||||
"category": [
|
|
||||||
"embed",
|
|
||||||
"embed-no-snap"
|
|
||||||
],
|
|
||||||
"depends": [
|
|
||||||
"dialogService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "remove-snapshot",
|
|
||||||
"implementation": RemoveSnapshotAction,
|
|
||||||
"name": "Remove Snapshot",
|
|
||||||
"cssClass": "icon-trash labeled",
|
|
||||||
"description": "Remove Snapshot of the embed",
|
|
||||||
"category": "embed",
|
|
||||||
"depends": [
|
|
||||||
"dialogService"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "notebook-new-entry",
|
|
||||||
"implementation": newEntryAction,
|
|
||||||
"name": "New Notebook Entry",
|
|
||||||
"cssClass": "icon-notebook labeled",
|
|
||||||
"description": "Add a new Notebook entry",
|
|
||||||
"category": [
|
|
||||||
"view-control"
|
|
||||||
],
|
|
||||||
"depends": [
|
|
||||||
"$compile",
|
|
||||||
"$rootScope",
|
|
||||||
"dialogService",
|
|
||||||
"notificationService",
|
|
||||||
"linkService"
|
|
||||||
],
|
|
||||||
"priority": "preferred"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"name": "painterro",
|
|
||||||
"version": "0.2.65",
|
|
||||||
"author": "Ivan Borshchov",
|
|
||||||
"description": "Painterro is JavaScript paint widget which allows editing images directly in a browser.",
|
|
||||||
"website": "https://github.com/ivictbor/painterro",
|
|
||||||
"copyright": "Copyright 2017 Ivan Borshchov",
|
|
||||||
"license": "MIT",
|
|
||||||
"link": "https://github.com/ivictbor/painterro/blob/master/LICENSE"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"capabilities": [
|
|
||||||
{
|
|
||||||
"key": "notebook",
|
|
||||||
"name": "Notebook Capability",
|
|
||||||
"description": "Provides a capability for looking for a notebook domain object",
|
|
||||||
"implementation": NotebookCapability,
|
|
||||||
"depends": [
|
|
||||||
"typeService"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"policies": [
|
|
||||||
{
|
|
||||||
"category": "composition",
|
|
||||||
"implementation": CompositionPolicy,
|
|
||||||
"message": "Objects of this type cannot contain objects of that type."
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"controls": [
|
|
||||||
{
|
|
||||||
"key": "embed-control",
|
|
||||||
"template": embedControlTemplate
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"key": "snapshot-select",
|
|
||||||
"template": snapSelectTemplate
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
@ -1,118 +0,0 @@
|
|||||||
<div ng-controller="NotebookController as controller" class="mct-notebook w-notebook l-flex-col">
|
|
||||||
<div class="l-notebook-head holder l-flex-row flex-elem">
|
|
||||||
<div class="c-search flex-elem holder grows">
|
|
||||||
<input class="c-search__search-input"
|
|
||||||
type="text" tabindex="10000"
|
|
||||||
ng-model="entrySearch"
|
|
||||||
ng-keyup="controller.search()"/>
|
|
||||||
<a class="c-search__clear-input clear-icon icon-x-in-circle"
|
|
||||||
ng-class="{show: !(entrySearch === '' || entrySearch === undefined)}"
|
|
||||||
ng-click="entrySearch = ''; controller.search()"></a>
|
|
||||||
</div>
|
|
||||||
<div class="notebook-view-controls l-flex-row flex-elem holder">
|
|
||||||
<div class="select notebook-view-controls__filter-time">
|
|
||||||
<select ng-model="showTime">
|
|
||||||
<option value="0" selected="selected">Show all</option>
|
|
||||||
<option value="1">Last hour</option>
|
|
||||||
<option value="8">Last 8 hours</option>
|
|
||||||
<option value="24">Last 24 hours</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
<div class="select notebook-view-controls__sort">
|
|
||||||
<select ng-model="sortEntries">
|
|
||||||
<option value="-createdOn" selected="selected">Newest first</option>
|
|
||||||
<option value="createdOn">Oldest first</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- drag area -->
|
|
||||||
<div class="holder flex-elem l-flex-row icon-plus labeled l-notebook-drag-area" ng-click="newEntry($event)"
|
|
||||||
id="newEntry" mct-entry-dnd>
|
|
||||||
<span class="label">To start a new entry, click here or drag and drop any object</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- entries -->
|
|
||||||
<div class="holder flex-elem grows w-notebook-entries t-entries-list" ng-mouseover="handleActive()">
|
|
||||||
<ul>
|
|
||||||
<li class="l-flex-row has-local-controls l-notebook-entry s-notebook-entry"
|
|
||||||
id="{{'entry_'+ entry.id}}"
|
|
||||||
ng-if="hoursFilter(showTime,entry.createdOn)"
|
|
||||||
ng-repeat="entry in model.entries | filter:entrySearch | orderBy: sortEntries track by $index"
|
|
||||||
ng-init="$last && finished(model.entries)"
|
|
||||||
mct-entry-dnd>
|
|
||||||
<div class="holder flex-elem l-flex-row grows w-notebook-entry-time-and-content">
|
|
||||||
<div class="holder flex-elem s-notebook-entry-time">
|
|
||||||
<span>{{entry.createdOn | date:'yyyy-MM-dd'}}</span>
|
|
||||||
<span>{{entry.createdOn | date:'HH:mm:ss'}}</span>
|
|
||||||
</div>
|
|
||||||
<div class="holder flex-elem l-flex-col grows l-notebook-entry-content">
|
|
||||||
<div contenteditable="true"
|
|
||||||
ng-blur="textBlur($event, entry.id)"
|
|
||||||
ng-focus="textFocus($event, entry.id)"
|
|
||||||
ng-model="entry.text"
|
|
||||||
placeholder="Enter text here"
|
|
||||||
class="flex-elem s-input-inline t-notebook-entry-input s-notebook-entry-text"
|
|
||||||
ng-bind="entry.text">
|
|
||||||
</div>
|
|
||||||
<!-- embeds -->
|
|
||||||
<div class="flex-elem entry-embeds l-flex-row">
|
|
||||||
<div class="l-flex-row l-entry-embed {{embed.cssClass}}"
|
|
||||||
ng-repeat="embed in entry.embeds track by $index"
|
|
||||||
ng-class="{ 'has-snapshot' : embed.snapshot }"
|
|
||||||
id="{{embed.id}}">
|
|
||||||
<div class="snap-thumb"
|
|
||||||
ng-if="embed.snapshot"
|
|
||||||
ng-click="viewSnapshot($event,embed.snapshot.src,embed.id,entry.createdOn,this,embed)">
|
|
||||||
<img ng-src="{{embed.snapshot.src}}" src="//:0" alt="{{embed.id}}">
|
|
||||||
</div>
|
|
||||||
<div class="embed-info l-flex-col">
|
|
||||||
<div class="embed-title object-header">
|
|
||||||
<a ng-click='navigate($event,embed.type)'>{{embed.name}}</a>
|
|
||||||
<a class='context-available' ng-click='openMenu($event,embed.type)'></a>
|
|
||||||
</div>
|
|
||||||
<div class="hide-menu" ng-show="false">
|
|
||||||
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
|
||||||
<div class="menu context-menu">
|
|
||||||
<ul>
|
|
||||||
<li ng-repeat="menu in menuEmbed"
|
|
||||||
ng-click="menu.perform($event,embed.snapshot.src,embed.id,entry.createdOn,this,embed)"
|
|
||||||
title="{{menu.getMetadata().description}}"
|
|
||||||
class="{{menu.getMetadata().cssClass}}"
|
|
||||||
ng-if="embed.snapshot">
|
|
||||||
{{menu.getMetadata().name}}
|
|
||||||
</li>
|
|
||||||
<li ng-repeat="menu in menuEmbedNoSnap"
|
|
||||||
ng-click="menu.perform($event,embed.snapshot.src,embed.id,entry.createdOn,this)"
|
|
||||||
title="{{menu.getMetadata().description}}"
|
|
||||||
class="{{menu.getMetadata().cssClass}}"
|
|
||||||
ng-if="!embed.snapshot">
|
|
||||||
{{menu.getMetadata().name}}
|
|
||||||
</li>
|
|
||||||
<li ng-repeat="menu in embedActions"
|
|
||||||
ng-click="menu.perform()"
|
|
||||||
title="{{menu.name}}"
|
|
||||||
class="{{menu.cssClass}}">
|
|
||||||
{{menu.name}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="embed-date"
|
|
||||||
ng-if="embed.snapshot">{{embed.id| date:'yyyy-MM-dd HH:mm:ss'}}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<!-- delete entry -->
|
|
||||||
<div class="holder flex-elem local-control local-controls-hidden notebook-entry-delete">
|
|
||||||
<a class="s-icon-button icon-trash" id={{entry.id}} title="Delete Entry" ng-click="deleteEntry($event)"></a>
|
|
||||||
</div>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,8 +0,0 @@
|
|||||||
<span class="status block">
|
|
||||||
<!-- DO NOT ADD SPACES BETWEEN THE SPANS - IT ADDS WHITE SPACE!! -->
|
|
||||||
<span class="status-indicator icon-bell"></span>
|
|
||||||
<span class="label">
|
|
||||||
Notifications
|
|
||||||
</span>
|
|
||||||
<span class="count"></span>
|
|
||||||
</span>
|
|
@ -1,34 +0,0 @@
|
|||||||
<div class="t-snapshot abs l-view-header">
|
|
||||||
<div class="abs object-browse-bar l-flex-row">
|
|
||||||
<div class="left flex-elem l-flex-row grows">
|
|
||||||
<div class="object-header flex-elem l-flex-row grows">
|
|
||||||
<div class="type-icon flex-elem embed-icon holder" ng-class="cssClass"></div>
|
|
||||||
<div class="title-label flex-elem holder flex-can-shrink">{{entryName}}</div>
|
|
||||||
<a class="context-available flex-elem holder" ng-click="openMenu($event,embedType)"></a>
|
|
||||||
<div class="hide-menu" ng-show="false">
|
|
||||||
<div class="menu-element menu-view context-menu-wrapper mobile-disable-select">
|
|
||||||
<div class="menu context-menu">
|
|
||||||
<ul>
|
|
||||||
<li ng-repeat="menu in embedActions"
|
|
||||||
ng-click="menuPerform(menu)"
|
|
||||||
title="{{menu.name}}"
|
|
||||||
class="{{menu.cssClass}}">
|
|
||||||
{{menu.name}}
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
|
|
||||||
<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">
|
|
||||||
SNAPSHOT {{snapDate | date:'yyyy-MM-dd HH:mm:ss'}}
|
|
||||||
</div>
|
|
||||||
<a class="s-button icon-pencil" title="Annotate">
|
|
||||||
<span class="title-label">Annotate</span>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@ -1,72 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2017, 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(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
function RemoveEmbed(dialogService,context) {
|
|
||||||
context = context || {};
|
|
||||||
|
|
||||||
this.domainObject = context.selectedObject || context.domainObject;
|
|
||||||
this.dialogService = dialogService;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
RemoveEmbed.prototype.perform = function ($event,snapshot,embedId,entryId) {
|
|
||||||
var domainObject = this.domainObject;
|
|
||||||
var errorDialog = this.dialogService.showBlockingMessage({
|
|
||||||
severity: "error",
|
|
||||||
title: "This action will permanently delete this Embed. Do you want to continue?",
|
|
||||||
minimized: true, // want the notification to be minimized initially (don't show banner)
|
|
||||||
options: [{
|
|
||||||
label: "OK",
|
|
||||||
callback: function () {
|
|
||||||
errorDialog.dismiss();
|
|
||||||
remove();
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
label: "Cancel",
|
|
||||||
callback: function () {
|
|
||||||
errorDialog.dismiss();
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
function remove() {
|
|
||||||
domainObject.useCapability('mutation', function (model) {
|
|
||||||
var elementPos = model.entries.map(function (x) {
|
|
||||||
return x.createdOn;
|
|
||||||
}).indexOf(entryId);
|
|
||||||
var entryEmbeds = model.entries[elementPos].embeds;
|
|
||||||
var embedPos = entryEmbeds.map(function (x) {
|
|
||||||
return x.id;
|
|
||||||
}).indexOf(embedId);
|
|
||||||
model.entries[elementPos].embeds.splice(embedPos, 1);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
return RemoveEmbed;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,74 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2017, 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(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
function RemoveSnapshot(dialogService, context) {
|
|
||||||
context = context || {};
|
|
||||||
|
|
||||||
this.domainObject = context.selectedObject || context.domainObject;
|
|
||||||
this.dialogService = dialogService;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
RemoveSnapshot.prototype.perform = function ($event, snapshot, embedId, entryId) {
|
|
||||||
|
|
||||||
var domainObject = this.domainObject;
|
|
||||||
var errorDialog = this.dialogService.showBlockingMessage({
|
|
||||||
severity: "error",
|
|
||||||
title: "This action will permanently delete this Snapshot. Do you want to continue?",
|
|
||||||
minimized: true, // want the notification to be minimized initially (don't show banner)
|
|
||||||
options: [{
|
|
||||||
label: "OK",
|
|
||||||
callback: function () {
|
|
||||||
errorDialog.dismiss();
|
|
||||||
remove();
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
label: "Cancel",
|
|
||||||
callback: function () {
|
|
||||||
errorDialog.dismiss();
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
|
|
||||||
function remove() {
|
|
||||||
domainObject.useCapability('mutation', function (model) {
|
|
||||||
var elementPos = model.entries.map(function (x) {
|
|
||||||
return x.createdOn;
|
|
||||||
}).indexOf(entryId);
|
|
||||||
var entryEmbeds = model.entries[elementPos].embeds;
|
|
||||||
var embedPos = entryEmbeds.map(function (x) {
|
|
||||||
return x.id;
|
|
||||||
}).indexOf(embedId);
|
|
||||||
model.entries[elementPos].embeds[embedPos].snapshot = "";
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
return RemoveSnapshot;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,132 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2017, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module defining ViewSnapshot
|
|
||||||
*/
|
|
||||||
|
|
||||||
var OVERLAY_TEMPLATE = '' +
|
|
||||||
' <div class="abs blocker"></div>' +
|
|
||||||
' <div class="abs outer-holder">' +
|
|
||||||
' <a class="close icon-x-in-circle"></a>' +
|
|
||||||
' <div class="abs inner-holder l-flex-col">' +
|
|
||||||
' <div class="t-contents flex-elem holder grows"></div>' +
|
|
||||||
' <div class="bottom-bar flex-elem holder">' +
|
|
||||||
' <a class="t-done s-button major">Done</a>' +
|
|
||||||
' </div>' +
|
|
||||||
' </div>' +
|
|
||||||
' </div>';
|
|
||||||
|
|
||||||
define([
|
|
||||||
'zepto',
|
|
||||||
"../../res/templates/snapshotHeader.html"
|
|
||||||
],
|
|
||||||
function ($, headerTemplate) {
|
|
||||||
|
|
||||||
var toggleOverlay,
|
|
||||||
overlay,
|
|
||||||
closeButton,
|
|
||||||
doneButton,
|
|
||||||
blocker,
|
|
||||||
overlayContainer,
|
|
||||||
img,
|
|
||||||
annotateButton,
|
|
||||||
annotateImg;
|
|
||||||
|
|
||||||
function ViewSnapshot($compile) {
|
|
||||||
this.$compile = $compile;
|
|
||||||
}
|
|
||||||
|
|
||||||
function openOverlay(url, header) {
|
|
||||||
overlay = document.createElement('div');
|
|
||||||
$(overlay).addClass('abs overlay l-large-view');
|
|
||||||
overlay.innerHTML = OVERLAY_TEMPLATE;
|
|
||||||
overlayContainer = overlay.querySelector('.t-contents');
|
|
||||||
closeButton = overlay.querySelector('a.close');
|
|
||||||
closeButton.addEventListener('click', toggleOverlay);
|
|
||||||
doneButton = overlay.querySelector('a.t-done');
|
|
||||||
doneButton.addEventListener('click', toggleOverlay);
|
|
||||||
blocker = overlay.querySelector('.abs.blocker');
|
|
||||||
blocker.addEventListener('click', toggleOverlay);
|
|
||||||
annotateButton = header.querySelector('a.icon-pencil');
|
|
||||||
annotateButton.addEventListener('click', annotateImg);
|
|
||||||
document.body.appendChild(overlay);
|
|
||||||
img = document.createElement('div');
|
|
||||||
$(img).addClass('abs object-holder t-image-holder s-image-holder');
|
|
||||||
img.innerHTML = '<div class="image-main s-image-main" style="background-image: url(' + url + ');"></div>';
|
|
||||||
overlayContainer.appendChild(header);
|
|
||||||
overlayContainer.appendChild(img);
|
|
||||||
}
|
|
||||||
|
|
||||||
function closeOverlay() {
|
|
||||||
overlayContainer.removeChild(img);
|
|
||||||
document.body.removeChild(overlay);
|
|
||||||
closeButton.removeEventListener('click', toggleOverlay);
|
|
||||||
closeButton = undefined;
|
|
||||||
doneButton.removeEventListener('click', toggleOverlay);
|
|
||||||
doneButton = undefined;
|
|
||||||
blocker.removeEventListener('click', toggleOverlay);
|
|
||||||
blocker = undefined;
|
|
||||||
overlayContainer = undefined;
|
|
||||||
overlay = undefined;
|
|
||||||
img = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
ViewSnapshot.prototype.perform = function ($event, snapshot, embedId, entryId, $scope, embed) {
|
|
||||||
var isOpen = false;
|
|
||||||
|
|
||||||
// onclick for menu items in overlay header context menu
|
|
||||||
$scope.menuPerform = function (menu) {
|
|
||||||
menu.perform();
|
|
||||||
closeOverlay();
|
|
||||||
};
|
|
||||||
|
|
||||||
// Create the overlay element and add it to the document's body
|
|
||||||
$scope.cssClass = embed.cssClass;
|
|
||||||
$scope.embedType = embed.type;
|
|
||||||
$scope.entryName = embed.name;
|
|
||||||
$scope.snapDate = +embedId;
|
|
||||||
var element = this.$compile(headerTemplate)($scope);
|
|
||||||
|
|
||||||
var annotateAction = $scope.action.getActions({category: 'embed'})[1];
|
|
||||||
|
|
||||||
toggleOverlay = function () {
|
|
||||||
if (!isOpen) {
|
|
||||||
openOverlay(snapshot, element[0]);
|
|
||||||
isOpen = true;
|
|
||||||
} else {
|
|
||||||
closeOverlay();
|
|
||||||
isOpen = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
annotateImg = function () {
|
|
||||||
closeOverlay();
|
|
||||||
annotateAction.perform($event, snapshot, embedId, entryId, $scope);
|
|
||||||
};
|
|
||||||
|
|
||||||
toggleOverlay();
|
|
||||||
};
|
|
||||||
|
|
||||||
return ViewSnapshot;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,50 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2017, 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(
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The notebook capability allows a domain object to know whether the
|
|
||||||
* notebook plugin is present or not.
|
|
||||||
*
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
function NotebookCapability(typeService, domainObject) {
|
|
||||||
this.domainObject = domainObject;
|
|
||||||
this.typeService = typeService;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns true if there is a notebook domain Object.
|
|
||||||
*
|
|
||||||
* @returns {Boolean}
|
|
||||||
*/
|
|
||||||
NotebookCapability.prototype.isNotebook = function () {
|
|
||||||
return !!this.typeService.getType('notebook');
|
|
||||||
};
|
|
||||||
|
|
||||||
return NotebookCapability;
|
|
||||||
}
|
|
||||||
);
|
|
@ -1,367 +0,0 @@
|
|||||||
/*****************************************************************************
|
|
||||||
* Open MCT, Copyright (c) 2014-2017, 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.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
/*-- main controller file, here is the core functionality of the notebook plugin --*/
|
|
||||||
|
|
||||||
define(
|
|
||||||
['zepto'],
|
|
||||||
function ($) {
|
|
||||||
|
|
||||||
|
|
||||||
function NotebookController(
|
|
||||||
$scope,
|
|
||||||
dialogService,
|
|
||||||
popupService,
|
|
||||||
agentService,
|
|
||||||
objectService,
|
|
||||||
navigationService,
|
|
||||||
now,
|
|
||||||
actionService,
|
|
||||||
$timeout,
|
|
||||||
$element,
|
|
||||||
$sce
|
|
||||||
) {
|
|
||||||
|
|
||||||
$scope.entriesEl = $(document.body).find('.t-entries-list');
|
|
||||||
$scope.sortEntries = $scope.domainObject.getModel().defaultSort;
|
|
||||||
$scope.showTime = "0";
|
|
||||||
$scope.editEntry = false;
|
|
||||||
$scope.entrySearch = '';
|
|
||||||
$scope.entryTypes = [];
|
|
||||||
$scope.embedActions = [];
|
|
||||||
$scope.currentEntryValue = '';
|
|
||||||
|
|
||||||
var SECONDS_IN_AN_HOUR = 60 * 60 * 1000;
|
|
||||||
|
|
||||||
this.scope = $scope;
|
|
||||||
|
|
||||||
$scope.hoursFilter = function (hours,entryTime) {
|
|
||||||
if (+hours) {
|
|
||||||
return entryTime > (Date.now() - SECONDS_IN_AN_HOUR * (+hours));
|
|
||||||
}else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.scrollToTop = function () {
|
|
||||||
var entriesContainer = $scope.entriesEl.parent();
|
|
||||||
entriesContainer[0].scrollTop = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.findEntryEl = function (entryId) {
|
|
||||||
var element = $($scope.entriesEl).find('#entry_' + entryId);
|
|
||||||
|
|
||||||
if (element[0]) {
|
|
||||||
return element.find("[contenteditable='true']");
|
|
||||||
} else {
|
|
||||||
var entries = $scope.entriesEl.children().children(),
|
|
||||||
lastOrFirst = $scope.sortEntries === "-createdOn" ? 0 : (entries.length - 1);
|
|
||||||
|
|
||||||
return $(entries[lastOrFirst]).find("[contenteditable='true']");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.findEntryPositionById = function (id) {
|
|
||||||
var foundId = -1;
|
|
||||||
|
|
||||||
$scope.domainObject.model.entries.forEach(function (element, index) {
|
|
||||||
if (element.id === id) {
|
|
||||||
foundId = index;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return foundId;
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.newEntry = function ($event) {
|
|
||||||
$scope.scrollToTop();
|
|
||||||
|
|
||||||
var entries = $scope.domainObject.model.entries,
|
|
||||||
lastEntry = entries[entries.length - 1],
|
|
||||||
id = Date.now();
|
|
||||||
|
|
||||||
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
|
|
||||||
var createdEntry = {'id': id, 'createdOn': id};
|
|
||||||
|
|
||||||
$scope.domainObject.useCapability('mutation', function (model) {
|
|
||||||
model.entries.push(createdEntry);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
$scope.findEntryEl(lastEntry.id).focus();
|
|
||||||
|
|
||||||
$scope.domainObject.useCapability('mutation', function (model) {
|
|
||||||
model.entries[entries.length - 1].createdOn = id;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
$scope.entrySearch = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
$scope.deleteEntry = function ($event) {
|
|
||||||
var delId = +$event.currentTarget.id;
|
|
||||||
var errorDialog = dialogService.showBlockingMessage({
|
|
||||||
severity: "error",
|
|
||||||
title: "This action will permanently delete this Notebook entry. Do you want to continue?",
|
|
||||||
minimized: true, // want the notification to be minimized initially (don't show banner)
|
|
||||||
options: [{
|
|
||||||
label: "OK",
|
|
||||||
callback: function () {
|
|
||||||
errorDialog.dismiss();
|
|
||||||
var elementPos = $scope.findEntryPositionById(delId);
|
|
||||||
|
|
||||||
if (elementPos !== -1) {
|
|
||||||
$scope.domainObject.useCapability('mutation', function (model) {
|
|
||||||
model.entries.splice(elementPos, 1);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
window.console.log('delete error');
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
},{
|
|
||||||
label: "Cancel",
|
|
||||||
callback: function () {
|
|
||||||
errorDialog.dismiss();
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.textFocus = function ($event, entryId) {
|
|
||||||
if ($event.srcElement) {
|
|
||||||
$scope.currentEntryValue = $event.srcElement.innerText;
|
|
||||||
} else {
|
|
||||||
$event.target.innerText = '';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//On text blur(when focus is removed)
|
|
||||||
$scope.textBlur = function ($event, entryId) {
|
|
||||||
// entryId is the unique numeric based on the original createdOn
|
|
||||||
if ($event.target) {
|
|
||||||
var elementPos = $scope.findEntryPositionById(+entryId);
|
|
||||||
|
|
||||||
// If the text of an entry has been changed, then update the text and the modifiedOn numeric
|
|
||||||
// Otherwise, don't do anything
|
|
||||||
if ($scope.currentEntryValue !== $event.target.innerText) {
|
|
||||||
$scope.domainObject.useCapability('mutation', function (model) {
|
|
||||||
model.entries[elementPos].text = $event.target.innerText;
|
|
||||||
model.entries[elementPos].modified = Date.now();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.finished = function (model) {
|
|
||||||
var lastEntry = model[model.length - 1];
|
|
||||||
|
|
||||||
if (!lastEntry.text) {
|
|
||||||
$scope.findEntryEl(lastEntry.id).focus();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.handleActive = function () {
|
|
||||||
var newEntry = $scope.entriesEl.find('.active');
|
|
||||||
if (newEntry) {
|
|
||||||
newEntry.removeClass('active');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
$scope.clearSearch = function () {
|
|
||||||
$scope.entrySearch = '';
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.viewSnapshot = function ($event,snapshot,embedId,entryId,$innerScope,domainObject) {
|
|
||||||
var viewAction = $scope.action.getActions({category: 'embed'})[0];
|
|
||||||
viewAction.perform($event, snapshot, embedId, entryId, $innerScope, domainObject);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.renderImage = function (img) {
|
|
||||||
return URL.createObjectURL(img);
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.getDomainObj = function (id) {
|
|
||||||
return objectService.getObjects([id]);
|
|
||||||
};
|
|
||||||
|
|
||||||
function refreshComp(change) {
|
|
||||||
if (change && change.length) {
|
|
||||||
change[0].getCapability('action').getActions({key: 'remove'})[0].perform();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.actionToMenuOption = function (action) {
|
|
||||||
return {
|
|
||||||
key: action.getMetadata().key,
|
|
||||||
name: action.getMetadata().name,
|
|
||||||
cssClass: action.getMetadata().cssClass,
|
|
||||||
perform: action.perform
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Maintain all "conclude-editing" and "save" actions in the
|
|
||||||
// present context.
|
|
||||||
function updateActions() {
|
|
||||||
$scope.menuEmbed = $scope.action ?
|
|
||||||
$scope.action.getActions({category: 'embed'}) :
|
|
||||||
[];
|
|
||||||
|
|
||||||
$scope.menuEmbedNoSnap = $scope.action ?
|
|
||||||
$scope.action.getActions({category: 'embed-no-snap'}) :
|
|
||||||
[];
|
|
||||||
|
|
||||||
$scope.menuActions = $scope.action ?
|
|
||||||
$scope.action.getActions({key: 'window'}) :
|
|
||||||
[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update set of actions whenever the action capability
|
|
||||||
// changes or becomes available.
|
|
||||||
$scope.$watch("action", updateActions);
|
|
||||||
|
|
||||||
$scope.navigate = function ($event,embedType) {
|
|
||||||
if ($event) {
|
|
||||||
$event.preventDefault();
|
|
||||||
}
|
|
||||||
$scope.getDomainObj(embedType).then(function (resp) {
|
|
||||||
navigationService.setNavigation(resp[embedType]);
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
$scope.saveSnap = function (url,embedPos,entryPos) {
|
|
||||||
var snapshot = false;
|
|
||||||
if (url) {
|
|
||||||
if (embedPos !== -1 && entryPos !== -1) {
|
|
||||||
var reader = new window.FileReader();
|
|
||||||
reader.readAsDataURL(url);
|
|
||||||
reader.onloadend = function () {
|
|
||||||
snapshot = reader.result;
|
|
||||||
$scope.domainObject.useCapability('mutation', function (model) {
|
|
||||||
if (model.entries[entryPos]) {
|
|
||||||
model.entries[entryPos].embeds[embedPos].snapshot = {
|
|
||||||
'src': snapshot,
|
|
||||||
'type': url.type,
|
|
||||||
'size': url.size,
|
|
||||||
'modified': Date.now()
|
|
||||||
};
|
|
||||||
model.entries[entryPos].embeds[embedPos].id = Date.now();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
$scope.domainObject.useCapability('mutation', function (model) {
|
|
||||||
model.entries[entryPos].embeds[embedPos].snapshot = snapshot;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/*---popups menu embeds----*/
|
|
||||||
|
|
||||||
function getEmbedActions(embedType) {
|
|
||||||
if (!$scope.embedActions.length) {
|
|
||||||
$scope.getDomainObj(embedType).then(function (resp) {
|
|
||||||
$scope.embedActions = [];
|
|
||||||
$scope.embedActions.push($scope.actionToMenuOption(
|
|
||||||
$scope.action.getActions({key: 'mct-preview-action', selectedObject: resp[embedType]})[0]
|
|
||||||
));
|
|
||||||
$scope.embedActions.push($scope.actionToMenuOption(
|
|
||||||
$scope.action.getActions({key: 'window', selectedObject: resp[embedType]})[0]
|
|
||||||
));
|
|
||||||
$scope.embedActions.push({
|
|
||||||
key: 'navigate',
|
|
||||||
name: 'Go to Original',
|
|
||||||
cssClass: '',
|
|
||||||
perform: function () {
|
|
||||||
$scope.navigate('', embedType);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$scope.openMenu = function ($event,embedType) {
|
|
||||||
$event.preventDefault();
|
|
||||||
|
|
||||||
getEmbedActions(embedType);
|
|
||||||
|
|
||||||
var body = $(document).find('body'),
|
|
||||||
initiatingEvent = agentService.isMobile() ?
|
|
||||||
'touchstart' : 'mousedown',
|
|
||||||
dismissExistingMenu,
|
|
||||||
menu;
|
|
||||||
|
|
||||||
var container = $($event.currentTarget).parent().parent();
|
|
||||||
|
|
||||||
menu = container.find('.menu-element');
|
|
||||||
|
|
||||||
// Remove the context menu
|
|
||||||
function dismiss() {
|
|
||||||
container.find('.hide-menu').append(menu);
|
|
||||||
body.off("mousedown", dismiss);
|
|
||||||
dismissExistingMenu = undefined;
|
|
||||||
$scope.embedActions = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dismiss any menu which was already showing
|
|
||||||
if (dismissExistingMenu) {
|
|
||||||
dismissExistingMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
// ...and record the presence of this menu.
|
|
||||||
dismissExistingMenu = dismiss;
|
|
||||||
|
|
||||||
popupService.display(menu, [$event.pageX,$event.pageY], {
|
|
||||||
marginX: 0,
|
|
||||||
marginY: -50
|
|
||||||
});
|
|
||||||
|
|
||||||
// Stop propagation so that clicks or touches on the menu do not close the menu
|
|
||||||
menu.on(initiatingEvent, function (event) {
|
|
||||||
event.stopPropagation();
|
|
||||||
$timeout(dismiss, 300);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Dismiss the menu when body is clicked/touched elsewhere
|
|
||||||
// ('mousedown' because 'click' breaks left-click context menus)
|
|
||||||
// ('touchstart' because 'touch' breaks context menus up)
|
|
||||||
body.on(initiatingEvent, dismiss);
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
$scope.$watchCollection("composition", refreshComp);
|
|
||||||
|
|
||||||
$scope.$watch('domainObject.getModel().defaultSort', function (newDefaultSort, oldDefaultSort) {
|
|
||||||
if (newDefaultSort !== oldDefaultSort) {
|
|
||||||
$scope.sortEntries = newDefaultSort;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
$scope.$on('$destroy', function () {});
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return NotebookController;
|
|
||||||
});
|
|
30
src/MCT.js
30
src/MCT.js
@ -35,8 +35,10 @@ define([
|
|||||||
'./ui/registries/InspectorViewRegistry',
|
'./ui/registries/InspectorViewRegistry',
|
||||||
'./ui/registries/ToolbarRegistry',
|
'./ui/registries/ToolbarRegistry',
|
||||||
'./ui/router/ApplicationRouter',
|
'./ui/router/ApplicationRouter',
|
||||||
|
'./ui/router/Browse',
|
||||||
'../platform/framework/src/Main',
|
'../platform/framework/src/Main',
|
||||||
'./styles-new/core.scss',
|
'./styles-new/core.scss',
|
||||||
|
'./styles-new/notebook.scss',
|
||||||
'./ui/components/layout/Layout.vue',
|
'./ui/components/layout/Layout.vue',
|
||||||
'vue'
|
'vue'
|
||||||
], function (
|
], function (
|
||||||
@ -54,8 +56,10 @@ define([
|
|||||||
InspectorViewRegistry,
|
InspectorViewRegistry,
|
||||||
ToolbarRegistry,
|
ToolbarRegistry,
|
||||||
ApplicationRouter,
|
ApplicationRouter,
|
||||||
|
Browse,
|
||||||
Main,
|
Main,
|
||||||
coreStyles,
|
coreStyles,
|
||||||
|
NotebookStyles,
|
||||||
Layout,
|
Layout,
|
||||||
Vue
|
Vue
|
||||||
) {
|
) {
|
||||||
@ -273,6 +277,7 @@ define([
|
|||||||
}.bind(this)
|
}.bind(this)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// TODO: remove with legacy types.
|
||||||
this.types.listKeys().forEach(function (typeKey) {
|
this.types.listKeys().forEach(function (typeKey) {
|
||||||
var type = this.types.get(typeKey);
|
var type = this.types.get(typeKey);
|
||||||
var legacyDefinition = type.toLegacyDefinition();
|
var legacyDefinition = type.toLegacyDefinition();
|
||||||
@ -280,26 +285,6 @@ define([
|
|||||||
this.legacyExtension('types', legacyDefinition);
|
this.legacyExtension('types', legacyDefinition);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
// TODO: move this to adapter bundle.
|
|
||||||
this.legacyExtension('runs', {
|
|
||||||
depends: ['types[]'],
|
|
||||||
implementation: (types) => {
|
|
||||||
this.types.importLegacyTypes(types);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.objectViews.getAllProviders().forEach(function (p) {
|
|
||||||
this.legacyExtension('views', {
|
|
||||||
key: p.key,
|
|
||||||
provider: p,
|
|
||||||
name: p.name,
|
|
||||||
cssClass: p.cssClass,
|
|
||||||
description: p.description,
|
|
||||||
editable: p.editable,
|
|
||||||
template: '<mct-view mct-provider-key="' + p.key + '"/>'
|
|
||||||
});
|
|
||||||
}, this);
|
|
||||||
|
|
||||||
legacyRegistry.register('adapter', this.legacyBundle);
|
legacyRegistry.register('adapter', this.legacyBundle);
|
||||||
legacyRegistry.enable('adapter');
|
legacyRegistry.enable('adapter');
|
||||||
|
|
||||||
@ -324,8 +309,6 @@ define([
|
|||||||
// something has depended upon objectService. Cool, right?
|
// something has depended upon objectService. Cool, right?
|
||||||
this.$injector.get('objectService');
|
this.$injector.get('objectService');
|
||||||
|
|
||||||
console.log('Rendering app layout.');
|
|
||||||
|
|
||||||
var appLayout = new Vue({
|
var appLayout = new Vue({
|
||||||
mixins: [Layout.default],
|
mixins: [Layout.default],
|
||||||
provide: {
|
provide: {
|
||||||
@ -334,7 +317,8 @@ define([
|
|||||||
});
|
});
|
||||||
domElement.appendChild(appLayout.$mount().$el);
|
domElement.appendChild(appLayout.$mount().$el);
|
||||||
|
|
||||||
|
this.layout = appLayout;
|
||||||
|
Browse(this);
|
||||||
this.router.start();
|
this.router.start();
|
||||||
this.emit('start');
|
this.emit('start');
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
@ -34,7 +34,9 @@ define([
|
|||||||
'./runs/TimeSettingsURLHandler',
|
'./runs/TimeSettingsURLHandler',
|
||||||
'./runs/TypeDeprecationChecker',
|
'./runs/TypeDeprecationChecker',
|
||||||
'./runs/LegacyTelemetryProvider',
|
'./runs/LegacyTelemetryProvider',
|
||||||
'./services/LegacyObjectAPIInterceptor'
|
'./runs/RegisterLegacyTypes',
|
||||||
|
'./services/LegacyObjectAPIInterceptor',
|
||||||
|
'./views/installLegacyViews'
|
||||||
], function (
|
], function (
|
||||||
legacyRegistry,
|
legacyRegistry,
|
||||||
ActionDialogDecorator,
|
ActionDialogDecorator,
|
||||||
@ -49,7 +51,9 @@ define([
|
|||||||
TimeSettingsURLHandler,
|
TimeSettingsURLHandler,
|
||||||
TypeDeprecationChecker,
|
TypeDeprecationChecker,
|
||||||
LegacyTelemetryProvider,
|
LegacyTelemetryProvider,
|
||||||
LegacyObjectAPIInterceptor
|
RegisterLegacyTypes,
|
||||||
|
LegacyObjectAPIInterceptor,
|
||||||
|
installLegacyViews
|
||||||
) {
|
) {
|
||||||
legacyRegistry.register('src/adapter', {
|
legacyRegistry.register('src/adapter', {
|
||||||
"extensions": {
|
"extensions": {
|
||||||
@ -149,6 +153,21 @@ define([
|
|||||||
"openmct",
|
"openmct",
|
||||||
"instantiate"
|
"instantiate"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
implementation: installLegacyViews,
|
||||||
|
depends: [
|
||||||
|
"openmct",
|
||||||
|
"views[]",
|
||||||
|
"instantiate"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
implementation: RegisterLegacyTypes,
|
||||||
|
depends: [
|
||||||
|
"types[]",
|
||||||
|
"openmct"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
licenses: [
|
licenses: [
|
||||||
|
17
src/adapter/runs/RegisterLegacyTypes.js
Normal file
17
src/adapter/runs/RegisterLegacyTypes.js
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
define([
|
||||||
|
|
||||||
|
], function (
|
||||||
|
|
||||||
|
) {
|
||||||
|
function RegisterLegacyTypes(types, openmct) {
|
||||||
|
types.forEach(function (legacyDefinition) {
|
||||||
|
if (!openmct.types.get(legacyDefinition.key)) {
|
||||||
|
console.warn(`DEPRECATION WARNING: Migrate type ${legacyDefinition.key} from ${legacyDefinition.bundle.path} to use the new Types API. Legacy type support will be removed soon.`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
openmct.types.importLegacyTypes(types);
|
||||||
|
}
|
||||||
|
|
||||||
|
return RegisterLegacyTypes;
|
||||||
|
});
|
93
src/adapter/views/LegacyViewProvider.js
Normal file
93
src/adapter/views/LegacyViewProvider.js
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
define([
|
||||||
|
|
||||||
|
], function (
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
function LegacyViewProvider(legacyView, openmct, convertToLegacyObject) {
|
||||||
|
console.warn(`DEPRECATION WARNING: Migrate ${legacyView.key} from ${legacyView.bundle.path} to use the new View APIs. Legacy view support will be removed soon.`);
|
||||||
|
return {
|
||||||
|
key: legacyView.key,
|
||||||
|
name: legacyView.name,
|
||||||
|
cssClass: legacyView.cssClass,
|
||||||
|
description: legacyView.description,
|
||||||
|
editable: legacyView.editable,
|
||||||
|
canView: function (domainObject) {
|
||||||
|
if (!domainObject || !domainObject.identifier) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (legacyView.type) {
|
||||||
|
return domainObject.type === legacyView.type;
|
||||||
|
}
|
||||||
|
let legacyObject = convertToLegacyObject(domainObject);
|
||||||
|
if (legacyView.needs) {
|
||||||
|
let meetsNeeds = legacyView.needs.every(k => legacyObject.hasCapability(k));
|
||||||
|
if (!meetsNeeds) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return openmct.$injector.get('policyService').allow(
|
||||||
|
'view', legacyView, legacyObject
|
||||||
|
);
|
||||||
|
},
|
||||||
|
view: function (domainObject) {
|
||||||
|
let $rootScope = openmct.$injector.get('$rootScope');
|
||||||
|
let templateLinker = openmct.$injector.get('templateLinker');
|
||||||
|
let scope = $rootScope.$new();
|
||||||
|
let legacyObject = convertToLegacyObject(domainObject);
|
||||||
|
let isDestroyed = false;
|
||||||
|
scope.domainObject = legacyObject;
|
||||||
|
scope.model = legacyObject.getModel();
|
||||||
|
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: function (container) {
|
||||||
|
// TODO: implement "gestures" support ?
|
||||||
|
let uses = legacyView.uses || [];
|
||||||
|
let promises = [];
|
||||||
|
let results = uses.map(function (capabilityKey, i) {
|
||||||
|
let result = legacyObject.useCapability(capabilityKey);
|
||||||
|
if (result.then) {
|
||||||
|
promises.push(result.then(function (r) {
|
||||||
|
results[i] = r;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
});
|
||||||
|
|
||||||
|
function link() {
|
||||||
|
if (isDestroyed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
uses.forEach(function (key, i) {
|
||||||
|
scope[key] = results[i];
|
||||||
|
});
|
||||||
|
templateLinker.link(
|
||||||
|
scope,
|
||||||
|
openmct.$angular.element(container),
|
||||||
|
legacyView
|
||||||
|
);
|
||||||
|
container.style.height = '100%';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (promises.length) {
|
||||||
|
Promise.all(promises)
|
||||||
|
.then(function () {
|
||||||
|
link();
|
||||||
|
scope.$digest();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
link();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
destroy: function () {
|
||||||
|
scope.$destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return LegacyViewProvider;
|
||||||
|
|
||||||
|
});
|
22
src/adapter/views/installLegacyViews.js
Normal file
22
src/adapter/views/installLegacyViews.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
define([
|
||||||
|
'./LegacyViewProvider',
|
||||||
|
'../../api/objects/object-utils'
|
||||||
|
], function (
|
||||||
|
LegacyViewProvider,
|
||||||
|
objectUtils
|
||||||
|
) {
|
||||||
|
function installLegacyViews(openmct, legacyViews, instantiate) {
|
||||||
|
|
||||||
|
function convertToLegacyObject(domainObject) {
|
||||||
|
let keyString = objectUtils.makeKeyString(domainObject.identifier);
|
||||||
|
let oldModel = objectUtils.toOldFormat(domainObject);
|
||||||
|
return instantiate(oldModel, keyString);
|
||||||
|
}
|
||||||
|
|
||||||
|
legacyViews.forEach(function (legacyView) {
|
||||||
|
openmct.objectViews.addProvider(new LegacyViewProvider(legacyView, openmct, convertToLegacyObject));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return installLegacyViews;
|
||||||
|
});
|
@ -89,12 +89,13 @@ define(function () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Array.isArray(legacyDefinition.creatable) && 'creation' in legacyDefinition.creatable) {
|
|
||||||
|
if (legacyDefinition.features && legacyDefinition.features.includes("creation")) {
|
||||||
definition.creatable = true;
|
definition.creatable = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return definition;
|
return definition;
|
||||||
}
|
};
|
||||||
|
|
||||||
return Type;
|
return Type;
|
||||||
});
|
});
|
||||||
|
@ -20,11 +20,10 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
define([
|
import CSV from 'comma-separated-values';
|
||||||
'csv',
|
import {saveAs} from 'file-saver/FileSaver';
|
||||||
'saveAs'
|
|
||||||
], function (CSV, saveAs) {
|
class CSVExporter {
|
||||||
class CSVExporter {
|
|
||||||
export(rows, options) {
|
export(rows, options) {
|
||||||
let headers = (options && options.headers) ||
|
let headers = (options && options.headers) ||
|
||||||
(Object.keys((rows[0] || {})).sort());
|
(Object.keys((rows[0] || {})).sort());
|
||||||
@ -33,7 +32,6 @@ define([
|
|||||||
let blob = new Blob([csvText], { type: "text/csv" });
|
let blob = new Blob([csvText], { type: "text/csv" });
|
||||||
saveAs(blob, filename);
|
saveAs(blob, filename);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
return CSVExporter;
|
export default CSVExporter;
|
||||||
});
|
|
||||||
|
215
src/plugins/notebook/plugin.js
Normal file
215
src/plugins/notebook/plugin.js
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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([
|
||||||
|
"./src/controllers/NotebookController",
|
||||||
|
"./src/controllers/NewEntryController",
|
||||||
|
"./src/controllers/SelectSnapshotController",
|
||||||
|
"./src/actions/NewEntryContextual",
|
||||||
|
"./src/actions/AnnotateSnapshot",
|
||||||
|
"./src/directives/MCTSnapshot",
|
||||||
|
"./src/directives/EntryDnd",
|
||||||
|
"./res/templates/controls/snapSelect.html",
|
||||||
|
"./res/templates/controls/embedControl.html",
|
||||||
|
"./res/templates/annotation.html",
|
||||||
|
"./res/templates/draggedEntry.html"
|
||||||
|
], function (
|
||||||
|
NotebookController,
|
||||||
|
NewEntryController,
|
||||||
|
SelectSnapshotController,
|
||||||
|
newEntryAction,
|
||||||
|
AnnotateSnapshotAction,
|
||||||
|
MCTSnapshotDirective,
|
||||||
|
EntryDndDirective,
|
||||||
|
snapSelectTemplate,
|
||||||
|
embedControlTemplate,
|
||||||
|
annotationTemplate,
|
||||||
|
draggedEntryTemplate
|
||||||
|
) {
|
||||||
|
var installed = false;
|
||||||
|
|
||||||
|
function NotebookPlugin() {
|
||||||
|
return function install(openmct) {
|
||||||
|
if (installed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
installed = true;
|
||||||
|
|
||||||
|
openmct.legacyRegistry.register('notebook', {
|
||||||
|
name: 'Notebook Plugin',
|
||||||
|
extensions: {
|
||||||
|
types: [
|
||||||
|
{
|
||||||
|
key: 'notebook',
|
||||||
|
name: 'Notebook',
|
||||||
|
cssClass: 'icon-notebook',
|
||||||
|
description: 'Create and save timestamped notes with embedded object snapshots.',
|
||||||
|
features: 'creation',
|
||||||
|
model: {
|
||||||
|
entries: [],
|
||||||
|
composition: [],
|
||||||
|
entryTypes: [],
|
||||||
|
defaultSort: '-createdOn'
|
||||||
|
},
|
||||||
|
properties: [
|
||||||
|
{
|
||||||
|
key: 'defaultSort',
|
||||||
|
name: 'Default Sort',
|
||||||
|
control: 'select',
|
||||||
|
options: [
|
||||||
|
{
|
||||||
|
name: 'Newest First',
|
||||||
|
value: "-createdOn",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Oldest First',
|
||||||
|
value: "createdOn"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
cssClass: 'l-inline'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
actions: [
|
||||||
|
{
|
||||||
|
"key": "notebook-new-entry",
|
||||||
|
"implementation": newEntryAction,
|
||||||
|
"name": "New Notebook Entry",
|
||||||
|
"cssClass": "icon-notebook labeled",
|
||||||
|
"description": "Add a new Notebook entry",
|
||||||
|
"category": [
|
||||||
|
"view-control"
|
||||||
|
],
|
||||||
|
"depends": [
|
||||||
|
"$compile",
|
||||||
|
"$rootScope",
|
||||||
|
"dialogService",
|
||||||
|
"notificationService",
|
||||||
|
"linkService"
|
||||||
|
],
|
||||||
|
"priority": "preferred"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "annotate-snapshot",
|
||||||
|
"implementation": AnnotateSnapshotAction,
|
||||||
|
"name": "Annotate Snapshot",
|
||||||
|
"cssClass": "icon-pencil labeled",
|
||||||
|
"description": "Annotate embed's snapshot",
|
||||||
|
"category": "embed",
|
||||||
|
"depends": [
|
||||||
|
"dialogService",
|
||||||
|
"dndService",
|
||||||
|
"$rootScope"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
controllers: [
|
||||||
|
{
|
||||||
|
"key": "NewEntryController",
|
||||||
|
"implementation": NewEntryController,
|
||||||
|
"depends": ["$scope",
|
||||||
|
"$rootScope"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "selectSnapshotController",
|
||||||
|
"implementation": SelectSnapshotController,
|
||||||
|
"depends": ["$scope",
|
||||||
|
"$rootScope"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
controls: [
|
||||||
|
{
|
||||||
|
"key": "snapshot-select",
|
||||||
|
"template": snapSelectTemplate
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "embed-control",
|
||||||
|
"template": embedControlTemplate
|
||||||
|
}
|
||||||
|
],
|
||||||
|
templates: [
|
||||||
|
{
|
||||||
|
"key": "annotate-snapshot",
|
||||||
|
"template": annotationTemplate
|
||||||
|
}
|
||||||
|
],
|
||||||
|
directives: [
|
||||||
|
{
|
||||||
|
"key": "mctSnapshot",
|
||||||
|
"implementation": MCTSnapshotDirective,
|
||||||
|
"depends": [
|
||||||
|
"$rootScope",
|
||||||
|
"$document",
|
||||||
|
"exportImageService",
|
||||||
|
"dialogService",
|
||||||
|
"notificationService"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"key": "mctEntryDnd",
|
||||||
|
"implementation": EntryDndDirective,
|
||||||
|
"depends": [
|
||||||
|
"$rootScope",
|
||||||
|
"$compile",
|
||||||
|
"dndService",
|
||||||
|
"typeService",
|
||||||
|
"notificationService"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
representations: [
|
||||||
|
{
|
||||||
|
"key": "draggedEntry",
|
||||||
|
"template": draggedEntryTemplate
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
openmct.legacyRegistry.enable('notebook');
|
||||||
|
|
||||||
|
openmct.objectViews.addProvider({
|
||||||
|
key: 'notebook-vue',
|
||||||
|
name: 'Notebook View',
|
||||||
|
cssClass: 'icon-notebook',
|
||||||
|
canView: function (domainObject) {
|
||||||
|
return domainObject.type === 'notebook';
|
||||||
|
},
|
||||||
|
view: function (domainObject) {
|
||||||
|
var controller = new NotebookController (openmct, domainObject);
|
||||||
|
|
||||||
|
return {
|
||||||
|
show: controller.show,
|
||||||
|
destroy: controller.destroy
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return NotebookPlugin;
|
||||||
|
});
|
@ -25,6 +25,5 @@
|
|||||||
ng-options="opt.value as opt.name for opt in options"
|
ng-options="opt.value as opt.name for opt in options"
|
||||||
ng-required="ngRequired"
|
ng-required="ngRequired"
|
||||||
name="mctControl">
|
name="mctControl">
|
||||||
<!-- <option value="" ng-show="!ngModel[field]">- Select One -</option> -->
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
32
src/plugins/notebook/res/templates/embed.html
Normal file
32
src/plugins/notebook/res/templates/embed.html
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
<div class="c-ne__embed">
|
||||||
|
<div class="c-ne__embed__snap-thumb"
|
||||||
|
v-if="embed.snapshot"
|
||||||
|
v-on:click="openSnapshot">
|
||||||
|
<img v-bind:src="embed.snapshot.src">
|
||||||
|
</div>
|
||||||
|
<div class="c-ne__embed__info">
|
||||||
|
<div class="c-ne__embed__name">
|
||||||
|
<a class="c-ne__embed__link"
|
||||||
|
v-on:click="navigate(embed.type)"
|
||||||
|
v-bind:class="[embed.cssClass]">{{embed.name}}</a>
|
||||||
|
<a class="c-ne__embed__context-available icon-arrow-down"
|
||||||
|
v-on:click="toggleActionMenu"></a>
|
||||||
|
</div>
|
||||||
|
<div class="hide-menu hidden">
|
||||||
|
<div class="menu-element context-menu-wrapper mobile-disable-select">
|
||||||
|
<div class="menu context-menu">
|
||||||
|
<ul>
|
||||||
|
<li v-for="action in actions"
|
||||||
|
v-bind:class="[action.cssClass]"
|
||||||
|
v-on:click="action.perform(embed, entry)">
|
||||||
|
{{ action.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="c-ne__embed__time" v-if="embed.snapshot">
|
||||||
|
{{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
35
src/plugins/notebook/res/templates/entry.html
Normal file
35
src/plugins/notebook/res/templates/entry.html
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
<li class="c-notebook__entry c-ne has-local-controls"
|
||||||
|
v-on:drop="dropOnEntry(entry.id)"
|
||||||
|
v-on:dragover="dragoverOnEntry"
|
||||||
|
>
|
||||||
|
<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>
|
||||||
|
</div>
|
||||||
|
<div class="c-ne__content">
|
||||||
|
<!-- TODO: fix styling for c-input-inline when SCSS is merged and remove s-input-inline class here -->
|
||||||
|
<div class="c-ne__text c-input-inline s-input-inline"
|
||||||
|
contenteditable="true"
|
||||||
|
ref="contenteditable"
|
||||||
|
v-on:blur="textBlur($event, entry.id)"
|
||||||
|
v-on:focus="textFocus($event, entry.id)"
|
||||||
|
v-bind:key="entry.id"
|
||||||
|
v-html="entry.text">
|
||||||
|
</div>
|
||||||
|
<div class="c-ne__embeds">
|
||||||
|
<notebook-embed
|
||||||
|
v-for="(embed, index) in entry.embeds"
|
||||||
|
v-bind:embed="embed"
|
||||||
|
v-bind:entry="entry"
|
||||||
|
></notebook-embed>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="c-ne__local-controls--hidden">
|
||||||
|
<a class="c-icon-button icon-trash"
|
||||||
|
title="Delete this entry"
|
||||||
|
v-on:click="deleteEntry"></a>
|
||||||
|
</div>
|
||||||
|
</li>
|
37
src/plugins/notebook/res/templates/notebook.html
Normal file
37
src/plugins/notebook/res/templates/notebook.html
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<div class="c-notebook">
|
||||||
|
<div class="c-notebook__head">
|
||||||
|
<search class="c-notebook__search"
|
||||||
|
v-model="entrySearch"
|
||||||
|
v-on:input="search($event)"
|
||||||
|
v-on:clear="entrySearch = ''; search($event)"></search>
|
||||||
|
<div class="c-notebook__controls">
|
||||||
|
<div class="select c-notebook__controls__time">
|
||||||
|
<select v-model="showTime">
|
||||||
|
<option value="0" selected="selected">Show all</option>
|
||||||
|
<option value="1">Last hour</option>
|
||||||
|
<option value="8">Last 8 hours</option>
|
||||||
|
<option value="24">Last 24 hours</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="select c-notebook__controls__sort">
|
||||||
|
<select v-model="sortEntries">
|
||||||
|
<option value="-createdOn" selected="selected">Newest first</option>
|
||||||
|
<option value="createdOn">Oldest first</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="c-notebook__drag-area icon-plus"
|
||||||
|
v-on:click="newEntry($event)"
|
||||||
|
id="newEntry" mct-entry-dnd>
|
||||||
|
<span class="c-notebook__drag-area__label">To start a new entry, click here or drag and drop any object</span>
|
||||||
|
</div>
|
||||||
|
<div class="c-notebook__entries" ng-mouseover="handleActive()">
|
||||||
|
<ul>
|
||||||
|
<notebook-entry
|
||||||
|
v-for="entry in filterBySearch(entries, entrySearch)"
|
||||||
|
v-bind:entry="entry"
|
||||||
|
></notebook-entry>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
50
src/plugins/notebook/res/templates/viewSnapshot.html
Normal file
50
src/plugins/notebook/res/templates/viewSnapshot.html
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
<div class="abs overlay l-large-view">
|
||||||
|
<div class="abs blocker" v-on:click="close"></div>
|
||||||
|
|
||||||
|
<div class="abs outer-holder">
|
||||||
|
|
||||||
|
<a
|
||||||
|
class="close icon-x-in-circle"
|
||||||
|
v-on:click="close">
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<div class="abs inner-holder l-flex-col">
|
||||||
|
<div class="t-contents flex-elem holder grows">
|
||||||
|
|
||||||
|
<div class="t-snapshot abs l-view-header">
|
||||||
|
<div class="abs object-browse-bar l-flex-row">
|
||||||
|
<div class="left flex-elem l-flex-row grows">
|
||||||
|
<div class="object-header flex-elem l-flex-row grows">
|
||||||
|
<div class="type-icon flex-elem embed-icon holder" v-bind:class="embed.cssClass"></div>
|
||||||
|
<div class="title-label flex-elem holder flex-can-shrink">{{embed.name}}</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="btn-bar right l-flex-row flex-elem flex-justify-end flex-fixed">
|
||||||
|
<div class="flex-elem holder flex-can-shrink s-snapshot-datetime">
|
||||||
|
SNAPSHOT {{formatTime(embed.createdOn, 'YYYY-MM-DD HH:mm:ss')}}
|
||||||
|
</div>
|
||||||
|
<a class="s-button icon-pencil" title="Annotate">
|
||||||
|
<span class="title-label">Annotate</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="abs object-holder t-image-holder s-image-holder">
|
||||||
|
<div
|
||||||
|
class="image-main s-image-main"
|
||||||
|
v-bind:style="{ backgroundImage: 'url(' + embed.snapshot.src + ')' }">
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="bottom-bar flex-elem holder"
|
||||||
|
v-on:click="close">
|
||||||
|
|
||||||
|
<a class="t-done s-button major">Done</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
@ -26,6 +26,7 @@
|
|||||||
define(
|
define(
|
||||||
["painterro", "zepto"],
|
["painterro", "zepto"],
|
||||||
function (Painterro, $) {
|
function (Painterro, $) {
|
||||||
|
|
||||||
var annotationStruct = {
|
var annotationStruct = {
|
||||||
title: "Annotate Snapshot",
|
title: "Annotate Snapshot",
|
||||||
template: "annotate-snapshot",
|
template: "annotate-snapshot",
|
||||||
@ -107,9 +108,6 @@ define(
|
|||||||
done(true);
|
done(true);
|
||||||
}
|
}
|
||||||
}).show(snapshot);
|
}).show(snapshot);
|
||||||
|
|
||||||
$(document.body).find('.ptro-icon-btn').addClass('s-button');
|
|
||||||
$(document.body).find('.ptro-input').addClass('s-button');
|
|
||||||
});
|
});
|
||||||
}];
|
}];
|
||||||
|
|
@ -90,7 +90,7 @@ define(
|
|||||||
var dialogService = this.dialogService;
|
var dialogService = this.dialogService;
|
||||||
var rootScope = this.$rootScope;
|
var rootScope = this.$rootScope;
|
||||||
rootScope.newEntryText = '';
|
rootScope.newEntryText = '';
|
||||||
// Create the overlay element and add it to the document's body
|
// // Create the overlay element and add it to the document's body
|
||||||
this.$rootScope.selObj = domainObj;
|
this.$rootScope.selObj = domainObj;
|
||||||
this.$rootScope.selValue = "";
|
this.$rootScope.selValue = "";
|
||||||
var newScope = rootScope.$new();
|
var newScope = rootScope.$new();
|
||||||
@ -187,7 +187,7 @@ define(
|
|||||||
var domainObject = context.domainObject;
|
var domainObject = context.domainObject;
|
||||||
|
|
||||||
if (domainObject) {
|
if (domainObject) {
|
||||||
if (domainObject.getModel().type === 'Notebook') {
|
if (domainObject.getModel().type === 'notebook') {
|
||||||
// do not allow in context of a notebook
|
// do not allow in context of a notebook
|
||||||
return false;
|
return false;
|
||||||
} else if (domainObject.getModel().type.includes('imagery')) {
|
} else if (domainObject.getModel().type.includes('imagery')) {
|
130
src/plugins/notebook/src/actions/snapshotAction.js
Normal file
130
src/plugins/notebook/src/actions/snapshotAction.js
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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(
|
||||||
|
['zepto'],
|
||||||
|
function ($) {
|
||||||
|
|
||||||
|
function SnapshotAction (exportImageService, dialogService, context) {
|
||||||
|
this.exportImageService = exportImageService;
|
||||||
|
this.dialogService = dialogService;
|
||||||
|
this.domainObject = context.domainObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
SnapshotAction.prototype.perform = function () {
|
||||||
|
var elementToSnapshot =
|
||||||
|
$(document.body).find(".overlay .object-holder")[0] ||
|
||||||
|
$(document.body).find("[key='representation.selected.key']")[0];
|
||||||
|
|
||||||
|
$(elementToSnapshot).addClass("s-status-taking-snapshot");
|
||||||
|
|
||||||
|
this.exportImageService.exportPNGtoSRC(elementToSnapshot).then(function (blob) {
|
||||||
|
$(elementToSnapshot).removeClass("s-status-taking-snapshot");
|
||||||
|
|
||||||
|
if (blob) {
|
||||||
|
var reader = new window.FileReader();
|
||||||
|
reader.readAsDataURL(blob);
|
||||||
|
reader.onloadend = function () {
|
||||||
|
this.saveSnapshot(reader.result, blob.type, blob.size);
|
||||||
|
}.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
SnapshotAction.prototype.saveSnapshot = function (imageURL, imageType, imageSize) {
|
||||||
|
var taskForm = this.generateTaskForm(),
|
||||||
|
domainObject = this.domainObject,
|
||||||
|
domainObjectId = domainObject.getId(),
|
||||||
|
cssClass = domainObject.getCapability('type').typeDef.cssClass,
|
||||||
|
name = domainObject.model.name;
|
||||||
|
|
||||||
|
this.dialogService.getDialogResponse(
|
||||||
|
'overlay-dialog',
|
||||||
|
taskForm,
|
||||||
|
function () {
|
||||||
|
return taskForm.value;
|
||||||
|
}
|
||||||
|
).then(function (options) {
|
||||||
|
var snapshotObject = {
|
||||||
|
src: imageURL,
|
||||||
|
type: imageType,
|
||||||
|
size: imageSize
|
||||||
|
};
|
||||||
|
|
||||||
|
options.notebook.useCapability('mutation', function (model) {
|
||||||
|
var date = Date.now();
|
||||||
|
|
||||||
|
model.entries.push({
|
||||||
|
id: 'entry-' + date,
|
||||||
|
createdOn: date,
|
||||||
|
text: options.entry,
|
||||||
|
embeds: [{
|
||||||
|
name: name,
|
||||||
|
cssClass: cssClass,
|
||||||
|
type: domainObjectId,
|
||||||
|
id: 'embed-' + date,
|
||||||
|
createdOn: date,
|
||||||
|
snapshot: snapshotObject
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
SnapshotAction.prototype.generateTaskForm = function () {
|
||||||
|
var taskForm = {
|
||||||
|
name: "Create a Notebook Entry",
|
||||||
|
hint: "Please select a Notebook",
|
||||||
|
sections: [{
|
||||||
|
rows: [{
|
||||||
|
name: 'Entry',
|
||||||
|
key: 'entry',
|
||||||
|
control: 'textarea',
|
||||||
|
required: false,
|
||||||
|
"cssClass": "l-textarea-sm"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Save in Notebook',
|
||||||
|
key: 'notebook',
|
||||||
|
control: 'locator',
|
||||||
|
validate: validateLocation
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
};
|
||||||
|
|
||||||
|
var overlayModel = {
|
||||||
|
title: taskForm.name,
|
||||||
|
message: 'AHAHAH',
|
||||||
|
structure: taskForm,
|
||||||
|
value: {'entry': ""}
|
||||||
|
};
|
||||||
|
|
||||||
|
function validateLocation(newParentObj) {
|
||||||
|
return newParentObj.model.type === 'notebook';
|
||||||
|
}
|
||||||
|
|
||||||
|
return overlayModel;
|
||||||
|
};
|
||||||
|
|
||||||
|
return SnapshotAction;
|
||||||
|
}
|
||||||
|
);
|
198
src/plugins/notebook/src/controllers/EmbedController.js
Normal file
198
src/plugins/notebook/src/controllers/EmbedController.js
Normal file
@ -0,0 +1,198 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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([
|
||||||
|
'moment',
|
||||||
|
'zepto',
|
||||||
|
'../utils/SnapshotOverlay',
|
||||||
|
],
|
||||||
|
function (
|
||||||
|
Moment,
|
||||||
|
$,
|
||||||
|
SnapshotOverlay
|
||||||
|
) {
|
||||||
|
function EmbedController (openmct, domainObject) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.objectService = openmct.$injector.get('objectService');
|
||||||
|
this.navigationService = openmct.$injector.get('navigationService');
|
||||||
|
this.popupService = openmct.$injector.get('popupService');
|
||||||
|
this.agentService = openmct.$injector.get('agentService');
|
||||||
|
this.dialogService = openmct.$injector.get('dialogService');
|
||||||
|
|
||||||
|
|
||||||
|
this.navigate = this.navigate.bind(this);
|
||||||
|
this.exposedData = this.exposedData.bind(this);
|
||||||
|
this.exposedMethods = this.exposedMethods.bind(this);
|
||||||
|
this.toggleActionMenu = this.toggleActionMenu.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
EmbedController.prototype.navigate = function (embedType) {
|
||||||
|
this.objectService.getObjects([embedType]).then(function (objects) {
|
||||||
|
this.navigationService.setNavigation(objects[embedType]);
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.openSnapshot = function () {
|
||||||
|
if (!this.snapshotOverlay) {
|
||||||
|
this.snapShotOverlay = new SnapshotOverlay(this.embed, this.formatTime);
|
||||||
|
} else {
|
||||||
|
this.snapShotOverlay = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.formatTime = function (unixTime, timeFormat) {
|
||||||
|
return Moment(unixTime).format(timeFormat);
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.findInArray = function (array, id) {
|
||||||
|
var foundId = -1;
|
||||||
|
|
||||||
|
array.forEach(function (element, index) {
|
||||||
|
if (element.id === id) {
|
||||||
|
foundId = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return foundId;
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.actionToMenuDecorator = function (action) {
|
||||||
|
return {
|
||||||
|
name: action.getMetadata().name,
|
||||||
|
cssClass: action.getMetadata().cssClass,
|
||||||
|
perform: action.perform
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.populateActionMenu = function (objectService, actionService) {
|
||||||
|
return function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
objectService.getObjects([self.embed.type]).then(function (resp) {
|
||||||
|
var domainObject = resp[self.embed.type],
|
||||||
|
previewAction = actionService.getActions({key: 'mct-preview-action', domainObject: domainObject})[0];
|
||||||
|
|
||||||
|
self.actions.push(self.actionToMenuDecorator(previewAction));
|
||||||
|
});
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.removeEmbedAction = function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
return {
|
||||||
|
name: 'Remove Embed',
|
||||||
|
cssClass: 'icon-trash',
|
||||||
|
perform: function (embed, entry) {
|
||||||
|
var entryPosition = self.findInArray(self.domainObject.entries, entry.id),
|
||||||
|
embedPosition = self.findInArray(entry.embeds, embed.id);
|
||||||
|
|
||||||
|
var warningDialog = self.dialogService.showBlockingMessage({
|
||||||
|
severity: "error",
|
||||||
|
title: "This action will permanently delete this embed. Do you wish to continue?",
|
||||||
|
options: [{
|
||||||
|
label: "OK",
|
||||||
|
callback: function () {
|
||||||
|
entry.embeds.splice(embedPosition, 1);
|
||||||
|
var dirString = 'entries[' + entryPosition + '].embeds';
|
||||||
|
|
||||||
|
self.openmct.objects.mutate(self.domainObject, dirString, entry.embeds);
|
||||||
|
|
||||||
|
warningDialog.dismiss();
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
label: "Cancel",
|
||||||
|
callback: function () {
|
||||||
|
warningDialog.dismiss();
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.toggleActionMenu = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
var body = $(document.body),
|
||||||
|
container = $(event.target.parentElement.parentElement),
|
||||||
|
initiatingEvent = this.agentService.isMobile() ?
|
||||||
|
'touchstart' : 'mousedown',
|
||||||
|
menu = container.find('.menu-element'),
|
||||||
|
dismissExistingMenu;
|
||||||
|
|
||||||
|
// Remove the context menu
|
||||||
|
function dismiss() {
|
||||||
|
container.find('.hide-menu').append(menu);
|
||||||
|
body.off(initiatingEvent, dismiss);
|
||||||
|
menu.off(initiatingEvent, menuClickHandler);
|
||||||
|
dismissExistingMenu = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function menuClickHandler(e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
window.setTimeout(dismiss, 300);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dismiss any menu which was already showing
|
||||||
|
if (dismissExistingMenu) {
|
||||||
|
dismissExistingMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...and record the presence of this menu.
|
||||||
|
dismissExistingMenu = dismiss;
|
||||||
|
|
||||||
|
this.popupService.display(menu, [event.pageX,event.pageY], {
|
||||||
|
marginX: 0,
|
||||||
|
marginY: -50
|
||||||
|
});
|
||||||
|
|
||||||
|
// Stop propagation so that clicks or touches on the menu do not close the menu
|
||||||
|
menu.on(initiatingEvent, menuClickHandler);
|
||||||
|
|
||||||
|
body.on(initiatingEvent, dismiss);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.exposedData = function () {
|
||||||
|
return {
|
||||||
|
actions: [this.removeEmbedAction()],
|
||||||
|
showActionMenu: false
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
EmbedController.prototype.exposedMethods = function () {
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
return {
|
||||||
|
navigate: self.navigate,
|
||||||
|
openSnapshot: self.openSnapshot,
|
||||||
|
formatTime: self.formatTime,
|
||||||
|
toggleActionMenu: self.toggleActionMenu,
|
||||||
|
actionToMenuDecorator: self.actionToMenuDecorator
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
return EmbedController;
|
||||||
|
});
|
150
src/plugins/notebook/src/controllers/EntryController.js
Normal file
150
src/plugins/notebook/src/controllers/EntryController.js
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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([
|
||||||
|
'moment'
|
||||||
|
],
|
||||||
|
function (
|
||||||
|
Moment
|
||||||
|
) {
|
||||||
|
|
||||||
|
function EntryController (openmct, domainObject) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.dndService = this.openmct.$injector.get('dndService');
|
||||||
|
this.dialogService = this.openmct.$injector.get('dialogService');
|
||||||
|
|
||||||
|
this.currentEntryValue = '';
|
||||||
|
|
||||||
|
this.exposedMethods = this.exposedMethods.bind(this);
|
||||||
|
this.exposedData = this.exposedData.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
EntryController.prototype.entryPosById = function (entryId) {
|
||||||
|
var foundId = -1;
|
||||||
|
|
||||||
|
this.domainObject.entries.forEach(function (element, index) {
|
||||||
|
if (element.id === entryId) {
|
||||||
|
foundId = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return foundId;
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.textFocus = function ($event) {
|
||||||
|
if ($event.target) {
|
||||||
|
this.currentEntryValue = $event.target.innerText;
|
||||||
|
} else {
|
||||||
|
$event.target.innerText = '';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.textBlur = function ($event, entryId) {
|
||||||
|
if ($event.target) {
|
||||||
|
var entryPos = this.entryPosById(entryId);
|
||||||
|
|
||||||
|
if (this.currentEntryValue !== $event.target.innerText) {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'entries[' + entryPos + '].text', $event.target.innerText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.formatTime = function (unixTime, timeFormat) {
|
||||||
|
return Moment(unixTime).format(timeFormat);
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.deleteEntry = function () {
|
||||||
|
var entryPos = this.entryPosById(this.entry.id),
|
||||||
|
domainObject = this.domainObject,
|
||||||
|
openmct = this.openmct;
|
||||||
|
|
||||||
|
if (entryPos !== -1) {
|
||||||
|
|
||||||
|
var errorDialog = this.dialogService.showBlockingMessage({
|
||||||
|
severity: "error",
|
||||||
|
title: "This action will permanently delete this Notebook entry. Do you wish to continue?",
|
||||||
|
options: [{
|
||||||
|
label: "OK",
|
||||||
|
callback: function () {
|
||||||
|
domainObject.entries.splice(entryPos, 1);
|
||||||
|
openmct.objects.mutate(domainObject, 'entries', domainObject.entries);
|
||||||
|
|
||||||
|
errorDialog.dismiss();
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
label: "Cancel",
|
||||||
|
callback: function () {
|
||||||
|
errorDialog.dismiss();
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.dropOnEntry = function (entryId) {
|
||||||
|
var selectedObject = this.dndService.getData('mct-domain-object'),
|
||||||
|
selectedObjectId = selectedObject.getId(),
|
||||||
|
selectedModel = selectedObject.getModel(),
|
||||||
|
cssClass = selectedObject.getCapability('type').typeDef.cssClass,
|
||||||
|
entryPos = this.entryPosById(entryId),
|
||||||
|
currentEntryEmbeds = this.domainObject.entries[entryPos].embeds,
|
||||||
|
newEmbed = {
|
||||||
|
type: selectedObjectId,
|
||||||
|
id: '' + Date.now(),
|
||||||
|
cssClass: cssClass,
|
||||||
|
name: selectedModel.name,
|
||||||
|
snapshot: ''
|
||||||
|
};
|
||||||
|
|
||||||
|
currentEntryEmbeds.push(newEmbed);
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'entries[' + entryPos + '].embeds', currentEntryEmbeds);
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.dragoverOnEntry = function () {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.exposedData = function () {
|
||||||
|
return {
|
||||||
|
openmct: this.openmct,
|
||||||
|
domainObject: this.domainObject,
|
||||||
|
dndService: this.dndService,
|
||||||
|
dialogService: this.dialogService,
|
||||||
|
currentEntryValue: this.currentEntryValue
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
EntryController.prototype.exposedMethods = function () {
|
||||||
|
return {
|
||||||
|
entryPosById: this.entryPosById,
|
||||||
|
textFocus: this.textFocus,
|
||||||
|
textBlur: this.textBlur,
|
||||||
|
formatTime: this.formatTime,
|
||||||
|
deleteEntry: this.deleteEntry,
|
||||||
|
dropOnEntry: this.dropOnEntry,
|
||||||
|
dragoverOnEntry: this.dragoverOnEntry
|
||||||
|
};
|
||||||
|
};
|
||||||
|
return EntryController;
|
||||||
|
});
|
@ -31,8 +31,7 @@ define(
|
|||||||
$scope.snapshot = undefined;
|
$scope.snapshot = undefined;
|
||||||
$scope.snapToggle = true;
|
$scope.snapToggle = true;
|
||||||
$scope.entryText = '';
|
$scope.entryText = '';
|
||||||
var annotateAction = $rootScope.selObj.getCapability('action').getActions(
|
var annotateAction = $rootScope.selObj.getCapability('action').getActions({key: 'annotate-snapshot'})[0];
|
||||||
{category: 'embed'})[1];
|
|
||||||
|
|
||||||
$scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = $rootScope.selObj;
|
$scope.$parent.$parent.ngModel[$scope.$parent.$parent.field] = $rootScope.selObj;
|
||||||
$scope.objectName = $rootScope.selObj.getModel().name;
|
$scope.objectName = $rootScope.selObj.getModel().name;
|
177
src/plugins/notebook/src/controllers/NotebookController.js
Normal file
177
src/plugins/notebook/src/controllers/NotebookController.js
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
/*****************************************************************************
|
||||||
|
* 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([
|
||||||
|
'vue',
|
||||||
|
'./EntryController',
|
||||||
|
'./EmbedController',
|
||||||
|
'../../res/templates/notebook.html',
|
||||||
|
'../../res/templates/entry.html',
|
||||||
|
'../../res/templates/embed.html',
|
||||||
|
'../../../../ui/components/controls/search.vue'
|
||||||
|
],
|
||||||
|
function (
|
||||||
|
Vue,
|
||||||
|
EntryController,
|
||||||
|
EmbedController,
|
||||||
|
NotebookTemplate,
|
||||||
|
EntryTemplate,
|
||||||
|
EmbedTemplate,
|
||||||
|
search
|
||||||
|
) {
|
||||||
|
|
||||||
|
function NotebookController(openmct, domainObject) {
|
||||||
|
this.openmct = openmct;
|
||||||
|
this.domainObject = domainObject;
|
||||||
|
this.entrySearch = '';
|
||||||
|
this.objectService = openmct.$injector.get('objectService');
|
||||||
|
this.actionService = openmct.$injector.get('actionService');
|
||||||
|
|
||||||
|
this.show = this.show.bind(this);
|
||||||
|
this.destroy = this.destroy.bind(this);
|
||||||
|
this.newEntry = this.newEntry.bind(this);
|
||||||
|
this.entryPosById = this.entryPosById.bind(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
NotebookController.prototype.initializeVue = function (container) {
|
||||||
|
var self = this,
|
||||||
|
entryController = new EntryController(this.openmct, this.domainObject),
|
||||||
|
embedController = new EmbedController(this.openmct, this.domainObject);
|
||||||
|
|
||||||
|
this.container = container;
|
||||||
|
|
||||||
|
var notebookEmbed = {
|
||||||
|
props:['embed', 'entry'],
|
||||||
|
template: EmbedTemplate,
|
||||||
|
data: embedController.exposedData,
|
||||||
|
methods: embedController.exposedMethods(),
|
||||||
|
beforeMount: embedController.populateActionMenu(self.objectService, self.actionService)
|
||||||
|
};
|
||||||
|
|
||||||
|
var entryComponent = {
|
||||||
|
props:['entry'],
|
||||||
|
template: EntryTemplate,
|
||||||
|
components: {
|
||||||
|
'notebook-embed': notebookEmbed
|
||||||
|
},
|
||||||
|
data: entryController.exposedData,
|
||||||
|
methods: entryController.exposedMethods(),
|
||||||
|
mounted: self.focusOnEntry
|
||||||
|
};
|
||||||
|
|
||||||
|
var notebookVue = Vue.extend({
|
||||||
|
template: NotebookTemplate,
|
||||||
|
components: {
|
||||||
|
'notebook-entry': entryComponent,
|
||||||
|
'search': search.default
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
entrySearch: self.entrySearch,
|
||||||
|
showTime: '0',
|
||||||
|
sortEntries: '-createdOn',
|
||||||
|
entries: self.domainObject.entries,
|
||||||
|
currentEntryValue: ''
|
||||||
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
search: function (event) {
|
||||||
|
if (event.target.value) {
|
||||||
|
this.entrySearch = event.target.value;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
newEntry: self.newEntry,
|
||||||
|
filterBySearch: self.filterBySearch
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.NotebookVue = new notebookVue();
|
||||||
|
container.appendChild(this.NotebookVue.$mount().$el);
|
||||||
|
};
|
||||||
|
|
||||||
|
NotebookController.prototype.newEntry = function (event) {
|
||||||
|
|
||||||
|
var entries = this.domainObject.entries,
|
||||||
|
lastEntryIndex = entries.length - 1,
|
||||||
|
lastEntry = entries[lastEntryIndex],
|
||||||
|
date = Date.now();
|
||||||
|
|
||||||
|
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds.length) {
|
||||||
|
var createdEntry = {'id': 'entry-' + date, 'createdOn': date, 'embeds':[]};
|
||||||
|
|
||||||
|
entries.push(createdEntry);
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'entries', entries);
|
||||||
|
} else {
|
||||||
|
lastEntry.createdOn = date;
|
||||||
|
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'entries[entries.length-1]', lastEntry);
|
||||||
|
this.focusOnEntry.bind(this.NotebookVue.$children[lastEntryIndex])();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.entrySearch = '';
|
||||||
|
};
|
||||||
|
|
||||||
|
NotebookController.prototype.entryPosById = function (entryId) {
|
||||||
|
var foundId = -1;
|
||||||
|
|
||||||
|
this.domainObject.entries.forEach(function (element, index) {
|
||||||
|
if (element.id === entryId) {
|
||||||
|
foundId = index;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return foundId;
|
||||||
|
};
|
||||||
|
|
||||||
|
NotebookController.prototype.focusOnEntry = function () {
|
||||||
|
if (!this.entry.text) {
|
||||||
|
this.$refs.contenteditable.focus();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NotebookController.prototype.filterBySearch = function (entryArray, filterString) {
|
||||||
|
if (filterString) {
|
||||||
|
var lowerCaseFilterString = filterString.toLowerCase();
|
||||||
|
|
||||||
|
return entryArray.filter(function (entry) {
|
||||||
|
if (entry.text) {
|
||||||
|
return entry.text.toLowerCase().includes(lowerCaseFilterString);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return entryArray;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
NotebookController.prototype.show = function (container) {
|
||||||
|
this.initializeVue(container);
|
||||||
|
};
|
||||||
|
|
||||||
|
NotebookController.prototype.destroy = function (container) {
|
||||||
|
this.NotebookVue.$destroy(true);
|
||||||
|
};
|
||||||
|
|
||||||
|
return NotebookController;
|
||||||
|
});
|
@ -31,9 +31,11 @@ define(['zepto'], function ($) {
|
|||||||
var selectedModel = selectedObject.getModel();
|
var selectedModel = selectedObject.getModel();
|
||||||
var cssClass = selectedObject.getCapability('type').typeDef.cssClass;
|
var cssClass = selectedObject.getCapability('type').typeDef.cssClass;
|
||||||
var entryId = -1;
|
var entryId = -1;
|
||||||
|
var embedId = -1;
|
||||||
$scope.clearSearch();
|
$scope.clearSearch();
|
||||||
if ($element[0].id === 'newEntry') {
|
if ($element[0].id === 'newEntry') {
|
||||||
entryId = $scope.domainObject.model.entries.length;
|
entryId = $scope.domainObject.model.entries.length;
|
||||||
|
embedId = 0;
|
||||||
var lastEntry = $scope.domainObject.model.entries[entryId - 1];
|
var lastEntry = $scope.domainObject.model.entries[entryId - 1];
|
||||||
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
|
if (lastEntry === undefined || lastEntry.text || lastEntry.embeds) {
|
||||||
$scope.domainObject.useCapability('mutation', function (model) {
|
$scope.domainObject.useCapability('mutation', function (model) {
|
||||||
@ -82,6 +84,8 @@ define(['zepto'], function ($) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
embedId = $scope.domainObject.model.entries[entryId].embeds.length - 1;
|
||||||
|
|
||||||
if (selectedObject) {
|
if (selectedObject) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
* Open MCT, Copyright (c) 2014-2017, United States Government
|
* Open MCT, Copyright (c) 2014-2018, United States Government
|
||||||
* as represented by the Administrator of the National Aeronautics and Space
|
* as represented by the Administrator of the National Aeronautics and Space
|
||||||
* Administration. All rights reserved.
|
* Administration. All rights reserved.
|
||||||
*
|
*
|
||||||
@ -20,35 +20,47 @@
|
|||||||
* at runtime from the About dialog for additional information.
|
* at runtime from the About dialog for additional information.
|
||||||
*****************************************************************************/
|
*****************************************************************************/
|
||||||
|
|
||||||
/**
|
|
||||||
* This bundle implements object types and associated views for
|
|
||||||
* display-building.
|
|
||||||
*/
|
|
||||||
define(
|
|
||||||
[],
|
|
||||||
function () {
|
|
||||||
|
|
||||||
/**
|
define([
|
||||||
* The LayoutNotebookController is responsible for supporting the
|
'vue',
|
||||||
* notebook feature creation on theLayout view.
|
'../../res/templates/viewSnapshot.html'
|
||||||
**/
|
], function (
|
||||||
|
Vue,
|
||||||
|
snapshotOverlayTemplate
|
||||||
|
) {
|
||||||
|
function SnapshotOverlay (embedObject, formatTime) {
|
||||||
|
this.embedObject = embedObject;
|
||||||
|
|
||||||
function LayoutNotebookController($scope) {
|
this.snapshotOverlayVue = new Vue({
|
||||||
$scope.hasNotebookAction = undefined;
|
template: snapshotOverlayTemplate,
|
||||||
|
data: function () {
|
||||||
$scope.newNotebook = undefined;
|
return {
|
||||||
|
embed: embedObject
|
||||||
var actions = $scope.domainObject.getCapability('action');
|
|
||||||
var notebookAction = actions.getActions({'key': 'notebook-new-entry'});
|
|
||||||
if (notebookAction.length > 0) {
|
|
||||||
$scope.hasNotebookAction = true;
|
|
||||||
$scope.newNotebook = function () {
|
|
||||||
notebookAction[0].perform();
|
|
||||||
};
|
};
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
close: this.close.bind(this),
|
||||||
|
formatTime: formatTime
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.open();
|
||||||
}
|
}
|
||||||
|
|
||||||
return LayoutNotebookController;
|
SnapshotOverlay.prototype.open = function () {
|
||||||
}
|
this.overlay = document.createElement('div');
|
||||||
);
|
this.overlay.classList.add('abs');
|
||||||
|
|
||||||
|
document.body.appendChild(this.overlay);
|
||||||
|
|
||||||
|
this.overlay.appendChild(this.snapshotOverlayVue.$mount().$el);
|
||||||
|
};
|
||||||
|
|
||||||
|
SnapshotOverlay.prototype.close = function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.snapshotOverlayVue.$destroy();
|
||||||
|
this.overlay.parentNode.removeChild(this.overlay);
|
||||||
|
};
|
||||||
|
|
||||||
|
return SnapshotOverlay;
|
||||||
|
});
|
@ -27,14 +27,14 @@ define([
|
|||||||
'./autoflow/AutoflowTabularPlugin',
|
'./autoflow/AutoflowTabularPlugin',
|
||||||
'./timeConductor/plugin',
|
'./timeConductor/plugin',
|
||||||
'../../example/imagery/plugin',
|
'../../example/imagery/plugin',
|
||||||
'../../platform/features/notebook/bundle',
|
|
||||||
'../../platform/import-export/bundle',
|
'../../platform/import-export/bundle',
|
||||||
'./summaryWidget/plugin',
|
'./summaryWidget/plugin',
|
||||||
'./URLIndicatorPlugin/URLIndicatorPlugin',
|
'./URLIndicatorPlugin/URLIndicatorPlugin',
|
||||||
'./telemetryMean/plugin',
|
'./telemetryMean/plugin',
|
||||||
'./plot/plugin',
|
'./plot/plugin',
|
||||||
'./telemetryTable/plugin',
|
'./telemetryTable/plugin',
|
||||||
'./staticRootPlugin/plugin'
|
'./staticRootPlugin/plugin',
|
||||||
|
'./notebook/plugin'
|
||||||
], function (
|
], function (
|
||||||
_,
|
_,
|
||||||
UTCTimeSystem,
|
UTCTimeSystem,
|
||||||
@ -42,19 +42,18 @@ define([
|
|||||||
AutoflowPlugin,
|
AutoflowPlugin,
|
||||||
TimeConductorPlugin,
|
TimeConductorPlugin,
|
||||||
ExampleImagery,
|
ExampleImagery,
|
||||||
Notebook,
|
|
||||||
ImportExport,
|
ImportExport,
|
||||||
SummaryWidget,
|
SummaryWidget,
|
||||||
URLIndicatorPlugin,
|
URLIndicatorPlugin,
|
||||||
TelemetryMean,
|
TelemetryMean,
|
||||||
PlotPlugin,
|
PlotPlugin,
|
||||||
TelemetryTablePlugin,
|
TelemetryTablePlugin,
|
||||||
StaticRootPlugin
|
StaticRootPlugin,
|
||||||
|
Notebook
|
||||||
) {
|
) {
|
||||||
var bundleMap = {
|
var bundleMap = {
|
||||||
LocalStorage: 'platform/persistence/local',
|
LocalStorage: 'platform/persistence/local',
|
||||||
MyItems: 'platform/features/my-items',
|
MyItems: 'platform/features/my-items'
|
||||||
Notebook: 'platform/features/notebook'
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var plugins = _.mapValues(bundleMap, function (bundleName, pluginName) {
|
var plugins = _.mapValues(bundleMap, function (bundleName, pluginName) {
|
||||||
@ -159,6 +158,7 @@ define([
|
|||||||
plugins.SummaryWidget = SummaryWidget;
|
plugins.SummaryWidget = SummaryWidget;
|
||||||
plugins.TelemetryMean = TelemetryMean;
|
plugins.TelemetryMean = TelemetryMean;
|
||||||
plugins.URLIndicator = URLIndicatorPlugin;
|
plugins.URLIndicator = URLIndicatorPlugin;
|
||||||
|
plugins.Notebook = Notebook;
|
||||||
|
|
||||||
return plugins;
|
return plugins;
|
||||||
});
|
});
|
||||||
|
@ -15,7 +15,8 @@ define([
|
|||||||
function SummaryWidgetViewProvider(openmct) {
|
function SummaryWidgetViewProvider(openmct) {
|
||||||
return {
|
return {
|
||||||
key: 'summary-widget-viewer',
|
key: 'summary-widget-viewer',
|
||||||
name: 'Widget View',
|
name: 'Summary View',
|
||||||
|
cssClass: 'icon-summary-widget',
|
||||||
canView: function (domainObject) {
|
canView: function (domainObject) {
|
||||||
return domainObject.type === 'summary-widget';
|
return domainObject.type === 'summary-widget';
|
||||||
},
|
},
|
||||||
|
@ -48,7 +48,12 @@ define(function () {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFormattedValue(telemetryDatum) {
|
getFormattedValue(telemetryDatum) {
|
||||||
return this.formatter.format(telemetryDatum);
|
let formattedValue = this.formatter.format(telemetryDatum);
|
||||||
|
if (typeof formattedValue !== 'string') {
|
||||||
|
return formattedValue.toString();
|
||||||
|
} else {
|
||||||
|
return formattedValue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -30,17 +30,16 @@ define([], function () {
|
|||||||
this.objectKeyString = objectKeyString;
|
this.objectKeyString = objectKeyString;
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormattedDatum() {
|
getFormattedDatum(headers) {
|
||||||
return Object.values(this.columns)
|
return Object.keys(headers).reduce((formattedDatum, columnKey) => {
|
||||||
.reduce((formattedDatum, column) => {
|
formattedDatum[columnKey] = this.getFormattedValue(columnKey);
|
||||||
formattedDatum[column.getKey()] = this.getFormattedValue(column.getKey());
|
|
||||||
return formattedDatum;
|
return formattedDatum;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
|
|
||||||
getFormattedValue(key) {
|
getFormattedValue(key) {
|
||||||
let column = this.columns[key];
|
let column = this.columns[key];
|
||||||
return column.getFormattedValue(this.datum[key]);
|
return column && column.getFormattedValue(this.datum[key]);
|
||||||
}
|
}
|
||||||
|
|
||||||
getRowLimitClass() {
|
getRowLimitClass() {
|
||||||
|
@ -35,12 +35,15 @@ define([
|
|||||||
return {
|
return {
|
||||||
key: 'table',
|
key: 'table',
|
||||||
name: 'Telemetry Table',
|
name: 'Telemetry Table',
|
||||||
editable: true,
|
cssClass: 'icon-tabular-realtime',
|
||||||
|
editable: function(domainObject) {
|
||||||
|
return domainObject.type === 'table';
|
||||||
|
},
|
||||||
canView: function (domainObject) {
|
canView: function (domainObject) {
|
||||||
return domainObject.type === 'table' || domainObject.hasOwnProperty('telemetry');
|
return domainObject.type === 'table' || domainObject.hasOwnProperty('telemetry');
|
||||||
},
|
},
|
||||||
view: function (domainObject) {
|
view: function (domainObject) {
|
||||||
let csvExporter = new CSVExporter();
|
let csvExporter = new CSVExporter.default();
|
||||||
let table = new TelemetryTable(domainObject, openmct);
|
let table = new TelemetryTable(domainObject, openmct);
|
||||||
let component;
|
let component;
|
||||||
return {
|
return {
|
||||||
|
@ -82,8 +82,7 @@ define(
|
|||||||
// Going to check for duplicates. Bound the search problem to
|
// Going to check for duplicates. Bound the search problem to
|
||||||
// items around the given time. Use sortedIndex because it
|
// items around the given time. Use sortedIndex because it
|
||||||
// employs a binary search which is O(log n). Can use binary search
|
// employs a binary search which is O(log n). Can use binary search
|
||||||
// based on time stamp because the array is guaranteed ordered due
|
// because the array is guaranteed ordered due to sorted insertion.
|
||||||
// to sorted insertion.
|
|
||||||
let startIx = this.sortedIndex(this.rows, row);
|
let startIx = this.sortedIndex(this.rows, row);
|
||||||
let endIx = undefined;
|
let endIx = undefined;
|
||||||
|
|
||||||
@ -113,15 +112,37 @@ define(
|
|||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
sortedIndex(rows, testRow, lodashFunction) {
|
sortedIndex(rows, testRow, lodashFunction) {
|
||||||
|
if (this.rows.length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
const sortOptionsKey = this.sortOptions.key;
|
const sortOptionsKey = this.sortOptions.key;
|
||||||
|
const testRowValue = testRow.datum[sortOptionsKey];
|
||||||
|
const firstValue = this.rows[0].datum[sortOptionsKey];
|
||||||
|
const lastValue = this.rows[this.rows.length - 1].datum[sortOptionsKey];
|
||||||
|
|
||||||
lodashFunction = lodashFunction || _.sortedIndex;
|
lodashFunction = lodashFunction || _.sortedIndex;
|
||||||
|
|
||||||
if (this.sortOptions.direction === 'asc') {
|
if (this.sortOptions.direction === 'asc') {
|
||||||
|
if (testRowValue > lastValue) {
|
||||||
|
return this.rows.length;
|
||||||
|
} else if (testRowValue === lastValue) {
|
||||||
|
return this.rows.length - 1;
|
||||||
|
} else if (testRowValue <= firstValue) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
return lodashFunction(rows, testRow, (thisRow) => {
|
return lodashFunction(rows, testRow, (thisRow) => {
|
||||||
return thisRow.datum[sortOptionsKey];
|
return thisRow.datum[sortOptionsKey];
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (testRowValue >= firstValue) {
|
||||||
|
return 0;
|
||||||
|
} else if (testRowValue < lastValue) {
|
||||||
|
return this.rows.length;
|
||||||
|
} else if (testRowValue === lastValue) {
|
||||||
|
return this.rows.length - 1;
|
||||||
} else {
|
} else {
|
||||||
const testRowValue = testRow.datum[this.sortOptions.key];
|
|
||||||
// Use a custom comparison function to support descending sort.
|
// Use a custom comparison function to support descending sort.
|
||||||
return lodashFunction(rows, testRow, (thisRow) => {
|
return lodashFunction(rows, testRow, (thisRow) => {
|
||||||
const thisRowValue = thisRow.datum[sortOptionsKey];
|
const thisRowValue = thisRow.datum[sortOptionsKey];
|
||||||
@ -135,6 +156,7 @@ define(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sorts the telemetry collection based on the provided sort field
|
* Sorts the telemetry collection based on the provided sort field
|
||||||
|
@ -15,7 +15,7 @@ export default {
|
|||||||
data: function () {
|
data: function () {
|
||||||
return {
|
return {
|
||||||
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
|
rowTop: (this.rowOffset + this.rowIndex) * this.rowHeight + 'px',
|
||||||
formattedRow: this.row.getFormattedDatum(),
|
formattedRow: this.row.getFormattedDatum(this.headers),
|
||||||
rowLimitClass: this.row.getRowLimitClass(),
|
rowLimitClass: this.row.getRowLimitClass(),
|
||||||
cellLimitClasses: this.row.getCellLimitClasses()
|
cellLimitClasses: this.row.getCellLimitClasses()
|
||||||
}
|
}
|
||||||
@ -32,7 +32,9 @@ export default {
|
|||||||
columnWidths: {
|
columnWidths: {
|
||||||
type: Array,
|
type: Array,
|
||||||
required: false,
|
required: false,
|
||||||
default: [],
|
default() {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
},
|
},
|
||||||
rowIndex: {
|
rowIndex: {
|
||||||
type: Number,
|
type: Number,
|
||||||
@ -48,10 +50,6 @@ export default {
|
|||||||
type: Number,
|
type: Number,
|
||||||
required: false,
|
required: false,
|
||||||
default: 0
|
default: 0
|
||||||
},
|
|
||||||
configuration: {
|
|
||||||
type: Object,
|
|
||||||
required: true
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
@ -59,7 +57,7 @@ export default {
|
|||||||
this.rowTop = (rowOffset + this.rowIndex) * this.rowHeight + 'px';
|
this.rowTop = (rowOffset + this.rowIndex) * this.rowHeight + 'px';
|
||||||
},
|
},
|
||||||
formatRow: function (row) {
|
formatRow: function (row) {
|
||||||
this.formattedRow = row.getFormattedDatum();
|
this.formattedRow = row.getFormattedDatum(this.headers);
|
||||||
this.rowLimitClass = row.getRowLimitClass();
|
this.rowLimitClass = row.getRowLimitClass();
|
||||||
this.cellLimitClasses = row.getCellLimitClasses();
|
this.cellLimitClasses = row.getCellLimitClasses();
|
||||||
}
|
}
|
||||||
|
@ -19,16 +19,16 @@
|
|||||||
:class="['is-sortable', sortOptions.key === key ? 'is-sorting' : '', sortOptions.direction].join(' ')"
|
:class="['is-sortable', sortOptions.key === key ? 'is-sorting' : '', sortOptions.direction].join(' ')"
|
||||||
:style="{ width: columnWidths[headerIndex], 'max-width': columnWidths[headerIndex]}">{{title}}</th>
|
:style="{ width: columnWidths[headerIndex], 'max-width': columnWidths[headerIndex]}">{{title}}</th>
|
||||||
</tr>
|
</tr>
|
||||||
<tr class="s-filters">
|
<tr>
|
||||||
<th v-for="(title, key, headerIndex) in headers"
|
<th v-for="(title, key, headerIndex) in headers"
|
||||||
:style="{
|
:style="{
|
||||||
width: columnWidths[headerIndex],
|
width: columnWidths[headerIndex],
|
||||||
'max-width': columnWidths[headerIndex],
|
'max-width': columnWidths[headerIndex],
|
||||||
}">
|
}">
|
||||||
<div class="holder l-filter flex-elem grows" :class="{active: filters[key]}">
|
<search class="c-table__search"
|
||||||
<input type="text" v-model="filters[key]" v-on:input="filterChanged(key)" />
|
v-model="filters[key]"
|
||||||
<a class="clear-icon clear-input icon-x-in-circle" :class="{show: filters[key]}" @click="clearFilter(key)"></a>
|
v-on:input="filterChanged(key)"
|
||||||
</div>
|
v-on:clear="clearFilter(key)" />
|
||||||
</th>
|
</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -266,6 +266,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
import TelemetryTableRow from './table-row.vue';
|
import TelemetryTableRow from './table-row.vue';
|
||||||
|
import search from '../../../ui/components/controls/search.vue';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
const VISIBLE_ROW_COUNT = 100;
|
const VISIBLE_ROW_COUNT = 100;
|
||||||
@ -275,14 +276,14 @@ const AUTO_SCROLL_TRIGGER_HEIGHT = 20;
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
TelemetryTableRow
|
TelemetryTableRow,
|
||||||
|
search
|
||||||
},
|
},
|
||||||
inject: ['table', 'openmct', 'csvExporter'],
|
inject: ['table', 'openmct', 'csvExporter'],
|
||||||
props: ['configuration'],
|
props: ['configuration'],
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
headers: {},
|
headers: {},
|
||||||
headersCount: 0,
|
|
||||||
visibleRows: [],
|
visibleRows: [],
|
||||||
columnWidths: [],
|
columnWidths: [],
|
||||||
sizingRows: {},
|
sizingRows: {},
|
||||||
@ -346,7 +347,6 @@ export default {
|
|||||||
let headers = this.table.configuration.getVisibleHeaders();
|
let headers = this.table.configuration.getVisibleHeaders();
|
||||||
|
|
||||||
this.headers = headers;
|
this.headers = headers;
|
||||||
this.headersCount = Object.values(headers).length;
|
|
||||||
this.$nextTick().then(this.calculateColumnWidths);
|
this.$nextTick().then(this.calculateColumnWidths);
|
||||||
},
|
},
|
||||||
setSizingTableWidth() {
|
setSizingTableWidth() {
|
||||||
@ -454,12 +454,12 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
exportAsCSV() {
|
exportAsCSV() {
|
||||||
|
const headerKeys = Object.keys(this.headers);
|
||||||
const justTheData = this.table.filteredRows.getRows()
|
const justTheData = this.table.filteredRows.getRows()
|
||||||
.map(row => row.getFormattedDatum());
|
.map(row => row.getFormattedDatum(this.headers));
|
||||||
const headers = Object.keys(this.headers);
|
|
||||||
this.csvExporter.export(justTheData, {
|
this.csvExporter.export(justTheData, {
|
||||||
filename: this.table.domainObject.name + '.csv',
|
filename: this.table.domainObject.name + '.csv',
|
||||||
headers: headers
|
headers: headerKeys
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
outstandingRequests(loading) {
|
outstandingRequests(loading) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
@import "constants";
|
@import "constants";
|
||||||
|
|
||||||
// Mixins
|
// Functions
|
||||||
@function pullForward($c: $colorBodyBg, $p: 20%) {
|
@function pullForward($c: $colorBodyBg, $p: 20%) {
|
||||||
// For dark interfaces, lighter things come forward - opposite for light interfaces
|
// For dark interfaces, lighter things come forward - opposite for light interfaces
|
||||||
@return darken($c, $p);
|
@return darken($c, $p);
|
||||||
@ -12,7 +12,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Global
|
// Global
|
||||||
$fontBaseSize: 13px;
|
$fontBaseSize: 12px;
|
||||||
$colorBodyBg: #fcfcfc;
|
$colorBodyBg: #fcfcfc;
|
||||||
$colorBodyFg: #666;
|
$colorBodyFg: #666;
|
||||||
$colorGenBg: #fff;
|
$colorGenBg: #fff;
|
||||||
@ -71,6 +71,7 @@ $sliderKnobR: 2px;
|
|||||||
$timeControllerToiLineColor: $colorBodyFg;
|
$timeControllerToiLineColor: $colorBodyFg;
|
||||||
$timeControllerToiLineColorHov: #0052b5;
|
$timeControllerToiLineColorHov: #0052b5;
|
||||||
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
|
$colorTransLucBg: #666; // Used as a visual blocking element over variable backgrounds, like imagery
|
||||||
|
$createBtnTextTransform: uppercase;
|
||||||
|
|
||||||
// Foundation Colors
|
// Foundation Colors
|
||||||
$colorAlt1: #776ba2;
|
$colorAlt1: #776ba2;
|
||||||
@ -293,3 +294,16 @@ $colorLoadingBg: rgba($colorLoadingFg, 0.1);
|
|||||||
// Transitions
|
// Transitions
|
||||||
$transIn: all 50ms ease-in;
|
$transIn: all 50ms ease-in;
|
||||||
$transOut: all 250ms ease-out;
|
$transOut: all 250ms ease-out;
|
||||||
|
|
||||||
|
// Discrete items, like Notebook entries, Widget rules
|
||||||
|
@mixin discreteItem() {
|
||||||
|
background: rgba($colorBodyFg,0.1);
|
||||||
|
border: 1px solid $colorInteriorBorder;
|
||||||
|
border-radius: $controlCr;
|
||||||
|
.c-input-inline:hover {
|
||||||
|
background: $colorBodyBg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@mixin discreteItemInnerElem() {
|
||||||
|
border: 1px solid $colorBodyBg;
|
||||||
|
border-radius: $controlCr; }
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
/**************************** BUTTONS */
|
/******************************************************** BUTTONS */
|
||||||
%c-control {
|
%c-control {
|
||||||
@include userSelectNone();
|
@include userSelectNone();
|
||||||
|
$fs: 1em;
|
||||||
display: inline-flex;
|
display: inline-flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
font-size: $fs;
|
||||||
justify-content: start;
|
justify-content: start;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
@ -13,12 +15,13 @@
|
|||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:before {
|
&:after {
|
||||||
font-size: 0.8em;
|
font-size: 0.8em;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:after {
|
[class*="__label"] {
|
||||||
font-size: 0.6em;
|
line-height: $fs; // Remove effect on top and bottom padding
|
||||||
|
font-size: $fs;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -47,8 +50,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/********* Buttons */
|
/********* Buttons */
|
||||||
// Optionally can include icon in :before
|
// Optionally can include icon in :before via markup
|
||||||
.c-button {
|
.c-button,
|
||||||
|
button {
|
||||||
@extend %c-button;
|
@extend %c-button;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,10 +60,14 @@
|
|||||||
.c-icon-button {
|
.c-icon-button {
|
||||||
// A clickable element that just includes the icon, no background
|
// A clickable element that just includes the icon, no background
|
||||||
// Padding is included to facilitate a bigger hit area
|
// Padding is included to facilitate a bigger hit area
|
||||||
|
// Make the icon bigger relative to its container
|
||||||
@extend %c-control;
|
@extend %c-control;
|
||||||
|
$pLR: 3px;
|
||||||
|
$pTB: 3px;
|
||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
color: $colorKey;
|
color: $colorKey;
|
||||||
padding: nth($btnPad, 1) floor(nth($btnPad, 2) * 0.8);
|
font-size: $fontBaseSize * 1.2;
|
||||||
|
padding: $pTB $pLR ;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background: rgba($colorKey, 0.2);
|
background: rgba($colorKey, 0.2);
|
||||||
@ -77,7 +85,7 @@
|
|||||||
// c-icon-buttons get grouped more closely together
|
// c-icon-buttons get grouped more closely together
|
||||||
// When one set is adjacent to another, provides a divider between
|
// When one set is adjacent to another, provides a divider between
|
||||||
|
|
||||||
display: flex;
|
display: inline-flex;
|
||||||
|
|
||||||
> * {
|
> * {
|
||||||
// Assume buttons are immediate descendants
|
// Assume buttons are immediate descendants
|
||||||
@ -118,6 +126,8 @@
|
|||||||
/********* Menu Buttons */
|
/********* Menu Buttons */
|
||||||
// Always includes :after dropdown arrow
|
// Always includes :after dropdown arrow
|
||||||
// Optionally can include icon in :before
|
// Optionally can include icon in :before
|
||||||
|
// Default menu position is down and to the right
|
||||||
|
// Apply c-menu-button--menus-up and c-menu-button--menus-left to --w wrapper element to modify menu position
|
||||||
.c-menu-button {
|
.c-menu-button {
|
||||||
$m: $interiorMarginSm;
|
$m: $interiorMarginSm;
|
||||||
@extend %c-button;
|
@extend %c-button;
|
||||||
@ -132,9 +142,106 @@
|
|||||||
margin-left: $m;
|
margin-left: $m;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--w {
|
||||||
|
// Wraps c-menu-button, contains button and menu
|
||||||
|
.c-menu {
|
||||||
|
// Default position
|
||||||
|
top: 100%; left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.c-menu-button--menus-up {
|
||||||
|
.c-menu {
|
||||||
|
top: auto; bottom: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.c-menu-button--menus-left {
|
||||||
|
.c-menu {
|
||||||
|
left: auto; right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**************************** MENUS */
|
/******************************************************** DISCLOSURE CONTROLS */
|
||||||
|
/********* Disclosure Button */
|
||||||
|
// Provides a downward arrow icon that when clicked displays a context menu
|
||||||
|
// Always placed AFTER an element
|
||||||
|
.c-disclosure-button {
|
||||||
|
@extend .c-icon-button;
|
||||||
|
margin-left: $interiorMarginSm;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
content: $glyph-icon-arrow-down;
|
||||||
|
font-family: symbolsfont;
|
||||||
|
font-size: 0.7em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/********* Disclosure Triangle */
|
||||||
|
// Provides an arrow icon that when clicked expands an element to reveal its contents.
|
||||||
|
// Used in tree items. Always placed BEFORE an element.
|
||||||
|
.c-disclosure-triangle {
|
||||||
|
$d: 12px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
width: $d;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&.is-enabled:before {
|
||||||
|
$s: .65;
|
||||||
|
content: $glyph-icon-arrow-right-equilateral;
|
||||||
|
display: block;
|
||||||
|
font-family: symbolsfont;
|
||||||
|
font-size: 1rem * $s;
|
||||||
|
position: absolute;
|
||||||
|
transform-origin: floor(($d / 2) * $s); // This is slightly better than 'center'
|
||||||
|
transition: transform 100ms ease-in-out;
|
||||||
|
}
|
||||||
|
|
||||||
|
&--expanded {
|
||||||
|
&:before {
|
||||||
|
transform: rotate(90deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************** FORM ELEMENTS */
|
||||||
|
/********* Inline inputs */
|
||||||
|
// A text input or contenteditable element that indicates edit affordance on hover and looks like an input on focus
|
||||||
|
.c-input-inline {
|
||||||
|
@include input-base();
|
||||||
|
border: 1px solid transparent;
|
||||||
|
display: block !important;
|
||||||
|
min-width: 0;
|
||||||
|
padding-left: 0;
|
||||||
|
padding-right: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
transition: all 250ms ease;
|
||||||
|
white-space: nowrap;
|
||||||
|
|
||||||
|
&:not(:focus) {
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
padding-left: $inputTextPLeftRight;
|
||||||
|
padding-right: $inputTextPLeftRight;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
border-color: rgba($colorBodyFg, 0.2);
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
@include nice-input($shdw: rgba(0, 0, 0, 0.6) 0 1px 3px);
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************** MENUS */
|
||||||
@mixin menuOuter() {
|
@mixin menuOuter() {
|
||||||
border-radius: $basicCr;
|
border-radius: $basicCr;
|
||||||
background: $colorMenuBg;
|
background: $colorMenuBg;
|
||||||
@ -171,8 +278,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.c-menu {
|
.c-menu {
|
||||||
@include menuOuter();
|
@include menuOuter();
|
||||||
@include menuInner();
|
@include menuInner();
|
||||||
|
@ -43,6 +43,15 @@ div {
|
|||||||
display: contents;
|
display: contents;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.u-space {
|
||||||
|
// Provides a separator space between elements
|
||||||
|
&--right {
|
||||||
|
+ [class*="__"] {
|
||||||
|
margin-left: $interiorMarginLg !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/******************************* BROWSER ELEMENTS */
|
/******************************* BROWSER ELEMENTS */
|
||||||
body.desktop {
|
body.desktop {
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
@ -160,6 +169,48 @@ li {
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************** HAS */
|
||||||
|
// Local Controls: Controls placed in proximity to or overlaid on components and views
|
||||||
|
body.desktop .has-local-controls {
|
||||||
|
// Provides hover ability to show local controls
|
||||||
|
&:hover [class*="local-controls--hidden"] {
|
||||||
|
transition: opacity 50ms ease-in-out;
|
||||||
|
opacity: 1;
|
||||||
|
pointer-events: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="local-controls--hidden"] {
|
||||||
|
transition: opacity 500ms ease-in-out;
|
||||||
|
opacity: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//[class*="local-controls"] {
|
||||||
|
// // An explicit outer holder for controls. Typically placed in upper right.
|
||||||
|
// //font-size: 0.7rem;
|
||||||
|
// display: flex;
|
||||||
|
// align-items: center;
|
||||||
|
// justify-content: flex-end;
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// &.h-local-controls-overlay-content {
|
||||||
|
// // Imagery controls
|
||||||
|
// $p: $interiorMargin;
|
||||||
|
// position: absolute;
|
||||||
|
// top: $p; right: $p;
|
||||||
|
// z-index: 2;
|
||||||
|
// }
|
||||||
|
|
||||||
|
//.l-btn-set,
|
||||||
|
//.s-button {
|
||||||
|
// &:not(:first-child) {
|
||||||
|
// margin-left: $interiorMargin;
|
||||||
|
// }
|
||||||
|
//}
|
||||||
|
//}
|
||||||
|
|
||||||
/************************** LEGACY */
|
/************************** LEGACY */
|
||||||
|
|
||||||
mct-container {
|
mct-container {
|
||||||
|
@ -110,13 +110,10 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
/************************** CONTROLS, BUTTONS */
|
/************************** CONTROLS, BUTTONS */
|
||||||
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.5) 0 0px 2px) {
|
@mixin input-base() {
|
||||||
appearance: none;
|
appearance: none;
|
||||||
background: $bg;
|
|
||||||
border: none;
|
border: none;
|
||||||
color: $fg;
|
|
||||||
border-radius: $controlCr;
|
border-radius: $controlCr;
|
||||||
box-shadow: inset $shdw;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
@ -129,6 +126,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@mixin nice-input($bg: $colorInputBg, $fg: $colorInputFg, $shdw: rgba(black, 0.5) 0 0px 2px) {
|
||||||
|
@include input-base();
|
||||||
|
background: $bg;
|
||||||
|
color: $fg;
|
||||||
|
box-shadow: inset $shdw;
|
||||||
|
}
|
||||||
|
|
||||||
@mixin button($bg: $colorBtnBg, $fg: $colorBtnFg, $radius: $controlCr, $shdw: none) {
|
@mixin button($bg: $colorBtnBg, $fg: $colorBtnFg, $radius: $controlCr, $shdw: none) {
|
||||||
background: $bg;
|
background: $bg;
|
||||||
color: $fg;
|
color: $fg;
|
||||||
|
@ -64,7 +64,7 @@
|
|||||||
@import "../styles/items/item";
|
@import "../styles/items/item";
|
||||||
@import "../styles/mobile/item";
|
@import "../styles/mobile/item";
|
||||||
@import "../styles/table";
|
@import "../styles/table";
|
||||||
@import "../styles/notebook/notebook";
|
//@import "../styles/notebook/notebook";
|
||||||
//
|
//
|
||||||
//!********************************* TO BE MOVED *!
|
//!********************************* TO BE MOVED *!
|
||||||
@import "../styles/autoflow";
|
@import "../styles/autoflow";
|
||||||
@ -76,3 +76,4 @@
|
|||||||
//@import "../styles/app-start";
|
//@import "../styles/app-start";
|
||||||
|
|
||||||
@import "../styles/conductor/time-conductor-snow";
|
@import "../styles/conductor/time-conductor-snow";
|
||||||
|
//@import "../styles/notebook/notebook-snow";
|
385
src/styles-new/notebook.scss
Normal file
385
src/styles-new/notebook.scss
Normal file
@ -0,0 +1,385 @@
|
|||||||
|
/*********************************************** NOTEBOOK */
|
||||||
|
@import "sass-base.scss";
|
||||||
|
|
||||||
|
|
||||||
|
.c-notebook {
|
||||||
|
//@include test(orange);
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
overflow: hidden;
|
||||||
|
position: absolute;
|
||||||
|
top: 0px;
|
||||||
|
right: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
|
||||||
|
> [class*="__"] + [class*="__"] {
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__head,
|
||||||
|
&__controls,
|
||||||
|
&__drag-area,
|
||||||
|
&__entries {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__head,
|
||||||
|
&__drag-area,
|
||||||
|
&__controls {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__head {
|
||||||
|
[class*="__"] + [class*="__"] {
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__search {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__drag-area {
|
||||||
|
background: rgba($colorKey, 0.1);
|
||||||
|
border: 1px dashed rgba($colorKey, 0.7);
|
||||||
|
border-radius: $controlCr;
|
||||||
|
color: rgba($colorBodyFg, 0.7);
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
margin-right: 7px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
[class*="__label"] {
|
||||||
|
font-style: italic;
|
||||||
|
@include ellipsize();
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: rgba($colorKey, 0.2);
|
||||||
|
color: $colorBodyFg;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.drag-active,
|
||||||
|
&.is-active {
|
||||||
|
// Not currently working
|
||||||
|
border-color: $colorKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile & {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__entries {
|
||||||
|
flex-direction: column;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
padding-right: $interiorMarginSm;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: scroll;
|
||||||
|
|
||||||
|
[class*="__entry"] + [class*="__entry"] {
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************** ENTRIES */
|
||||||
|
.c-ne {
|
||||||
|
// A Notebook entry
|
||||||
|
$p: $interiorMarginSm;
|
||||||
|
@include discreteItem();
|
||||||
|
display: flex;
|
||||||
|
//flex-wrap: wrap;
|
||||||
|
padding: $interiorMarginSm $interiorMarginSm $interiorMarginSm $interiorMargin;
|
||||||
|
|
||||||
|
&__time,
|
||||||
|
&__text,
|
||||||
|
&__local-controls {
|
||||||
|
padding-top: $p;
|
||||||
|
padding-bottom: $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__time,
|
||||||
|
&__embed__time {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__time-and-content {
|
||||||
|
display: flex;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__time {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-width: 130px;
|
||||||
|
margin-right: $interiorMarginLg;
|
||||||
|
|
||||||
|
* {
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
|
||||||
|
> [class*="__"] + [class*="__"] {
|
||||||
|
margin-top: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__text {
|
||||||
|
min-height: 24px; // Needed in Firefox when field is blank
|
||||||
|
white-space: pre-wrap;
|
||||||
|
|
||||||
|
&.is-blank-notebook-entry {
|
||||||
|
&:not(:focus):before {
|
||||||
|
content: 'Blank entry';
|
||||||
|
font-style: italic;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__embeds {
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
> [class*="__embed"] {
|
||||||
|
margin: 0 $interiorMarginSm $interiorMarginSm 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************** EMBEDS */
|
||||||
|
@mixin snapThumb() {
|
||||||
|
// LEGACY: TODO: refactor when .snap-thumb in New Entry dialog is refactored
|
||||||
|
$d: 50px;
|
||||||
|
border: 1px solid $colorInteriorBorder;
|
||||||
|
cursor: pointer;
|
||||||
|
width: $d;
|
||||||
|
height: $d;
|
||||||
|
border-radius: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
|
||||||
|
img {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.snap-thumb {
|
||||||
|
// LEGACY,
|
||||||
|
@include snapThumb();
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-ne__embed {
|
||||||
|
@include discreteItemInnerElem();
|
||||||
|
display: inline-flex;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
padding: $interiorMargin;
|
||||||
|
|
||||||
|
[class*="__"] + [class*="__"] {
|
||||||
|
margin-left: $interiorMargin;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__info {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: $colorKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__name,
|
||||||
|
&__link {
|
||||||
|
// Holds __link and __context-available
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__link {
|
||||||
|
&:before {
|
||||||
|
display: block;
|
||||||
|
font-size: 0.85em;
|
||||||
|
margin-right: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__context-available {
|
||||||
|
font-size: 0.7em;
|
||||||
|
margin-left: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__snap-thumb {
|
||||||
|
@include snapThumb();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/****************************** SNAPSHOTTING */
|
||||||
|
// LEGACY: TODO: refactor these names
|
||||||
|
.t-contents,
|
||||||
|
.snap-annotation {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.s-status-taking-snapshot,
|
||||||
|
.overlay.snapshot {
|
||||||
|
// Handle overflow-y issues with tables and html2canvas
|
||||||
|
.l-sticky-headers .l-tabular-body { overflow: auto; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************** PAINTERRO OVERRIDES */
|
||||||
|
.annotation-dialog .abs.editor {
|
||||||
|
border-radius: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#snap-annotation {
|
||||||
|
$m: $interiorMargin;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
position: absolute;
|
||||||
|
top: $m; right: 0; bottom: $m; left: 0; // LEGACY, deal with .editor border-radius clipping stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
#snap-annotation-wrapper,
|
||||||
|
#snap-annotation-bar {
|
||||||
|
position: relative;
|
||||||
|
top: auto; right: auto; bottom: auto; left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#snap-annotation-wrapper {
|
||||||
|
background: rgba($colorBodyFg, 0.1);
|
||||||
|
border: 1px solid $colorInteriorBorder;
|
||||||
|
order: 2;
|
||||||
|
flex: 10 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#snap-annotation-bar {
|
||||||
|
// Holds tool buttons, color selectors, etc.
|
||||||
|
$h: 22px;
|
||||||
|
$fs: 0.8rem;
|
||||||
|
|
||||||
|
order: 1;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
height: auto;
|
||||||
|
background-color: transparent !important;
|
||||||
|
margin-bottom: $interiorMargin;
|
||||||
|
|
||||||
|
> div > span {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
font-size: $fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
> div,
|
||||||
|
> div > span,
|
||||||
|
.ptro-icon-btn,
|
||||||
|
.ptro-named-btn,
|
||||||
|
.ptro-color-btn,
|
||||||
|
.ptro-bordered-btn,
|
||||||
|
.ptro-tool-ctl-name,
|
||||||
|
.ptro-color-btn,
|
||||||
|
.tool-controls,
|
||||||
|
.ptro-input {
|
||||||
|
// Lot of resets for crappy CSS in Painterro
|
||||||
|
&:first-child {
|
||||||
|
margin-left: 0 !important;
|
||||||
|
}
|
||||||
|
display: inline-block;
|
||||||
|
font-family: inherit;
|
||||||
|
font-size: $fs !important;
|
||||||
|
height: $h !important;
|
||||||
|
margin: 0 0 0 5px;
|
||||||
|
position: relative;
|
||||||
|
width: auto !important;
|
||||||
|
line-height: $h !important;
|
||||||
|
top: auto;
|
||||||
|
right: auto;
|
||||||
|
bottom: auto;
|
||||||
|
left: auto;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ptro-tool-ctl-name {
|
||||||
|
border-radius: 0;
|
||||||
|
background: none;
|
||||||
|
top: auto;
|
||||||
|
font-family: inherit;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ptro-color-btn {
|
||||||
|
width: $h !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ptro-color-control,
|
||||||
|
.ptro-icon-btn,
|
||||||
|
.ptro-named-btn {
|
||||||
|
// Buttons in toolbar. Why the f* they're named like this is a mystery
|
||||||
|
background-color: $colorBtnBg;
|
||||||
|
color: $colorBtnFg;
|
||||||
|
padding: 0 $interiorMargin;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
background: $colorBtnBgHov;
|
||||||
|
color: $colorBtnFgHov;
|
||||||
|
}
|
||||||
|
|
||||||
|
i {
|
||||||
|
display: contents;
|
||||||
|
font-size: $fs * 1.2;
|
||||||
|
line-height: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.ptro-color-active-control {
|
||||||
|
background: $colorBtnMajorBg !important;
|
||||||
|
color: $colorBtnMajorFg !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ptro-info,
|
||||||
|
.ptro-btn-color-checkers-bar,
|
||||||
|
*[title="Font name"],
|
||||||
|
*[title="Stroke color"],
|
||||||
|
*[title="Stroke width"],
|
||||||
|
*[data-id="fontName"],
|
||||||
|
*[data-id="fontStrokeSize"],
|
||||||
|
*[data-id="stroke"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/****************************** MOBILE */
|
||||||
|
body.mobile {
|
||||||
|
.c-notebook__drag-area { display: none; }
|
||||||
|
.c-notebook__entry {
|
||||||
|
[class*="local-controls"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.phone.portrait {
|
||||||
|
.c-notebook__head,
|
||||||
|
.c-notebook__entry {
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
|
> [class*="__"] + [class*="__"] {
|
||||||
|
margin-left: 0;
|
||||||
|
margin-top: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.c-notebook__entry {
|
||||||
|
[class*="text"] {
|
||||||
|
min-height: 0;
|
||||||
|
padding: 0;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -2,29 +2,25 @@
|
|||||||
<div class="c-create-button--w">
|
<div class="c-create-button--w">
|
||||||
<div class="c-create-button c-menu-button c-button--major icon-plus"
|
<div class="c-create-button c-menu-button c-button--major icon-plus"
|
||||||
@click="toggleCreateMenu">
|
@click="toggleCreateMenu">
|
||||||
Create
|
<span class="c-button__label">Create</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-create-menu c-super-menu"
|
<div class="c-create-menu c-super-menu"
|
||||||
v-if="showCreateMenu">
|
v-if="showCreateMenu">
|
||||||
<div class="c-super-menu__menu">
|
<div class="c-super-menu__menu">
|
||||||
<ul>
|
<ul>
|
||||||
<li v-for="item in createMenuItems"
|
<li v-for="(item, index) in items"
|
||||||
|
:key="index"
|
||||||
:class="item.class"
|
:class="item.class"
|
||||||
:title="item.title"
|
:title="item.title"
|
||||||
@mouseover="showItemDescription">
|
@mouseover="showItemDescription(item)">
|
||||||
{{ item.name }}
|
{{ item.name }}
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div class="c-super-menu__item-description">
|
<div class="c-super-menu__item-description">
|
||||||
<div class="l-item-description__icon bg-icon-plot-stacked"></div>
|
<div :class="['l-item-description__icon', 'bg-' + selectedMenuItem.class]"></div>
|
||||||
<div class="l-item-description__name">Name</div>
|
<div class="l-item-description__name">{{selectedMenuItem.name}}</div>
|
||||||
<div class="l-item-description__description">
|
<div class="l-item-description__description">{{selectedMenuItem.title}}</div>
|
||||||
A timer that counts up or down to a datetime.
|
|
||||||
Timers can be started, stopped and reset whenever needed,
|
|
||||||
and support a variety of display formats.
|
|
||||||
Each Timer displays the same value to all users.
|
|
||||||
Timers can be added to Display Layouts.</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,6 +39,10 @@
|
|||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.c-create-button .c-button__label {
|
||||||
|
text-transform: $createBtnTextTransform;
|
||||||
|
}
|
||||||
|
|
||||||
.c-create-menu {
|
.c-create-menu {
|
||||||
max-height: 80vh;
|
max-height: 80vh;
|
||||||
max-width: 500px;
|
max-width: 500px;
|
||||||
@ -61,6 +61,7 @@
|
|||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
props: {
|
props: {
|
||||||
showCreateMenu: {
|
showCreateMenu: {
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
@ -71,27 +72,30 @@
|
|||||||
toggleCreateMenu: function () {
|
toggleCreateMenu: function () {
|
||||||
this.showCreateMenu = !this.showCreateMenu;
|
this.showCreateMenu = !this.showCreateMenu;
|
||||||
},
|
},
|
||||||
|
showItemDescription: function (menuItem) {
|
||||||
|
this.selectedMenuItem = menuItem;
|
||||||
|
}
|
||||||
},
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
|
let items = [];
|
||||||
|
|
||||||
|
this.openmct.types.listKeys().forEach(key => {
|
||||||
|
let menuItem = openmct.types.get(key).definition;
|
||||||
|
|
||||||
|
if (menuItem.creatable) {
|
||||||
|
let menuItemTemplate = {
|
||||||
|
name: menuItem.name,
|
||||||
|
class: menuItem.cssClass,
|
||||||
|
title: menuItem.description
|
||||||
|
};
|
||||||
|
|
||||||
|
items.push(menuItemTemplate);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
return {
|
return {
|
||||||
createMenuItems: [
|
items: items,
|
||||||
{ name: 'Folder', class: 'icon-folder', title: 'Details will go here' },
|
selectedMenuItem: {}
|
||||||
{ name: 'Display Layout', class: 'icon-layout', title: 'Details will go here' },
|
|
||||||
{ name: 'Fixed Position Display', class: 'icon-box-with-dashed-lines', title: 'Details will go here' },
|
|
||||||
{ name: 'Overlay Plot', class: 'icon-plot-overlay', title: 'Details will go here' },
|
|
||||||
{ name: 'Stacked Plot', class: 'icon-plot-stacked', title: 'Details will go here' },
|
|
||||||
{ name: 'Telemetry Table', class: 'icon-tabular-realtime', title: 'Details will go here' },
|
|
||||||
{ name: 'Clock', class: 'icon-clock', title: 'Details will go here' },
|
|
||||||
{ name: 'Timer', class: 'icon-timer', title: 'Details will go here' },
|
|
||||||
{ name: 'Web Page', class: 'icon-page', title: 'Details will go here' },
|
|
||||||
{ name: 'Event Message Generator', class: 'icon-folder-new', title: 'Details will go here' },
|
|
||||||
{ name: 'Hyperlink', class: 'icon-chain-links', title: 'Details will go here' },
|
|
||||||
{ name: 'Notebook', class: 'icon-notebook', title: 'Details will go here' },
|
|
||||||
{ name: 'State Generator', class: 'icon-telemetry', title: 'Details will go here' },
|
|
||||||
{ name: 'Sine Wave Generator', class: 'icon-telemetry', title: 'Details will go here' },
|
|
||||||
{ name: 'Example Imagery', class: 'icon-image', title: 'Details will go here' },
|
|
||||||
{ name: 'Summary Widget', class: 'icon-summary-widget', title: 'Details will go here' }
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@
|
|||||||
|
|
||||||
&__collapse-button {
|
&__collapse-button {
|
||||||
$m: 2px;
|
$m: 2px;
|
||||||
$h: 12px; //nth($splitterBtnD, 1) - ($m * 2);
|
$h: 12px;
|
||||||
color: $splitterBtnColorFg;
|
color: $splitterBtnColorFg;
|
||||||
flex: 0 0 nth($splitterBtnD, 1);
|
flex: 0 0 nth($splitterBtnD, 1);
|
||||||
font-size: $h * .9;
|
font-size: $h * .9;
|
||||||
@ -192,6 +192,7 @@
|
|||||||
// Name of the pane
|
// Name of the pane
|
||||||
@include ellipsize();
|
@include ellipsize();
|
||||||
display: block;
|
display: block;
|
||||||
|
padding-right: nth($splitterBtnD, 2) + $interiorMargin; // Force label to ellipsis
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
transform-origin: top left;
|
transform-origin: top left;
|
||||||
flex: 1 0 90%;
|
flex: 1 0 90%;
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="c-search"
|
<div class="c-search"
|
||||||
:class="{ 'is-active': active === true }">
|
:class="{ 'is-active': active === true }">
|
||||||
<input class="c-search__input" type="search"
|
<input class="c-search__input"
|
||||||
v-bind:value="searchInput"
|
tabindex="10000"
|
||||||
@input="handleInput($event)"/>
|
type="search"
|
||||||
|
v-bind="$attrs"
|
||||||
|
v-bind:value="value"
|
||||||
|
v-on="inputListeners"/>
|
||||||
<a class="c-search__clear-input icon-x-in-circle"
|
<a class="c-search__clear-input icon-x-in-circle"
|
||||||
v-on:click="clearInput"></a>
|
v-on:click="clearInput"></a>
|
||||||
</div>
|
</div>
|
||||||
@ -47,7 +50,7 @@
|
|||||||
&__input {
|
&__input {
|
||||||
background: none !important;
|
background: none !important;
|
||||||
box-shadow: none !important; // !important needed to override default for [input]
|
box-shadow: none !important; // !important needed to override default for [input]
|
||||||
flex: 0 1 100%;
|
flex: 1 1 auto;
|
||||||
padding-left: 2px !important;
|
padding-left: 2px !important;
|
||||||
padding-right: 2px !important;
|
padding-right: 2px !important;
|
||||||
min-width: 10px; // Must be set to allow input to collapse below browser min
|
min-width: 10px; // Must be set to allow input to collapse below browser min
|
||||||
@ -71,26 +74,36 @@
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
/* Emits input and clear events */
|
||||||
export default {
|
export default {
|
||||||
|
inheritAttrs: false,
|
||||||
props: {
|
props: {
|
||||||
value: String
|
value: String
|
||||||
},
|
},
|
||||||
|
computed: {
|
||||||
|
inputListeners: function () {
|
||||||
|
let vm = this;
|
||||||
|
return Object.assign({},
|
||||||
|
this.$listeners,
|
||||||
|
{
|
||||||
|
input: function (event) {
|
||||||
|
vm.$emit('input', event.target.value);
|
||||||
|
vm.active = (event.target.value.length > 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
},
|
||||||
data: function() {
|
data: function() {
|
||||||
return {
|
return {
|
||||||
searchInput: '',
|
|
||||||
active: false
|
active: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleInput(e) {
|
|
||||||
// Grab input as the user types it
|
|
||||||
// and set 'active' based on input length > 0
|
|
||||||
this.searchInput = e.target.value;
|
|
||||||
this.active = (this.searchInput.length > 0);
|
|
||||||
},
|
|
||||||
clearInput() {
|
clearInput() {
|
||||||
// Clear the user's input and set 'active' to false
|
// Clear the user's input and set 'active' to false
|
||||||
this.searchInput = '';
|
this.value = '';
|
||||||
|
this.$emit('clear','');
|
||||||
this.active = false;
|
this.active = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="c-splitter" :class="{
|
|
||||||
'c-splitter-vertical' : align === 'vertical',
|
|
||||||
'c-splitter-horizontal' : align === 'horizontal',
|
|
||||||
'c-splitter-collapse-left' : collapse === 'to-left',
|
|
||||||
'c-splitter-collapse-right' : collapse === 'to-right',
|
|
||||||
}">
|
|
||||||
<a class="c-splitter__btn"></a>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "~styles/constants";
|
|
||||||
@import "~styles/constants-snow";
|
|
||||||
@import "~styles/mixins";
|
|
||||||
@import "~styles/glyphs";
|
|
||||||
|
|
||||||
$c: #06f;
|
|
||||||
$size: $splitterHandleD;
|
|
||||||
$margin: 0px;
|
|
||||||
$hitMargin: 4px;
|
|
||||||
|
|
||||||
|
|
||||||
.c-splitter {
|
|
||||||
background: $colorSplitterBg;
|
|
||||||
transition: $transOut;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
// Bigger hit area
|
|
||||||
//@include test();
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active, &:hover {
|
|
||||||
transition: $transIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: $colorSplitterActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $colorSplitterHover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&-vertical {
|
|
||||||
cursor: col-resize;
|
|
||||||
width: $size;
|
|
||||||
margin: 0 $margin;
|
|
||||||
&:before {
|
|
||||||
top: 0;
|
|
||||||
right: $hitMargin * -1;
|
|
||||||
bottom: 0;
|
|
||||||
left: $hitMargin * -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&-horizontal {
|
|
||||||
cursor: row-resize;
|
|
||||||
height: $size;
|
|
||||||
margin: $margin 0;
|
|
||||||
&:before {
|
|
||||||
top: $hitMargin * -1;
|
|
||||||
right: 0;
|
|
||||||
bottom: $hitMargin * -1;
|
|
||||||
left: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.c-splitter__btn {
|
|
||||||
// Collapse button
|
|
||||||
background: $colorSplitterBg;
|
|
||||||
display: none; // Only display if splitter is collapsible, see below
|
|
||||||
width: $splitterD;
|
|
||||||
height: 40px;
|
|
||||||
transition: $transOut;
|
|
||||||
|
|
||||||
&:active, &:hover {
|
|
||||||
transition: $transIn;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: $colorSplitterHover;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: $colorSplitterActive;
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="collapse"] & {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
position: absolute;
|
|
||||||
z-index: 3;
|
|
||||||
&:before {
|
|
||||||
color: $colorSplitterFg;
|
|
||||||
display: block;
|
|
||||||
font-size: 0.8em;
|
|
||||||
font-family: symbolsfont;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="collapse-left"] & {
|
|
||||||
border-bottom-left-radius: $controlCr;
|
|
||||||
right: 0;
|
|
||||||
&:before {
|
|
||||||
content: $glyph-icon-arrow-left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[class*="collapse-right"] & {
|
|
||||||
border-bottom-right-radius: $controlCr;
|
|
||||||
left: 0;
|
|
||||||
&:before {
|
|
||||||
content: $glyph-icon-arrow-right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
export default {
|
|
||||||
props: {
|
|
||||||
align: String,
|
|
||||||
collapse: String
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
@ -1,43 +1,12 @@
|
|||||||
<template>
|
<template>
|
||||||
<span class="c-view-control"
|
<span class="c-disclosure-triangle"
|
||||||
:class="{
|
:class="{
|
||||||
'c-view-control--expanded' : expanded,
|
'c-disclosure-triangle--expanded' : expanded,
|
||||||
'is-enabled' : enabled
|
'is-enabled' : enabled
|
||||||
}"
|
}"
|
||||||
@click="toggle"></span>
|
@click="toggle"></span>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
@import "~styles/sass-base";;
|
|
||||||
|
|
||||||
.c-view-control {
|
|
||||||
$d: 12px;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex: 0 0 auto;
|
|
||||||
width: $d;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&.is-enabled:before {
|
|
||||||
$s: .65;
|
|
||||||
content: $glyph-icon-arrow-right-equilateral;
|
|
||||||
display: block;
|
|
||||||
font-family: symbolsfont;
|
|
||||||
font-size: 1rem * $s;
|
|
||||||
position: absolute;
|
|
||||||
transform-origin: floor(($d / 2) * $s); // This is slightly better than 'center'
|
|
||||||
transition: transform 100ms ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
&--expanded {
|
|
||||||
&:before {
|
|
||||||
transform: rotate(90deg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
|
177
src/ui/components/layout/BrowseBar.vue
Normal file
177
src/ui/components/layout/BrowseBar.vue
Normal file
@ -0,0 +1,177 @@
|
|||||||
|
<template>
|
||||||
|
<div class="l-browse-bar">
|
||||||
|
<div class="l-browse-bar__start">
|
||||||
|
<a class="l-browse-bar__nav-to-parent-button c-icon-button icon-pointer-left"></a>
|
||||||
|
<div class="l-browse-bar__object-name--w"
|
||||||
|
:class="type.cssClass">
|
||||||
|
<span
|
||||||
|
class="l-browse-bar__object-name c-input-inline"
|
||||||
|
v-on:blur="updateName"
|
||||||
|
contenteditable>
|
||||||
|
{{ domainObject.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="l-browse-bar__context-actions c-disclosure-button"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="l-browse-bar__end">
|
||||||
|
<div class="l-browse-bar__view-switcher c-menu-button--w c-menu-button--menus-left"
|
||||||
|
v-if="views.length > 1">
|
||||||
|
<div class="c-menu-button"
|
||||||
|
:class="currentView.cssClass"
|
||||||
|
title="Switch view type"
|
||||||
|
@click="toggleViewMenu">
|
||||||
|
<span class="c-button__label">
|
||||||
|
{{ currentView.name }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="c-menu" v-show="showViewMenu">
|
||||||
|
<ul>
|
||||||
|
<li v-for="(view, index) in views"
|
||||||
|
@click="setView(view)"
|
||||||
|
:key="index"
|
||||||
|
:class="view.cssClass"
|
||||||
|
:title="view.name">
|
||||||
|
{{ view.name }}
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<!-- Action buttons -->
|
||||||
|
<div class="l-browse-bar__actions">
|
||||||
|
<div class="l-browse-bar__action c-button icon-eye-open" title="Preview"></div>
|
||||||
|
<div class="l-browse-bar__action c-button icon-notebook" title="New Notebook entry"></div>
|
||||||
|
<div class="l-browse-bar__action c-button c-button--major icon-pencil" title="Edit"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
inject: ['openmct'],
|
||||||
|
methods: {
|
||||||
|
toggleViewMenu: function (event) {
|
||||||
|
event.stopPropagation();
|
||||||
|
this.showViewMenu = !this.showViewMenu;
|
||||||
|
},
|
||||||
|
updateName: function (event) {
|
||||||
|
// TODO: handle isssues with contenteditable text escaping.
|
||||||
|
if (event.target.innerText !== this.domainObject.name) {
|
||||||
|
this.openmct.objects.mutate(this.domainObject, 'name', event.target.innerText);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
setView: function (view) {
|
||||||
|
this.viewKey = view.key;
|
||||||
|
this.openmct.router.updateParams({
|
||||||
|
view: this.viewKey
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
data: function () {
|
||||||
|
return {
|
||||||
|
showViewMenu: false,
|
||||||
|
domainObject: {},
|
||||||
|
viewKey: undefined
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
currentView() {
|
||||||
|
return this.views.filter(v => v.key === this.viewKey)[0] || {};
|
||||||
|
},
|
||||||
|
views() {
|
||||||
|
return this
|
||||||
|
.openmct
|
||||||
|
.objectViews
|
||||||
|
.get(this.domainObject)
|
||||||
|
.map((p) => {
|
||||||
|
return {
|
||||||
|
key: p.key,
|
||||||
|
cssClass: p.cssClass,
|
||||||
|
name: p.name
|
||||||
|
};
|
||||||
|
});
|
||||||
|
},
|
||||||
|
type() {
|
||||||
|
let objectType = this.openmct.types.get(this.domainObject.type);
|
||||||
|
if (!objectType) {
|
||||||
|
return {}
|
||||||
|
}
|
||||||
|
return objectType.definition;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function () {
|
||||||
|
document.addEventListener('click', () => {
|
||||||
|
if (this.showViewMenu) {
|
||||||
|
this.showViewMenu = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import "~styles/sass-base";
|
||||||
|
|
||||||
|
/******************************* START */
|
||||||
|
|
||||||
|
.l-browse-bar {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
|
||||||
|
[class*="__"] {
|
||||||
|
// Removes extraneous horizontal white space
|
||||||
|
display: inline-flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__start {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 1 1 auto;
|
||||||
|
font-size: 1.4em;
|
||||||
|
margin-right: $interiorMargin;
|
||||||
|
min-width: 0; // Forces interior to compress when pushed on
|
||||||
|
}
|
||||||
|
|
||||||
|
&__end {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
[class*="__"] + [class*="__"] {
|
||||||
|
margin-left: $interiorMarginSm;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__nav-to-parent-button,
|
||||||
|
&__disclosure-button {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__nav-to-parent-button {
|
||||||
|
// This is an icon-button
|
||||||
|
$p: $interiorMarginLg;
|
||||||
|
margin-right: $interiorMargin;
|
||||||
|
padding-left: $p;
|
||||||
|
padding-right: $p;
|
||||||
|
}
|
||||||
|
|
||||||
|
&__object-name--w {
|
||||||
|
align-items: center;
|
||||||
|
display: flex;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-width: 0;
|
||||||
|
|
||||||
|
&:before {
|
||||||
|
// Icon
|
||||||
|
opacity: 0.5;
|
||||||
|
margin-right: $interiorMargin;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&__object-name {
|
||||||
|
flex: 0 1 auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
@ -1,159 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div></div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style lang="scss">
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
|
|
||||||
// Find an object in an array of objects.
|
|
||||||
function findObject(domainObjects, id) {
|
|
||||||
var i;
|
|
||||||
for (i = 0; i < domainObjects.length; i += 1) {
|
|
||||||
if (domainObjects[i].getId() === id) {
|
|
||||||
return domainObjects[i];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// recursively locate and return an object inside of a container
|
|
||||||
// via a path. If at any point in the recursion it fails to find
|
|
||||||
// the next object, it will return the parent.
|
|
||||||
function findViaComposition(containerObject, path) {
|
|
||||||
var nextId = path.shift();
|
|
||||||
if (!nextId) {
|
|
||||||
return containerObject;
|
|
||||||
}
|
|
||||||
return containerObject.useCapability('composition')
|
|
||||||
.then(function (composees) {
|
|
||||||
var nextObject = findObject(composees, nextId);
|
|
||||||
if (!nextObject) {
|
|
||||||
return containerObject;
|
|
||||||
}
|
|
||||||
if (!nextObject.hasCapability('composition')) {
|
|
||||||
return nextObject;
|
|
||||||
}
|
|
||||||
return findViaComposition(nextObject, path);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getLastChildIfRoot(object) {
|
|
||||||
if (object.getId() !== 'ROOT') {
|
|
||||||
return object;
|
|
||||||
}
|
|
||||||
return object.useCapability('composition')
|
|
||||||
.then(function (composees) {
|
|
||||||
return composees[composees.length - 1];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function pathForObject(domainObject) {
|
|
||||||
var context = domainObject.getCapability('context'),
|
|
||||||
objectPath = context ? context.getPath() : [],
|
|
||||||
ids = objectPath.map(function (domainObj) {
|
|
||||||
return domainObj.getId();
|
|
||||||
});
|
|
||||||
return "/browse/" + ids.slice(1).join("/");
|
|
||||||
}
|
|
||||||
|
|
||||||
export default {
|
|
||||||
inject: ["openmct"],
|
|
||||||
mounted() {
|
|
||||||
let openmct = this.openmct;
|
|
||||||
let $injector = openmct.$injector;
|
|
||||||
let angular = openmct.$angular;
|
|
||||||
|
|
||||||
this.objectService = $injector.get('objectService');
|
|
||||||
this.templateLinker = $injector.get('templateLinker');
|
|
||||||
this.navigationService = $injector.get('navigationService');
|
|
||||||
this.$timeout = $injector.get('$timeout');
|
|
||||||
|
|
||||||
this.templateMap = {};
|
|
||||||
$injector.get('templates[]').forEach((t) => {
|
|
||||||
this.templateMap[t.key] = this.templateMap[t.key] || t;
|
|
||||||
});
|
|
||||||
|
|
||||||
this.$rootScope = $injector.get('$rootScope');
|
|
||||||
this.$scope = this.$rootScope.$new();
|
|
||||||
this.$scope.representation = {};
|
|
||||||
|
|
||||||
openmct.router.route(/^\/browse\/(.*)$/, (path, results) => {
|
|
||||||
let navigatePath = results[1];
|
|
||||||
if (!navigatePath) {
|
|
||||||
navigatePath = 'mine';
|
|
||||||
}
|
|
||||||
this.navigateToPath(navigatePath);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.navigationService.addListener(o => this.navigateToObject(o));
|
|
||||||
},
|
|
||||||
destroyed() {
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
navigateToPath(path) {
|
|
||||||
if (!Array.isArray(path)) {
|
|
||||||
path = path.split('/');
|
|
||||||
}
|
|
||||||
return this.getObject('ROOT')
|
|
||||||
.then(root => {
|
|
||||||
return findViaComposition(root, path);
|
|
||||||
})
|
|
||||||
.then(getLastChildIfRoot)
|
|
||||||
.then(object => {
|
|
||||||
this.setMainViewObject(object);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setMainViewObject(object) {
|
|
||||||
this.$scope.domainObject = object;
|
|
||||||
this.$scope.navigatedObject = object;
|
|
||||||
this.templateLinker.link(
|
|
||||||
this.$scope,
|
|
||||||
this.openmct.$angular.element(this.$el),
|
|
||||||
this.templateMap["browseObject"]
|
|
||||||
);
|
|
||||||
document.title = object.getModel().name;
|
|
||||||
this.scheduleDigest();
|
|
||||||
},
|
|
||||||
|
|
||||||
idsForObject(domainObject) {
|
|
||||||
return this.urlService
|
|
||||||
.urlForLocation("", domainObject)
|
|
||||||
.replace('/', '');
|
|
||||||
},
|
|
||||||
|
|
||||||
navigateToObject(object) {
|
|
||||||
let path = pathForObject(object);
|
|
||||||
let views = object.useCapability('view');
|
|
||||||
let params = this.openmct.router.getParams();
|
|
||||||
let currentViewIsValid = views.some(v => v.key === params['view']);
|
|
||||||
if (!currentViewIsValid) {
|
|
||||||
this.scope.representation = {
|
|
||||||
selected: views[0]
|
|
||||||
}
|
|
||||||
this.openmct.router.update(path, {
|
|
||||||
view: views[0].key
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
this.openmct.router.setPath(path);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
scheduleDigest() {
|
|
||||||
this.$timeout(function () {
|
|
||||||
// digest done!
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
getObject(id) {
|
|
||||||
return this.objectService.getObjects([id])
|
|
||||||
.then(function (results) {
|
|
||||||
return results[id];
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
|
|
@ -3,11 +3,9 @@
|
|||||||
<div class="l-shell__head">
|
<div class="l-shell__head">
|
||||||
<CreateButton class="l-shell__create-button"></CreateButton>
|
<CreateButton class="l-shell__create-button"></CreateButton>
|
||||||
<div class="l-shell__controls">
|
<div class="l-shell__controls">
|
||||||
<div class="l-controls__elem c-button-set">
|
|
||||||
<a class="c-icon-button icon-new-window" title="Open in a new browser tab"></a>
|
<a class="c-icon-button icon-new-window" title="Open in a new browser tab"></a>
|
||||||
<a class="c-icon-button icon-fullscreen-collapse" title="Enable full screen mode"></a>
|
<a class="c-icon-button icon-fullscreen-collapse" title="Enable full screen mode"></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div class="l-shell__app-logo">[ App Logo ]</div>
|
<div class="l-shell__app-logo">[ App Logo ]</div>
|
||||||
</div>
|
</div>
|
||||||
<multipane class="l-shell__main"
|
<multipane class="l-shell__main"
|
||||||
@ -24,8 +22,12 @@
|
|||||||
</div>
|
</div>
|
||||||
</pane>
|
</pane>
|
||||||
<pane class="l-shell__pane-main">
|
<pane class="l-shell__pane-main">
|
||||||
<browse-object class="l-shell__main-container">
|
<browse-bar class="l-shell__main-view-browse-bar"
|
||||||
</browse-object>
|
ref="browseBar">
|
||||||
|
</browse-bar>
|
||||||
|
<object-view class="l-shell__main-container"
|
||||||
|
ref="browseObject">
|
||||||
|
</object-view>
|
||||||
<mct-template template-key="conductor"
|
<mct-template template-key="conductor"
|
||||||
class="l-shell__time-conductor">
|
class="l-shell__time-conductor">
|
||||||
</mct-template>
|
</mct-template>
|
||||||
@ -82,7 +84,8 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__pane-main {
|
&__pane-main,
|
||||||
|
&__pane-tree {
|
||||||
> .l-pane__contents {
|
> .l-pane__contents {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column nowrap;
|
flex-flow: column nowrap;
|
||||||
@ -117,11 +120,15 @@
|
|||||||
|
|
||||||
&__head,
|
&__head,
|
||||||
&__status {
|
&__status {
|
||||||
flex: 0 1 auto;
|
flex: 0 0 auto;
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************* HEAD */
|
/******************************* HEAD */
|
||||||
|
&__main-view-browse-bar {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
&__head {
|
&__head {
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
@ -148,8 +155,9 @@
|
|||||||
/********** MAIN AREA */
|
/********** MAIN AREA */
|
||||||
&__main-container {
|
&__main-container {
|
||||||
// Wrapper for main views
|
// Wrapper for main views
|
||||||
flex: 1 1 100%;
|
flex: 1 1 auto;
|
||||||
font-size: 16px; // TEMP FOR LEGACY STYLING
|
overflow: auto;
|
||||||
|
//font-size: 16px; // TEMP FOR LEGACY STYLING
|
||||||
}
|
}
|
||||||
|
|
||||||
&__tree {
|
&__tree {
|
||||||
@ -186,26 +194,28 @@
|
|||||||
import Inspector from '../inspector/Inspector.vue';
|
import Inspector from '../inspector/Inspector.vue';
|
||||||
import MctStatus from './MctStatus.vue';
|
import MctStatus from './MctStatus.vue';
|
||||||
import MctTree from './mct-tree.vue';
|
import MctTree from './mct-tree.vue';
|
||||||
import BrowseObject from './BrowseObject.vue';
|
import ObjectView from './ObjectView.vue';
|
||||||
import MctTemplate from '../legacy/mct-template.vue';
|
import MctTemplate from '../legacy/mct-template.vue';
|
||||||
import ContextMenu from '../controls/ContextMenu.vue';
|
import ContextMenu from '../controls/ContextMenu.vue';
|
||||||
import CreateButton from '../controls/CreateButton.vue';
|
import CreateButton from '../controls/CreateButton.vue';
|
||||||
import search from '../controls/search.vue';
|
import search from '../controls/search.vue';
|
||||||
import multipane from '../controls/multipane.vue';
|
import multipane from '../controls/multipane.vue';
|
||||||
import pane from '../controls/pane.vue';
|
import pane from '../controls/pane.vue';
|
||||||
|
import BrowseBar from './BrowseBar.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
Inspector,
|
Inspector,
|
||||||
MctStatus,
|
MctStatus,
|
||||||
MctTree,
|
MctTree,
|
||||||
BrowseObject,
|
ObjectView,
|
||||||
'mct-template': MctTemplate,
|
'mct-template': MctTemplate,
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
CreateButton,
|
CreateButton,
|
||||||
search,
|
search,
|
||||||
multipane,
|
multipane,
|
||||||
pane
|
pane,
|
||||||
|
BrowseBar
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
74
src/ui/components/layout/ObjectView.vue
Normal file
74
src/ui/components/layout/ObjectView.vue
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
<template>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
.l-object-view {
|
||||||
|
display: contents;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import _ from "lodash"
|
||||||
|
|
||||||
|
export default {
|
||||||
|
inject: ["openmct"],
|
||||||
|
props: {
|
||||||
|
view: String,
|
||||||
|
object: Object
|
||||||
|
},
|
||||||
|
destroyed() {
|
||||||
|
this.clear();
|
||||||
|
},
|
||||||
|
watch: {
|
||||||
|
view(newView, oldView) {
|
||||||
|
this.viewKey = newView;
|
||||||
|
this.debounceUpdateView();
|
||||||
|
},
|
||||||
|
object(newObject, oldObject) {
|
||||||
|
this.currentObject = newObject;
|
||||||
|
this.debounceUpdateView();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.debounceUpdateView = _.debounce(this.updateView, 10);
|
||||||
|
},
|
||||||
|
mounted() {
|
||||||
|
this.updateView();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clear() {
|
||||||
|
if (this.currentView) {
|
||||||
|
this.currentView.destroy();
|
||||||
|
this.$el.innerHTML = '';
|
||||||
|
}
|
||||||
|
delete this.viewContainer;
|
||||||
|
delete this.currentView;
|
||||||
|
},
|
||||||
|
updateView() {
|
||||||
|
this.clear();
|
||||||
|
if (!this.currentObject) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.viewContainer = document.createElement('div');
|
||||||
|
this.viewContainer.classList.add('l-object-view');
|
||||||
|
this.$el.append(this.viewContainer);
|
||||||
|
let provider = this.openmct.objectViews.getByProviderKey(this.viewKey);
|
||||||
|
if (!provider) {
|
||||||
|
provider = this.openmct.objectViews.get(this.currentObject)[0];
|
||||||
|
if (!provider) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.currentView = provider.view(this.currentObject);
|
||||||
|
this.currentView.show(this.viewContainer);
|
||||||
|
},
|
||||||
|
show(object, viewKey) {
|
||||||
|
this.currentObject = object;
|
||||||
|
this.viewKey = viewKey;
|
||||||
|
this.updateView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
@ -69,7 +69,8 @@
|
|||||||
|
|
||||||
&:before {
|
&:before {
|
||||||
// Type icon
|
// Type icon
|
||||||
display: inline-block;
|
display: block;
|
||||||
|
flex: 0 0 auto;
|
||||||
font-size: 1.3em;
|
font-size: 1.3em;
|
||||||
margin-right: $interiorMarginSm;
|
margin-right: $interiorMarginSm;
|
||||||
}
|
}
|
||||||
|
@ -22,8 +22,6 @@ export default {
|
|||||||
|
|
||||||
let $rootScope = $injector.get('$rootScope');
|
let $rootScope = $injector.get('$rootScope');
|
||||||
this.$scope = $rootScope.$new();
|
this.$scope = $rootScope.$new();
|
||||||
console.log('mounting', this.templateKey);
|
|
||||||
console.log('template:', templateMap[this.templateKey]);
|
|
||||||
|
|
||||||
templateLinker.link(
|
templateLinker.link(
|
||||||
this.$scope,
|
this.$scope,
|
||||||
|
@ -101,7 +101,7 @@ class ApplicationRouter extends EventEmitter {
|
|||||||
doPathChange(newPath, oldPath, newLocation) {
|
doPathChange(newPath, oldPath, newLocation) {
|
||||||
let route = this.routes.filter(r => r.matcher.test(newPath))[0];
|
let route = this.routes.filter(r => r.matcher.test(newPath))[0];
|
||||||
if (route) {
|
if (route) {
|
||||||
route.callback(newPath, route.matcher.exec(newPath));
|
route.callback(newPath, route.matcher.exec(newPath), this.currentLocation.params);
|
||||||
}
|
}
|
||||||
this.emit('change:path', newPath, oldPath);
|
this.emit('change:path', newPath, oldPath);
|
||||||
}
|
}
|
||||||
|
80
src/ui/router/Browse.js
Normal file
80
src/ui/router/Browse.js
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
define([
|
||||||
|
|
||||||
|
], function (
|
||||||
|
|
||||||
|
) {
|
||||||
|
|
||||||
|
return function install(openmct) {
|
||||||
|
let navigateCall = 0;
|
||||||
|
let browseObject;
|
||||||
|
|
||||||
|
|
||||||
|
function viewObject(object, viewProvider) {
|
||||||
|
openmct.layout.$refs.browseObject.show(object, viewProvider.key);
|
||||||
|
openmct.layout.$refs.browseBar.domainObject = object;
|
||||||
|
openmct.layout.$refs.browseBar.viewKey = viewProvider.key;
|
||||||
|
};
|
||||||
|
|
||||||
|
function navigateToPath(path, currentViewKey) {
|
||||||
|
navigateCall++;
|
||||||
|
let currentNavigation = navigateCall;
|
||||||
|
|
||||||
|
if (!Array.isArray(path)) {
|
||||||
|
path = path.split('/');
|
||||||
|
}
|
||||||
|
let keyString = path[path.length - 1];
|
||||||
|
// TODO: retain complete path in navigation.
|
||||||
|
return openmct.objects.get(keyString)
|
||||||
|
.then((object) => {
|
||||||
|
if (currentNavigation !== navigateCall) {
|
||||||
|
return; // Prevent race.
|
||||||
|
}
|
||||||
|
openmct.layout.$refs.browseBar.domainObject = object;
|
||||||
|
browseObject = object;
|
||||||
|
if (!object) {
|
||||||
|
openmct.layout.$refs.browseObject.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let currentProvider = openmct
|
||||||
|
.objectViews
|
||||||
|
.getByProviderKey(currentViewKey)
|
||||||
|
|
||||||
|
if (currentProvider && currentProvider.canView(object)) {
|
||||||
|
viewObject(object, currentProvider);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let defaultProvider = openmct.objectViews.get(object)[0];
|
||||||
|
if (defaultProvider) {
|
||||||
|
openmct.router.updateParams({
|
||||||
|
view: defaultProvider.key
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
openmct.router.updateParams({
|
||||||
|
view: undefined
|
||||||
|
});
|
||||||
|
openmct.layout.$refs.browseObject.clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
openmct.router.route(/^\/browse\/(.*)$/, (path, results, params) => {
|
||||||
|
let navigatePath = results[1];
|
||||||
|
if (!navigatePath) {
|
||||||
|
navigatePath = 'mine';
|
||||||
|
}
|
||||||
|
navigateToPath(navigatePath, params.view);
|
||||||
|
});
|
||||||
|
|
||||||
|
openmct.router.on('change:params', function (newParams, oldParams, changed) {
|
||||||
|
if (changed.view && browseObject) {
|
||||||
|
let provider = openmct
|
||||||
|
.objectViews
|
||||||
|
.getByProviderKey(changed.view);
|
||||||
|
viewObject(browseObject, provider);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
Reference in New Issue
Block a user