mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-10-29 17:42:12 +08:00
Merge pull request #13922 from guerler/replace_multiview
Replace scratchbook with window manager
This commit is contained in:
@@ -92,6 +92,7 @@
|
||||
"vuex": "^3.6.2",
|
||||
"vuex-cache": "^3.4.0",
|
||||
"vuex-persist": "2.3",
|
||||
"winbox": "^0.2.1",
|
||||
"xml-beautifier": "^0.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
@@ -65,6 +65,7 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { getAppRoot } from "onload";
|
||||
import { backboneRoute, useGalaxy, iframeRedirect } from "components/plugins/legacyNavigation";
|
||||
import { StatelessTags } from "components/Tags";
|
||||
import { STATES } from "./model/states";
|
||||
@@ -137,10 +138,14 @@ export default {
|
||||
onDisplay() {
|
||||
const id = this.item.id;
|
||||
useGalaxy((Galaxy) => {
|
||||
const url = `${getAppRoot()}datasets/${id}/display/?preview=True`;
|
||||
if (Galaxy.frame && Galaxy.frame.active) {
|
||||
Galaxy.frame.addDataset(id);
|
||||
Galaxy.frame.add({
|
||||
title: this.name,
|
||||
url: url,
|
||||
});
|
||||
} else {
|
||||
iframeRedirect(`datasets/${id}/display/?preview=True`);
|
||||
iframeRedirect(url);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -113,10 +113,12 @@ export default {
|
||||
this.backboneRoute(`root?job_id=${this.item.creating_job}`);
|
||||
},
|
||||
onVisualize() {
|
||||
const name = this.item.name || "";
|
||||
const title = `Visualization of ${name}`;
|
||||
const path = `visualizations?dataset_id=${this.item.id}`;
|
||||
const redirectParams = {
|
||||
path: path,
|
||||
title: "Dataset details",
|
||||
title: title,
|
||||
tryIframe: false,
|
||||
};
|
||||
if (!this.iframeAdd(redirectParams)) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { default as Masthead } from "./Masthead.vue";
|
||||
import { mount } from "@vue/test-utils";
|
||||
import { getLocalVue } from "jest/helpers";
|
||||
import Scratchbook from "layout/scratchbook";
|
||||
import { WindowManager } from "layout/window-manager";
|
||||
import { fetchMenu } from "layout/menu";
|
||||
import { loadWebhookMenuItems } from "./_webhooks";
|
||||
|
||||
@@ -12,7 +12,7 @@ jest.mock("./_webhooks");
|
||||
describe("Masthead.vue", () => {
|
||||
let wrapper;
|
||||
let localVue;
|
||||
let scratchbook;
|
||||
let windowManager;
|
||||
let quotaRendered;
|
||||
let quotaEl;
|
||||
let tabs;
|
||||
@@ -71,15 +71,15 @@ describe("Masthead.vue", () => {
|
||||
];
|
||||
const initialActiveTab = "shared";
|
||||
|
||||
// scratchbook assumes this is a Backbone collection - mock that out.
|
||||
// window manager assumes this is a Backbone collection - mock that out.
|
||||
tabs.add = (x) => {
|
||||
tabs.push(x);
|
||||
return x;
|
||||
};
|
||||
scratchbook = new Scratchbook({});
|
||||
windowManager = new WindowManager({});
|
||||
const mastheadState = {
|
||||
quotaMeter,
|
||||
frame: scratchbook,
|
||||
windowManager,
|
||||
};
|
||||
|
||||
wrapper = mount(Masthead, {
|
||||
@@ -105,7 +105,7 @@ describe("Masthead.vue", () => {
|
||||
});
|
||||
|
||||
it("should render simple tab item links", () => {
|
||||
expect(wrapper.findAll("li.nav-item").length).toBe(6);
|
||||
expect(wrapper.findAll("li.nav-item").length).toBe(5);
|
||||
// Ensure specified link title respected.
|
||||
expect(wrapper.find("#analysis a").text()).toBe("Analyze");
|
||||
expect(wrapper.find("#analysis a").attributes("href")).toBe("/root");
|
||||
@@ -132,11 +132,11 @@ describe("Masthead.vue", () => {
|
||||
expect(wrapper.find("#shared").classes("active")).toBe(true);
|
||||
});
|
||||
|
||||
it("should display scratchbook button", async () => {
|
||||
expect(wrapper.find("#enable-scratchbook a span").classes("fa-th")).toBe(true);
|
||||
expect(scratchbook.active).toBe(false);
|
||||
await wrapper.find("#enable-scratchbook a").trigger("click");
|
||||
expect(scratchbook.active).toBe(true);
|
||||
it("should display window manager button", async () => {
|
||||
expect(wrapper.find("#enable-window-manager a span").classes("fa-th")).toBe(true);
|
||||
expect(windowManager.active).toBe(false);
|
||||
await wrapper.find("#enable-window-manager a").trigger("click");
|
||||
expect(windowManager.active).toBe(true);
|
||||
});
|
||||
|
||||
it("should load webhooks on creation", async () => {
|
||||
|
||||
@@ -82,8 +82,8 @@ export default {
|
||||
return brandTitle;
|
||||
},
|
||||
tabs() {
|
||||
const scratchbookTabs = [this.mastheadState.frame.buttonActive, this.mastheadState.frame.buttonLoad];
|
||||
const tabs = [].concat(this.baseTabs, this.extensionTabs, scratchbookTabs);
|
||||
const windowTabs = [this.mastheadState.windowManager.buttonActive];
|
||||
const tabs = [].concat(this.baseTabs, this.extensionTabs, windowTabs);
|
||||
return tabs.map(this._tabToJson);
|
||||
},
|
||||
},
|
||||
@@ -95,17 +95,6 @@ export default {
|
||||
mounted() {
|
||||
this.mastheadState.quotaMeter.setElement(this.$refs["quota-meter-container"]);
|
||||
this.mastheadState.quotaMeter.render();
|
||||
const frames = this.mastheadState.frame.getFrames();
|
||||
frames
|
||||
.on("add remove", () => {
|
||||
const tab = this.mastheadState.frame.buttonLoad;
|
||||
tab.note = String(frames.length());
|
||||
tab.visible = frames.length() > 0;
|
||||
tab.show_note = frames.length() > 0;
|
||||
})
|
||||
.on("show hide", () => {
|
||||
this._reflectScratchbookFrames();
|
||||
});
|
||||
},
|
||||
methods: {
|
||||
addItem(item) {
|
||||
@@ -127,12 +116,6 @@ export default {
|
||||
}
|
||||
return Object.assign({}, defaults, asJson);
|
||||
},
|
||||
_reflectScratchbookFrames() {
|
||||
const frames = this.mastheadState.frame.getFrames();
|
||||
const tab = this.mastheadState.frame.buttonLoad;
|
||||
tab.toggle = frames.visible;
|
||||
tab.icon = (frames.visible && "fa-eye") || "fa-eye-slash";
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -148,9 +148,6 @@ export default {
|
||||
propogateClick(tab, event) {
|
||||
event.preventDefault();
|
||||
tab.onclick();
|
||||
if (tab.id === "enable-scratchbook") {
|
||||
this.$emit("updateScratchbookTab", tab);
|
||||
}
|
||||
},
|
||||
formatUrl(url) {
|
||||
if (typeof url === "string" && url.indexOf("//") === -1 && url.charAt(0) != "/") {
|
||||
|
||||
@@ -17,13 +17,13 @@ export function backboneRoute(path, ...args) {
|
||||
}
|
||||
}
|
||||
|
||||
// wrapper for scratchbook/multiview feature
|
||||
// wrapper for window manager
|
||||
export function iframeAdd({ path, title = "Galaxy", tryIframe = true }) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
if (Galaxy.frame && Galaxy.frame.active) {
|
||||
Galaxy.frame.add({
|
||||
url: prependPath(path),
|
||||
title: _l(title),
|
||||
url: prependPath(path),
|
||||
});
|
||||
return true;
|
||||
} else if (tryIframe) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import $ from "jquery";
|
||||
import Scratchbook from "layout/scratchbook";
|
||||
import { WindowManager } from "layout/window-manager";
|
||||
import QuotaMeter from "mvc/user/user-quotameter";
|
||||
import { getGalaxyInstance } from "app";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
@@ -13,7 +13,7 @@ export class MastheadState {
|
||||
|
||||
constructor(Galaxy = null) {
|
||||
Galaxy = Galaxy || getGalaxyInstance();
|
||||
Galaxy.frame = this.frame = new Scratchbook();
|
||||
Galaxy.frame = this.windowManager = new WindowManager();
|
||||
|
||||
// set up the quota meter (And fetch the current user data from trans)
|
||||
// add quota meter to masthead
|
||||
@@ -35,7 +35,7 @@ export class MastheadState {
|
||||
}
|
||||
})
|
||||
.on("beforeunload", () => {
|
||||
const text = this.frame.beforeUnload();
|
||||
const text = this.windowManager.beforeUnload();
|
||||
if (text) {
|
||||
return text;
|
||||
}
|
||||
|
||||
@@ -239,7 +239,6 @@ export function fetchMenu(options = {}) {
|
||||
cls: "loggedout-only",
|
||||
tooltip: _l("Login"),
|
||||
url: "login",
|
||||
noscratchbook: true,
|
||||
};
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -62,7 +62,6 @@ const View = Backbone.View.extend({
|
||||
this.masthead = mountMasthead(this.$masthead[0], this.config, mastheadState);
|
||||
}
|
||||
this.$center.append(this.center.$el);
|
||||
this.$el.append(mastheadState.frame.$el);
|
||||
this.$el.append(this.modal.$el);
|
||||
|
||||
// build panels
|
||||
|
||||
@@ -1,247 +0,0 @@
|
||||
/** Frame manager uses the ui-frames to create the scratch book masthead icon and functionality **/
|
||||
import _ from "underscore";
|
||||
import $ from "jquery";
|
||||
import Backbone from "backbone";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
import { getGalaxyInstance } from "app";
|
||||
import Frames from "mvc/ui/ui-frames";
|
||||
import { Dataset, createTabularDatasetChunkedView, TabularDataset } from "mvc/dataset/data";
|
||||
import visualization from "viz/visualization";
|
||||
import { TracksterUI } from "viz/trackster";
|
||||
import _l from "utils/localization";
|
||||
|
||||
export default Backbone.View.extend({
|
||||
initialize: function (options) {
|
||||
options = options || {};
|
||||
this.frames = new Frames.View({ visible: false });
|
||||
this.setElement(this.frames.$el);
|
||||
this.active = false;
|
||||
this.buttonActive = {
|
||||
id: "enable-scratchbook",
|
||||
icon: "fa-th",
|
||||
tooltip: _l("Enable/Disable Scratchbook"),
|
||||
toggle: false,
|
||||
onclick: () => {
|
||||
this.active = !this.active;
|
||||
this.buttonActive.toggle = this.active;
|
||||
this.buttonActive.show_note = this.active;
|
||||
this.buttonActive.note_cls = this.active && "fa fa-check";
|
||||
if (!this.active) {
|
||||
this.frames.hide();
|
||||
}
|
||||
},
|
||||
};
|
||||
this.buttonLoad = {
|
||||
id: "show-scratchbook",
|
||||
icon: "fa-eye",
|
||||
tooltip: _l("Show/Hide Scratchbook"),
|
||||
show_note: true,
|
||||
visible: false,
|
||||
note: "",
|
||||
onclick: (e) => {
|
||||
if (this.frames.visible) {
|
||||
this.frames.hide();
|
||||
} else {
|
||||
this.frames.show();
|
||||
}
|
||||
},
|
||||
};
|
||||
this.history_cache = {};
|
||||
},
|
||||
|
||||
getFrames() {
|
||||
// needed for Vue.js integration
|
||||
return this.frames;
|
||||
},
|
||||
|
||||
beforeUnload() {
|
||||
let confirmText = "";
|
||||
if (this.frames.length() > 0) {
|
||||
confirmText = `You opened ${this.frames.length()} frame(s) which will be lost.`;
|
||||
}
|
||||
return confirmText;
|
||||
},
|
||||
|
||||
/** Add a dataset to the frames */
|
||||
addDataset: function (dataset_id) {
|
||||
const self = this;
|
||||
let current_dataset = null;
|
||||
const Galaxy = getGalaxyInstance();
|
||||
if (Galaxy && Galaxy.currHistoryPanel) {
|
||||
const history_id = Galaxy.currHistoryPanel.model.id;
|
||||
this.history_cache[history_id] = {
|
||||
name: Galaxy.currHistoryPanel.model.get("name"),
|
||||
dataset_ids: [],
|
||||
};
|
||||
Galaxy.currHistoryPanel.collection.each((model) => {
|
||||
if (!model.get("deleted") && model.get("visible") && model.get("history_content_type") == "dataset") {
|
||||
self.history_cache[history_id].dataset_ids.push(model.get("id"));
|
||||
}
|
||||
});
|
||||
}
|
||||
const _findDataset = (dataset, offset) => {
|
||||
if (dataset) {
|
||||
const history_details = self.history_cache[dataset.get("history_id")];
|
||||
if (history_details && history_details.dataset_ids) {
|
||||
const dataset_list = history_details.dataset_ids;
|
||||
const pos = dataset_list.indexOf(dataset.get("id"));
|
||||
if (pos !== -1 && pos + offset >= 0 && pos + offset < dataset_list.length) {
|
||||
return dataset_list[pos + offset];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
const _loadOffset = (dataset, offset, frame) => {
|
||||
const new_dataset_id = _findDataset(dataset, offset);
|
||||
if (new_dataset_id) {
|
||||
self._loadDataset(new_dataset_id, (new_dataset, config) => {
|
||||
current_dataset = new_dataset;
|
||||
frame.model.set(config);
|
||||
});
|
||||
}
|
||||
};
|
||||
this._loadDataset(dataset_id, (dataset, config) => {
|
||||
current_dataset = dataset;
|
||||
self.add(
|
||||
_.extend(
|
||||
{
|
||||
menu: [
|
||||
{
|
||||
icon: "fa fa-chevron-circle-left",
|
||||
tooltip: _l("Previous in History"),
|
||||
onclick: function (frame) {
|
||||
_loadOffset(current_dataset, -1, frame);
|
||||
},
|
||||
disabled: function () {
|
||||
return !_findDataset(current_dataset, -1);
|
||||
},
|
||||
},
|
||||
{
|
||||
icon: "fa fa-chevron-circle-right",
|
||||
tooltip: _l("Next in History"),
|
||||
onclick: function (frame) {
|
||||
_loadOffset(current_dataset, 1, frame);
|
||||
},
|
||||
disabled: function () {
|
||||
return !_findDataset(current_dataset, 1);
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
config
|
||||
)
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
_loadDataset: function (dataset_id, callback) {
|
||||
const self = this;
|
||||
const dataset = new Dataset({ id: dataset_id });
|
||||
$.when(dataset.fetch()).then(() => {
|
||||
const is_tabular = _.find(
|
||||
["tabular", "interval"],
|
||||
(data_type) => dataset.get("data_type").indexOf(data_type) !== -1
|
||||
);
|
||||
let title = dataset.get("name");
|
||||
const history_details = self.history_cache[dataset.get("history_id")];
|
||||
if (history_details) {
|
||||
title = `${history_details.name}: ${title}`;
|
||||
}
|
||||
callback(
|
||||
dataset,
|
||||
is_tabular
|
||||
? {
|
||||
title: title,
|
||||
url: null,
|
||||
content: createTabularDatasetChunkedView({
|
||||
model: new TabularDataset(dataset.toJSON()),
|
||||
embedded: true,
|
||||
height: "100%",
|
||||
}).$el,
|
||||
}
|
||||
: {
|
||||
title: title,
|
||||
url: `${getAppRoot()}datasets/${dataset_id}/display/?preview=True`,
|
||||
content: null,
|
||||
}
|
||||
);
|
||||
});
|
||||
},
|
||||
|
||||
/** Add a trackster visualization to the frames. */
|
||||
addTrackster: function (viz_id) {
|
||||
const self = this;
|
||||
const viz = new visualization.Visualization({ id: viz_id });
|
||||
$.when(viz.fetch()).then(() => {
|
||||
const ui = new TracksterUI(getAppRoot());
|
||||
|
||||
// Construct frame config based on dataset's type.
|
||||
const frame_config = {
|
||||
title: viz.get("name"),
|
||||
type: "other",
|
||||
content: function (parent_elt) {
|
||||
// Create view config.
|
||||
const view_config = {
|
||||
container: parent_elt,
|
||||
name: viz.get("title"),
|
||||
id: viz.id,
|
||||
// FIXME: this will not work with custom builds b/c the dbkey needed to be encoded.
|
||||
dbkey: viz.get("dbkey"),
|
||||
stand_alone: false,
|
||||
};
|
||||
|
||||
const latest_revision = viz.get("latest_revision");
|
||||
const drawables = latest_revision.config.view.drawables;
|
||||
|
||||
// Set up datasets in drawables.
|
||||
_.each(drawables, (d) => {
|
||||
d.dataset = {
|
||||
hda_ldda: d.hda_ldda,
|
||||
id: d.dataset_id,
|
||||
};
|
||||
});
|
||||
ui.create_visualization(
|
||||
view_config,
|
||||
latest_revision.config.viewport,
|
||||
latest_revision.config.view.drawables,
|
||||
latest_revision.config.bookmarks,
|
||||
false
|
||||
);
|
||||
},
|
||||
};
|
||||
self.add(frame_config);
|
||||
});
|
||||
},
|
||||
|
||||
/** Add and display a new frame/window based on options. */
|
||||
add: function (options) {
|
||||
if (options.target == "_blank") {
|
||||
window.open(options.url);
|
||||
} else if (options.target == "_top" || options.target == "_parent" || options.target == "_self") {
|
||||
window.location = options.url;
|
||||
} else if (!this.active || options.noscratchbook) {
|
||||
const $galaxy_main = $(window.parent.document).find("#galaxy_main");
|
||||
if (options.target == "galaxy_main" || options.target == "center") {
|
||||
if ($galaxy_main.length === 0) {
|
||||
window.location = this._build_url(options.url, { use_panels: true });
|
||||
} else {
|
||||
$galaxy_main.attr("src", options.url);
|
||||
}
|
||||
} else {
|
||||
window.location = options.url;
|
||||
}
|
||||
} else {
|
||||
options.url = this._build_url(options.url, { hide_panels: true, hide_masthead: true });
|
||||
this.frames.add(options);
|
||||
}
|
||||
},
|
||||
|
||||
/** Url helper */
|
||||
_build_url: function (url, options) {
|
||||
if (url) {
|
||||
url += url.indexOf("?") == -1 ? "?" : "&";
|
||||
url += $.param(options, true);
|
||||
return url;
|
||||
}
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,74 @@
|
||||
/** Adds window manager masthead icon and functionality **/
|
||||
import _l from "utils/localization";
|
||||
import WinBox from "winbox/src/js/winbox.js";
|
||||
import "winbox/dist/css/winbox.min.css";
|
||||
|
||||
export class WindowManager {
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
this.counter = 0;
|
||||
this.active = false;
|
||||
this.buttonActive = {
|
||||
id: "enable-window-manager",
|
||||
icon: "fa-th",
|
||||
tooltip: _l("Enable/Disable Window Manager"),
|
||||
toggle: false,
|
||||
onclick: () => {
|
||||
this.active = !this.active;
|
||||
this.buttonActive.toggle = this.active;
|
||||
this.buttonActive.show_note = this.active;
|
||||
this.buttonActive.note_cls = this.active && "fa fa-check";
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
/** Add and display a new window based on options. */
|
||||
add(options) {
|
||||
if (options.target == "_blank") {
|
||||
window.open(options.url);
|
||||
} else if (options.target == "_top" || options.target == "_parent" || options.target == "_self") {
|
||||
window.location = options.url;
|
||||
} else if (!this.active) {
|
||||
const $galaxy_main = window.parent.document.getElementById("galaxy_main");
|
||||
if (options.target == "galaxy_main" || options.target == "center") {
|
||||
if ($galaxy_main.length === 0) {
|
||||
window.location = this._build_url(options.url, { use_panels: true });
|
||||
} else {
|
||||
$galaxy_main.attr("src", options.url);
|
||||
}
|
||||
} else {
|
||||
window.location = options.url;
|
||||
}
|
||||
} else {
|
||||
this.counter++;
|
||||
const url = this._build_url(options.url, { hide_panels: true, hide_masthead: true });
|
||||
WinBox.new({
|
||||
title: options.title || "Window",
|
||||
url: url,
|
||||
onclose: () => {
|
||||
this.counter--;
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** Called before closing all windows. */
|
||||
beforeUnload() {
|
||||
let confirmText = "";
|
||||
if (this.counter > 0) {
|
||||
confirmText = `You opened ${this.counter} window(s) which will be lost.`;
|
||||
}
|
||||
return confirmText;
|
||||
}
|
||||
|
||||
/** Url helper */
|
||||
_build_url(url, options) {
|
||||
if (url) {
|
||||
url += url.indexOf("?") == -1 ? "?" : "&";
|
||||
Object.entries(options).forEach(([key, value]) => {
|
||||
url += `${key}=${value}&`;
|
||||
});
|
||||
return url;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ import BASE_MVC from "mvc/base-mvc";
|
||||
import _l from "utils/localization";
|
||||
import { mountNametags } from "components/Nametags";
|
||||
import { Toast } from "ui/toast";
|
||||
import { getAppRoot } from "onload/loadConfig";
|
||||
|
||||
var logNamespace = "dataset";
|
||||
/*==============================================================================
|
||||
@@ -187,7 +188,8 @@ export var DatasetListItemView = _super.extend(
|
||||
if (Galaxy.frame && Galaxy.frame.active) {
|
||||
// Add dataset to frames.
|
||||
const identifier = self.model.get("element_id") || self.model.get("id");
|
||||
Galaxy.frame.addDataset(identifier);
|
||||
const url = `${getAppRoot()}datasets/${identifier}/display/?preview=True`;
|
||||
Galaxy.frame.add({ url });
|
||||
ev.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,648 +0,0 @@
|
||||
/** Frame view */
|
||||
import _ from "underscore";
|
||||
import $ from "jquery";
|
||||
import Backbone from "backbone";
|
||||
import _l from "utils/localization";
|
||||
import { getGalaxyInstance } from "app";
|
||||
|
||||
var FrameView = Backbone.View.extend({
|
||||
initialize: function (options) {
|
||||
this.model = (options && options.model) || new Backbone.Model(options);
|
||||
this.setElement($("<div/>").addClass("corner frame"));
|
||||
this.$el
|
||||
.append(
|
||||
$("<div/>")
|
||||
.addClass("f-header corner")
|
||||
.append($("<div/>").addClass("f-title"))
|
||||
.append(
|
||||
$("<div/>")
|
||||
.addClass("f-icon f-close fa fa-close")
|
||||
.tooltip({
|
||||
title: _l("Close"),
|
||||
placement: "bottom",
|
||||
})
|
||||
)
|
||||
)
|
||||
.append($("<div/>").addClass("f-content"))
|
||||
.append($("<div/>").addClass("f-resize f-icon corner fa fa-expand").tooltip({ title: "Resize" }))
|
||||
.append($("<div/>").addClass("f-cover"));
|
||||
this.$header = this.$(".f-header");
|
||||
this.$title = this.$(".f-title");
|
||||
this.$content = this.$(".f-content");
|
||||
this.render();
|
||||
this.listenTo(this.model, "change", this.render, this);
|
||||
},
|
||||
|
||||
render: function () {
|
||||
var self = this;
|
||||
var options = this.model.attributes;
|
||||
this.$title.html(_.escape(options.title) || "");
|
||||
this.$header.find(".f-icon-left").remove();
|
||||
_.each(options.menu, (option) => {
|
||||
var $option = $("<div/>").addClass("f-icon-left").addClass(option.icon);
|
||||
if (_.isFunction(option.disabled) && option.disabled()) {
|
||||
$option.attr("disabled", true);
|
||||
} else {
|
||||
$option
|
||||
.on("click", () => {
|
||||
option.onclick(self);
|
||||
})
|
||||
.tooltip({
|
||||
title: option.tooltip || "",
|
||||
placement: "bottom",
|
||||
});
|
||||
}
|
||||
self.$header.append($option);
|
||||
});
|
||||
if (options.url) {
|
||||
this.$content.html(
|
||||
$("<iframe/>")
|
||||
.addClass("f-iframe")
|
||||
.attr("scrolling", "auto")
|
||||
.attr("src", `${options.url + (options.url.indexOf("?") === -1 ? "?" : "&")}widget=True`)
|
||||
);
|
||||
} else if (options.content) {
|
||||
if (_.isFunction(options.content)) {
|
||||
options.content(self.$content);
|
||||
} else {
|
||||
self.$content.html(options.content);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
/** Scratchbook viewer */
|
||||
var View = Backbone.View.extend({
|
||||
defaultOptions: {
|
||||
frame: {
|
||||
// default frame size in cells
|
||||
cols: 6,
|
||||
rows: 3,
|
||||
},
|
||||
rows: 1000, // maximum number of rows
|
||||
cell: 130, // cell size in px
|
||||
margin: 5, // margin between frames
|
||||
scroll: 5, // scroll speed
|
||||
top_min: 40, // top margin
|
||||
frame_max: 9, // maximum number of frames
|
||||
visible: true, // initial visibility
|
||||
},
|
||||
|
||||
cols: 0, // number of columns
|
||||
top: 0, // scroll/element top
|
||||
top_max: 0, // viewport scrolling state
|
||||
frame_z: 0, // frame z-index
|
||||
frame_counter: 0, // frame counter
|
||||
frame_uid: 0, // unique frame id counter
|
||||
frame_list: {}, // list of all frames
|
||||
frame_shadow: null, // frame shown as placeholder when moving active frames
|
||||
visible: false, // flag indicating if scratchbook viewer is visible or not
|
||||
event: {}, // dictionary keeping track of current event
|
||||
|
||||
initialize: function (options) {
|
||||
var self = this;
|
||||
this.options = _.defaults(options || {}, this.defaultOptions);
|
||||
this.visible = this.options.visible;
|
||||
this.top = this.top_max = this.options.top_min;
|
||||
this.setElement(
|
||||
$("<div/>")
|
||||
.addClass("galaxy-frame")
|
||||
.append($("<div/>").addClass("frame-background"))
|
||||
.append($("<div/>").addClass("frame-menu frame-scroll-up fa fa-chevron-up fa-2x"))
|
||||
.append($("<div/>").addClass("frame-menu frame-scroll-down fa fa-chevron-down fa-2x"))
|
||||
);
|
||||
|
||||
// initialize shadow to guiding drag/resize events
|
||||
this.frame_shadow = new Backbone.View({
|
||||
el: $("<div/>").addClass("corner frame-shadow"),
|
||||
});
|
||||
this.$el.append(this.frame_shadow.$el);
|
||||
this._frameInit(this.frame_shadow, "#frame-shadow");
|
||||
this._frameResize(this.frame_shadow, { width: 0, height: 0 });
|
||||
this.frame_list["#frame-shadow"] = this.frame_shadow;
|
||||
|
||||
// initialize panel
|
||||
if (this.visible) {
|
||||
this.show();
|
||||
} else {
|
||||
this.hide();
|
||||
}
|
||||
this._panelRefresh();
|
||||
$(window).resize(() => {
|
||||
if (self.visible) {
|
||||
self._panelRefresh();
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
/** Render */
|
||||
render: function () {
|
||||
this.$(".frame-scroll-up")[(this.top != this.options.top_min && "show") || "hide"]();
|
||||
this.$(".frame-scroll-down")[(this.top != this.top_max && "show") || "hide"]();
|
||||
},
|
||||
|
||||
/**
|
||||
* Adds and displays a new frame.
|
||||
*
|
||||
* options:
|
||||
* url : loaded into an iframe
|
||||
* content : content is treated as a function or raw HTML, function is passed a single
|
||||
* argument that is the frame's content DOM element
|
||||
*/
|
||||
add: function (options) {
|
||||
const Galaxy = getGalaxyInstance();
|
||||
if (this.frame_counter >= this.options.frame_max) {
|
||||
Galaxy.modal.show({
|
||||
title: _l("Warning"),
|
||||
body: `You have reached the maximum number of allowed frames (${this.options.frame_max}).`,
|
||||
buttons: {
|
||||
Close: function () {
|
||||
Galaxy.modal.hide();
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
var frame_id = `#frame-${this.frame_uid++}`;
|
||||
if ($(frame_id).length !== 0) {
|
||||
Galaxy.modal.show({
|
||||
title: _l("Error"),
|
||||
body: "This frame already exists. This page might contain multiple frame managers.",
|
||||
buttons: {
|
||||
Close: function () {
|
||||
Galaxy.modal.hide();
|
||||
},
|
||||
},
|
||||
});
|
||||
} else {
|
||||
// initialize new frame elements
|
||||
this.top = this.options.top_min;
|
||||
var frame = new FrameView(options);
|
||||
this.$el.append(frame.$el);
|
||||
|
||||
// set dimensions
|
||||
options.width = this._toPixelCoord("width", this.options.frame.cols);
|
||||
options.height = this._toPixelCoord("height", this.options.frame.rows);
|
||||
|
||||
// set default z-index and add to ui and frame list
|
||||
this.frame_z = parseInt(frame.$el.css("z-index"));
|
||||
this.frame_list[frame_id] = frame;
|
||||
this.frame_counter++;
|
||||
this._frameInit(frame, frame_id);
|
||||
this._frameResize(frame, {
|
||||
width: options.width,
|
||||
height: options.height,
|
||||
});
|
||||
this._frameInsert(frame, { top: 0, left: 0 }, true);
|
||||
if (!this.visible) {
|
||||
this.show();
|
||||
}
|
||||
this.trigger("add");
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** Remove a frame */
|
||||
del: function (frame) {
|
||||
var self = this;
|
||||
var $frame = frame.$el;
|
||||
$frame.fadeOut("fast", () => {
|
||||
$frame.remove();
|
||||
delete self.frame_list[frame.id];
|
||||
self.frame_counter--;
|
||||
self._panelRefresh(true);
|
||||
self._panelAnimationComplete();
|
||||
if (this.frame_counter == 0) {
|
||||
this._eventHide();
|
||||
}
|
||||
self.trigger("remove");
|
||||
});
|
||||
},
|
||||
|
||||
/** Show panel */
|
||||
show: function () {
|
||||
this.visible = true;
|
||||
this.$el.fadeIn("fast");
|
||||
this.trigger("show");
|
||||
},
|
||||
|
||||
/** Hide panel */
|
||||
hide: function () {
|
||||
if (!this.event.type) {
|
||||
this.visible = false;
|
||||
this.$el.fadeOut("fast", function () {
|
||||
$(this).hide();
|
||||
});
|
||||
this.trigger("hide");
|
||||
}
|
||||
},
|
||||
|
||||
/** Returns the number of frames */
|
||||
length: function () {
|
||||
return this.frame_counter;
|
||||
},
|
||||
|
||||
/*
|
||||
EVENT HANDLING
|
||||
*/
|
||||
events: {
|
||||
// global frame events
|
||||
mousemove: "_eventFrameMouseMove",
|
||||
mouseup: "_eventFrameMouseUp",
|
||||
mouseleave: "_eventFrameMouseUp",
|
||||
mousewheel: "_eventPanelScroll",
|
||||
DOMMouseScroll: "_eventPanelScroll",
|
||||
|
||||
// events fixed to elements
|
||||
"mousedown .frame": "_eventFrameMouseDown",
|
||||
"mousedown .frame-background": "_eventHide",
|
||||
"mousedown .frame-scroll-up": "_eventPanelScroll_up",
|
||||
"mousedown .frame-scroll-down": "_eventPanelScroll_down",
|
||||
"mousedown .f-close": "_eventFrameClose",
|
||||
},
|
||||
|
||||
/** Start drag/resize event */
|
||||
_eventFrameMouseDown: function (e) {
|
||||
$(".tooltip").hide();
|
||||
if (!this.event.type) {
|
||||
if ($(e.target).hasClass("f-header") || $(e.target).hasClass("f-title")) {
|
||||
this.event.type = "drag";
|
||||
}
|
||||
if ($(e.target).hasClass("f-resize")) {
|
||||
this.event.type = "resize";
|
||||
}
|
||||
if (this.event.type) {
|
||||
e.preventDefault();
|
||||
this.event.target = this._frameIdentify(e.target);
|
||||
this.event.xy = {
|
||||
x: e.originalEvent.pageX,
|
||||
y: e.originalEvent.pageY,
|
||||
};
|
||||
this._frameDragStart(this.event.target);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** Processes drag/resize events */
|
||||
_eventFrameMouseMove: function (e) {
|
||||
if (this.event.type) {
|
||||
// get mouse motion and delta
|
||||
var event_xy_new = {
|
||||
x: e.originalEvent.pageX,
|
||||
y: e.originalEvent.pageY,
|
||||
};
|
||||
var event_xy_delta = {
|
||||
x: event_xy_new.x - this.event.xy.x,
|
||||
y: event_xy_new.y - this.event.xy.y,
|
||||
};
|
||||
this.event.xy = event_xy_new;
|
||||
|
||||
// get current screen position and size of frame
|
||||
var p = this._frameScreen(this.event.target);
|
||||
|
||||
// drag/resize event
|
||||
if (this.event.type == "resize") {
|
||||
p.width += event_xy_delta.x;
|
||||
p.height += event_xy_delta.y;
|
||||
var min_dim = this.options.cell - this.options.margin - 1;
|
||||
p.width = Math.max(p.width, min_dim);
|
||||
p.height = Math.max(p.height, min_dim);
|
||||
this._frameResize(this.event.target, p);
|
||||
p.width = this._toGridCoord("width", p.width) + 1;
|
||||
p.height = this._toGridCoord("height", p.height) + 1;
|
||||
p.width = this._toPixelCoord("width", p.width);
|
||||
p.height = this._toPixelCoord("height", p.height);
|
||||
this._frameResize(this.frame_shadow, p);
|
||||
this._frameInsert(this.frame_shadow, {
|
||||
top: this._toGridCoord("top", p.top),
|
||||
left: this._toGridCoord("left", p.left),
|
||||
});
|
||||
} else if (this.event.type == "drag") {
|
||||
p.left += event_xy_delta.x;
|
||||
p.top += event_xy_delta.y;
|
||||
this._frameOffset(this.event.target, p);
|
||||
var l = {
|
||||
top: this._toGridCoord("top", p.top),
|
||||
left: this._toGridCoord("left", p.left),
|
||||
};
|
||||
if (l.left !== 0) {
|
||||
l.left++;
|
||||
}
|
||||
this._frameInsert(this.frame_shadow, l);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** Stop drag/resize events */
|
||||
_eventFrameMouseUp: function (e) {
|
||||
if (this.event.type) {
|
||||
this._frameDragStop(this.event.target);
|
||||
this.event.type = null;
|
||||
}
|
||||
},
|
||||
|
||||
/** Destroy a frame */
|
||||
_eventFrameClose: function (e) {
|
||||
if (!this.event.type) {
|
||||
e.preventDefault();
|
||||
this.del(this._frameIdentify(e.target));
|
||||
}
|
||||
},
|
||||
|
||||
/** Hide all frames */
|
||||
_eventHide: function (e) {
|
||||
if (!this.event.type) {
|
||||
this.hide();
|
||||
}
|
||||
},
|
||||
|
||||
/** Fired when scrolling occurs on panel */
|
||||
_eventPanelScroll: function (e) {
|
||||
if (!this.event.type && this.visible) {
|
||||
// Stop propagation if scrolling is happening inside a frame.
|
||||
// TODO: could propagate scrolling if at top/bottom of frame.
|
||||
var frames = $(e.srcElement).parents(".frame");
|
||||
if (frames.length !== 0) {
|
||||
e.stopPropagation();
|
||||
} else {
|
||||
e.preventDefault();
|
||||
this._panelScroll(e.originalEvent.detail ? e.originalEvent.detail : e.originalEvent.wheelDelta / -3);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/** Handle scroll up event */
|
||||
_eventPanelScroll_up: function (e) {
|
||||
if (!this.event.type) {
|
||||
e.preventDefault();
|
||||
this._panelScroll(-this.options.scroll);
|
||||
}
|
||||
},
|
||||
|
||||
/** Handle scroll down */
|
||||
_eventPanelScroll_down: function (e) {
|
||||
if (!this.event.type) {
|
||||
e.preventDefault();
|
||||
this._panelScroll(this.options.scroll);
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
FRAME EVENTS SUPPORT
|
||||
*/
|
||||
|
||||
/** Identify the target frame */
|
||||
_frameIdentify: function (target) {
|
||||
return this.frame_list[`#${$(target).closest(".frame").attr("id")}`];
|
||||
},
|
||||
|
||||
/** Provides drag support */
|
||||
_frameDragStart: function (frame) {
|
||||
this._frameFocus(frame, true);
|
||||
var p = this._frameScreen(frame);
|
||||
this._frameResize(this.frame_shadow, p);
|
||||
this._frameGrid(this.frame_shadow, frame.grid_location);
|
||||
frame.grid_location = null;
|
||||
this.frame_shadow.$el.show();
|
||||
$(".f-cover").show();
|
||||
},
|
||||
|
||||
/** Removes drag support */
|
||||
_frameDragStop: function (frame) {
|
||||
this._frameFocus(frame, false);
|
||||
var p = this._frameScreen(this.frame_shadow);
|
||||
this._frameResize(frame, p);
|
||||
this._frameGrid(frame, this.frame_shadow.grid_location, true);
|
||||
this.frame_shadow.grid_location = null;
|
||||
this.frame_shadow.$el.hide();
|
||||
$(".f-cover").hide();
|
||||
this._panelAnimationComplete();
|
||||
},
|
||||
|
||||
/*
|
||||
GRID/PIXEL CONVERTER
|
||||
*/
|
||||
|
||||
/** Converts a pixel to a grid dimension */
|
||||
_toGridCoord: function (type, px) {
|
||||
var sign = type == "width" || type == "height" ? 1 : -1;
|
||||
if (type == "top") {
|
||||
px -= this.top;
|
||||
}
|
||||
return parseInt((px + sign * this.options.margin) / this.options.cell, 10);
|
||||
},
|
||||
|
||||
/** Converts a grid to a pixels dimension */
|
||||
_toPixelCoord: function (type, g) {
|
||||
var sign = type == "width" || type == "height" ? 1 : -1;
|
||||
var px = g * this.options.cell - sign * this.options.margin;
|
||||
if (type == "top") {
|
||||
px += this.top;
|
||||
}
|
||||
return px;
|
||||
},
|
||||
|
||||
/** Converts a pixel to a grid coordinate set */
|
||||
_toGrid: function (px) {
|
||||
return {
|
||||
top: this._toGridCoord("top", px.top),
|
||||
left: this._toGridCoord("left", px.left),
|
||||
width: this._toGridCoord("width", px.width),
|
||||
height: this._toGridCoord("height", px.height),
|
||||
};
|
||||
},
|
||||
|
||||
/** Converts a pixel to a grid coordinate set */
|
||||
_toPixel: function (g) {
|
||||
return {
|
||||
top: this._toPixelCoord("top", g.top),
|
||||
left: this._toPixelCoord("left", g.left),
|
||||
width: this._toPixelCoord("width", g.width),
|
||||
height: this._toPixelCoord("height", g.height),
|
||||
};
|
||||
},
|
||||
|
||||
/*
|
||||
COLLISION DETECTION
|
||||
*/
|
||||
|
||||
/** Check collisions for a grid coordinate set */
|
||||
_isCollision: function (g) {
|
||||
function is_collision_pair(a, b) {
|
||||
return !(
|
||||
a.left > b.left + b.width - 1 ||
|
||||
a.left + a.width - 1 < b.left ||
|
||||
a.top > b.top + b.height - 1 ||
|
||||
a.top + a.height - 1 < b.top
|
||||
);
|
||||
}
|
||||
for (var i in this.frame_list) {
|
||||
var frame = this.frame_list[i];
|
||||
if (frame.grid_location !== null && is_collision_pair(g, frame.grid_location)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
/** Return location/grid rank */
|
||||
_locationRank: function (loc) {
|
||||
return loc.top * this.cols + loc.left;
|
||||
},
|
||||
|
||||
/*
|
||||
PANEL/WINDOW FUNCTIONS
|
||||
*/
|
||||
|
||||
/** Refresh panel */
|
||||
_panelRefresh: function (animate) {
|
||||
this.cols = parseInt($(window).width() / this.options.cell, 10) + 1;
|
||||
this._frameInsert(null, null, animate);
|
||||
},
|
||||
|
||||
/** Complete panel animation / frames not moving */
|
||||
_panelAnimationComplete: function () {
|
||||
var self = this;
|
||||
$(".frame")
|
||||
.promise()
|
||||
.done(() => {
|
||||
self._panelScroll(0, true);
|
||||
});
|
||||
},
|
||||
|
||||
/** Scroll panel */
|
||||
_panelScroll: function (delta, animate) {
|
||||
var top_new = this.top - this.options.scroll * delta;
|
||||
top_new = Math.max(top_new, this.top_max);
|
||||
top_new = Math.min(top_new, this.options.top_min);
|
||||
if (this.top != top_new) {
|
||||
for (var i in this.frame_list) {
|
||||
var frame = this.frame_list[i];
|
||||
if (frame.grid_location !== null) {
|
||||
var screen_location = {
|
||||
top: frame.screen_location.top - (this.top - top_new),
|
||||
left: frame.screen_location.left,
|
||||
};
|
||||
this._frameOffset(frame, screen_location, animate);
|
||||
}
|
||||
}
|
||||
this.top = top_new;
|
||||
}
|
||||
this.render();
|
||||
},
|
||||
|
||||
/*
|
||||
FRAME FUNCTIONS
|
||||
*/
|
||||
|
||||
/** Initialize a new frame */
|
||||
_frameInit: function (frame, id) {
|
||||
frame.id = id;
|
||||
frame.screen_location = {};
|
||||
frame.grid_location = {};
|
||||
frame.grid_rank = null;
|
||||
frame.$el.attr("id", id.substring(1));
|
||||
},
|
||||
|
||||
/** Insert frame at given location */
|
||||
_frameInsert: function (frame, new_loc, animate) {
|
||||
var self = this;
|
||||
var place_list = [];
|
||||
if (frame) {
|
||||
frame.grid_location = null;
|
||||
place_list.push([frame, this._locationRank(new_loc)]);
|
||||
}
|
||||
_.each(this.frame_list, (f) => {
|
||||
if (f.grid_location !== null) {
|
||||
f.grid_location = null;
|
||||
place_list.push([f, f.grid_rank]);
|
||||
}
|
||||
});
|
||||
place_list.sort((a, b) => (a[1] < b[1] ? -1 : a[1] > b[1] ? 1 : 0));
|
||||
_.each(place_list, (place) => {
|
||||
self._framePlace(place[0], animate);
|
||||
});
|
||||
this.top_max = 0;
|
||||
_.each(this.frame_list, (f) => {
|
||||
if (f.grid_location !== null) {
|
||||
self.top_max = Math.max(self.top_max, f.grid_location.top + f.grid_location.height);
|
||||
}
|
||||
});
|
||||
this.top_max = $(window).height() - this.top_max * this.options.cell - 2 * this.options.margin;
|
||||
this.top_max = Math.min(this.top_max, this.options.top_min);
|
||||
this.render();
|
||||
},
|
||||
|
||||
/** Naive frame placement */
|
||||
_framePlace: function (frame, animate) {
|
||||
frame.grid_location = null;
|
||||
var g = this._toGrid(this._frameScreen(frame));
|
||||
var done = false;
|
||||
for (var i = 0; i < this.options.rows; i++) {
|
||||
for (var j = 0; j < Math.max(1, this.cols - g.width); j++) {
|
||||
g.top = i;
|
||||
g.left = j;
|
||||
if (!this._isCollision(g)) {
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (done) {
|
||||
this._frameGrid(frame, g, animate);
|
||||
} else {
|
||||
console.log("Grid dimensions exceeded.");
|
||||
}
|
||||
},
|
||||
|
||||
/** Handle frame focussing */
|
||||
_frameFocus: function (frame, has_focus) {
|
||||
frame.$el.css("z-index", this.frame_z + (has_focus ? 1 : 0));
|
||||
},
|
||||
|
||||
/** New left/top position frame */
|
||||
_frameOffset: function (frame, p, animate) {
|
||||
frame.screen_location.left = p.left;
|
||||
frame.screen_location.top = p.top;
|
||||
if (animate) {
|
||||
this._frameFocus(frame, true);
|
||||
var self = this;
|
||||
frame.$el.animate({ top: p.top, left: p.left }, "fast", () => {
|
||||
self._frameFocus(frame, false);
|
||||
});
|
||||
} else {
|
||||
frame.$el.css({ top: p.top, left: p.left });
|
||||
}
|
||||
},
|
||||
|
||||
/** Resize frame */
|
||||
_frameResize: function (frame, p) {
|
||||
frame.$el.css({ width: p.width, height: p.height });
|
||||
frame.screen_location.width = p.width;
|
||||
frame.screen_location.height = p.height;
|
||||
},
|
||||
|
||||
/** Push frame to new grid location */
|
||||
_frameGrid: function (frame, l, animate) {
|
||||
frame.grid_location = l;
|
||||
this._frameOffset(frame, this._toPixel(l), animate);
|
||||
frame.grid_rank = this._locationRank(l);
|
||||
},
|
||||
|
||||
/** Get frame dimensions */
|
||||
_frameScreen: function (frame) {
|
||||
var p = frame.screen_location;
|
||||
return {
|
||||
top: p.top,
|
||||
left: p.left,
|
||||
width: p.width,
|
||||
height: p.height,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default {
|
||||
View: View,
|
||||
};
|
||||
@@ -507,9 +507,9 @@ define({
|
||||
"Local data": "Datos locales",
|
||||
"Form Definitions": "Definiciones de formulario",
|
||||
|
||||
// ---------------------------------------------------------------------------- Scratchbook
|
||||
"Enable/Disable Scratchbook": "Habilitar/Deshabilitar Scratchbook",
|
||||
"Show/Hide Scratchbook": "Mostrar/Ocultar Scratchbook",
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Enable/Disable Window Manager": "Habilitar/Deshabilitar Window Manager",
|
||||
"Show/Hide Window Manager": "Mostrar/Ocultar Window Manager",
|
||||
|
||||
// ---------------------------------------------------------------------------- misc. MVC
|
||||
|
||||
@@ -793,7 +793,7 @@ define({
|
||||
"Create new Build": "Crear nueva construcción",
|
||||
"Delete custom build.": "Eliminar construcción personalizada",
|
||||
"Provide the data source.": "Proporcionar la fuente de datos",
|
||||
// ---------------------------------------------------------------------------- scratchbook
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Next in History": "Siguiente en historial",
|
||||
"Previous in History": "Anterior en historial",
|
||||
// ---------------------------------------------------------------------------- generic-nav-view
|
||||
|
||||
@@ -230,9 +230,9 @@ define({
|
||||
"Local data": "Données locales",
|
||||
"Form Definitions": "Définitions de formulaires",
|
||||
|
||||
// ---------------------------------------------------------------------------- Scratchbook
|
||||
"Enable/Disable Scratchbook": "Activer/Désactiver la visu Scratchbook",
|
||||
"Show/Hide Scratchbook": "Montrer/cacher la visu Scratchbook",
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Enable/Disable Window Manager": "Activer/Désactiver la visu Window Manager",
|
||||
"Show/Hide Window Manager": "Montrer/cacher la visu Window Manager",
|
||||
|
||||
// ---------------------------------------------------------------------------- misc. MVC
|
||||
Tags: "Mots-clés",
|
||||
@@ -437,7 +437,7 @@ define({
|
||||
"Create new Build": false,
|
||||
"Delete custom build.": false,
|
||||
"Provide the data source.": false,
|
||||
// ---------------------------------------------------------------------------- scratchbook
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Next in History": false,
|
||||
"Previous in History": false,
|
||||
// ---------------------------------------------------------------------------- generic-nav-view
|
||||
|
||||
@@ -230,9 +230,9 @@ define({
|
||||
"Local data": false,
|
||||
"Form Definitions": false,
|
||||
|
||||
// ---------------------------------------------------------------------------- Scratchbook
|
||||
"Enable/Disable Scratchbook": false,
|
||||
"Show/Hide Scratchbook": false,
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Enable/Disable Window Manager": false,
|
||||
"Show/Hide Window Manager": false,
|
||||
|
||||
// ---------------------------------------------------------------------------- misc. MVC
|
||||
Tags: false,
|
||||
@@ -435,7 +435,7 @@ define({
|
||||
"Create new Build": false,
|
||||
"Delete custom build.": false,
|
||||
"Provide the data source.": false,
|
||||
// ---------------------------------------------------------------------------- scratchbook
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Next in History": false,
|
||||
"Previous in History": false,
|
||||
// ---------------------------------------------------------------------------- generic-nav-view
|
||||
|
||||
@@ -239,9 +239,9 @@ define({
|
||||
"Local data": false,
|
||||
"Form Definitions": false,
|
||||
|
||||
// ---------------------------------------------------------------------------- Scratchbook
|
||||
"Enable/Disable Scratchbook": "启用/禁用 Scratchbook",
|
||||
"Show/Hide Scratchbook": "显示/隐藏 Scratchbook",
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Enable/Disable Window Manager": "启用/禁用 Window Manager",
|
||||
"Show/Hide Window Manager": "显示/隐藏 Window Manager",
|
||||
|
||||
// ---------------------------------------------------------------------------- misc. MVC
|
||||
Tags: "标签",
|
||||
@@ -451,7 +451,7 @@ define({
|
||||
"Create new Build": "创建新的构建集",
|
||||
"Delete custom build.": "删除自定义的构建集。",
|
||||
"Provide the data source.": "提供数据源。",
|
||||
// ---------------------------------------------------------------------------- scratchbook
|
||||
// ---------------------------------------------------------------------------- Window Manager
|
||||
"Next in History": "下一个历史记录",
|
||||
"Previous in History": "上一个历史记录",
|
||||
// ---------------------------------------------------------------------------- generic-nav-view
|
||||
|
||||
@@ -24,7 +24,7 @@ $fa-font-path: "../../../node_modules/@fortawesome/fontawesome-free/webfonts/";
|
||||
|
||||
// galaxy sub-components
|
||||
@import "reports";
|
||||
@import "frame.scss";
|
||||
@import "windows.scss";
|
||||
@import "upload.scss";
|
||||
@import "ui.scss";
|
||||
@import "library.scss";
|
||||
|
||||
@@ -1,155 +0,0 @@
|
||||
$frame-zindex: 1000;
|
||||
$frame-default-border: $border-color;
|
||||
|
||||
.galaxy-frame {
|
||||
.corner {
|
||||
-moz-border-radius: $border-radius-large;
|
||||
border-radius: $border-radius-large;
|
||||
}
|
||||
|
||||
.toggle {
|
||||
color: $dropdown-link-active-color;
|
||||
}
|
||||
|
||||
.frame-background {
|
||||
z-index: $frame-zindex;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0.5;
|
||||
background: $brand-dark;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.frame-shadow {
|
||||
z-index: $frame-zindex + 1;
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
opacity: 0.5;
|
||||
background: $brand-dark;
|
||||
border: 1px solid $frame-default-border;
|
||||
}
|
||||
|
||||
/*
|
||||
panel menu button
|
||||
*/
|
||||
.frame-menu {
|
||||
z-index: $frame-zindex + 5;
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
color: $dropdown-link-active-color;
|
||||
right: 10px;
|
||||
}
|
||||
|
||||
.frame-scroll-up {
|
||||
top: 50px;
|
||||
}
|
||||
|
||||
.frame-scroll-down {
|
||||
bottom: 20px;
|
||||
}
|
||||
|
||||
/*
|
||||
frame components
|
||||
*/
|
||||
|
||||
.frame {
|
||||
z-index: $frame-zindex + 2;
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
background: $white;
|
||||
border: 1px solid $frame-default-border;
|
||||
-webkit-box-shadow: 0 0 5px rgba(0, 0, 0, 0.3);
|
||||
|
||||
.f-content {
|
||||
position: absolute;
|
||||
overflow: hidden;
|
||||
background: $white;
|
||||
border: none;
|
||||
top: 24px;
|
||||
bottom: 3px;
|
||||
left: 3px;
|
||||
right: 3px;
|
||||
}
|
||||
|
||||
.f-cover {
|
||||
position: absolute;
|
||||
display: none;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
opacity: 0;
|
||||
background: $white;
|
||||
}
|
||||
|
||||
.f-iframe {
|
||||
border: none;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.f-header {
|
||||
height: 17px;
|
||||
margin: 2px;
|
||||
cursor: pointer;
|
||||
border: 1px solid $black;
|
||||
background: $brand-dark;
|
||||
color: $white;
|
||||
.f-icon-left {
|
||||
cursor: pointer;
|
||||
font-size: 15px;
|
||||
margin-left: 3px;
|
||||
float: left;
|
||||
&[disabled] {
|
||||
opacity: 0.25;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.f-title {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
left: 50px;
|
||||
right: 50px;
|
||||
font-size: 12px;
|
||||
font-family: $font-family-sans-serif;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/*
|
||||
frame icons
|
||||
*/
|
||||
|
||||
.f-not-allowed {
|
||||
cursor: not-allowed;
|
||||
}
|
||||
|
||||
.f-close {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
font-size: 15px;
|
||||
right: 5px;
|
||||
top: 2px;
|
||||
}
|
||||
|
||||
.f-resize {
|
||||
cursor: pointer;
|
||||
position: absolute;
|
||||
font-size: 15px;
|
||||
right: 0px;
|
||||
bottom: 0px;
|
||||
background: $white;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
color: $brand-dark;
|
||||
text-align: center;
|
||||
line-height: 16px;
|
||||
border: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
.winbox {
|
||||
border-radius: $border-radius-base;
|
||||
margin-top: 4rem;
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.winbox.min {
|
||||
@extend .m-0;
|
||||
}
|
||||
|
||||
.wb-header {
|
||||
border-radius: $border-radius-base;
|
||||
background: $brand-info;
|
||||
}
|
||||
|
||||
.wb-icon * {
|
||||
opacity: 0.65;
|
||||
}
|
||||
|
||||
.wb-icon *:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.wb-full {
|
||||
display: none !important;
|
||||
}
|
||||
@@ -3,7 +3,7 @@ const path = require("path");
|
||||
// For a detailed explanation regarding each configuration property, visit:
|
||||
// https://jestjs.io/docs/en/configuration.html
|
||||
|
||||
const modulesToTransform = ["bootstrap-vue", "rxjs", "@hirez_io"].join("|");
|
||||
const modulesToTransform = ["bootstrap-vue", "rxjs", "@hirez_io", "winbox"].join("|");
|
||||
|
||||
module.exports = {
|
||||
// All imported modules in your tests should be mocked automatically
|
||||
@@ -81,7 +81,8 @@ module.exports = {
|
||||
"^config$": "<rootDir>/tests/jest/__mocks__/config.js",
|
||||
"utils/localization$": "<rootDir>/tests/jest/__mocks__/localization.js",
|
||||
"viz/trackster$": "<rootDir>/tests/jest/__mocks__/trackster.js",
|
||||
"rxjs/internal/scheduler/AsyncScheduler": "<rootDir>/node_modules/rxjs/dist/esm/internal/scheduler/AsyncScheduler.js"
|
||||
"rxjs/internal/scheduler/AsyncScheduler":
|
||||
"<rootDir>/node_modules/rxjs/dist/esm/internal/scheduler/AsyncScheduler.js",
|
||||
},
|
||||
|
||||
// An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader
|
||||
|
||||
@@ -10163,6 +10163,11 @@ wildcard@^2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/wildcard/-/wildcard-2.0.0.tgz#a77d20e5200c6faaac979e4b3aadc7b3dd7f8fec"
|
||||
integrity sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==
|
||||
|
||||
winbox@^0.2.1:
|
||||
version "0.2.1"
|
||||
resolved "https://registry.yarnpkg.com/winbox/-/winbox-0.2.1.tgz#6ca7cd047fa52d9f3324884698ce8a9c9ba9bf27"
|
||||
integrity sha512-K3PY+y+aWpkCpECGF2TqSi4w+OT+cuJHWbOKBjVerpexmdC6Is5m4y0gZ9rbxU2K+GszE1nH+d2okMAQTG05hg==
|
||||
|
||||
word-wrap@^1.2.3, word-wrap@~1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c"
|
||||
|
||||
Reference in New Issue
Block a user