mirror of
https://github.com/galaxyproject/galaxy.git
synced 2026-09-24 16:30:27 +08:00
Merge branch 'dev' into remove_formbuilder
This commit is contained in:
@@ -1,7 +0,0 @@
|
||||
import AdminToolshed from "admin.toolshed";
|
||||
|
||||
export function App(options) {
|
||||
new AdminToolshed.GalaxyApp(options);
|
||||
}
|
||||
|
||||
window.adminToolshedApp = App;
|
||||
@@ -0,0 +1,50 @@
|
||||
import WorkflowView from "mvc/workflow/workflow-view";
|
||||
import Trackster from "viz/trackster";
|
||||
import Circster from "viz/circster";
|
||||
import GalaxyLibrary from "galaxy.library";
|
||||
import AdminToolshed from "admin.toolshed";
|
||||
import Masthead from "layout/masthead";
|
||||
import user from "mvc/user/user-model";
|
||||
import Modal from "mvc/ui/ui-modal";
|
||||
|
||||
export function mastheadEntry(options) {
|
||||
if (!Galaxy.user) {
|
||||
Galaxy.user = new user.User(options.user_json);
|
||||
}
|
||||
if (!Galaxy.masthead) {
|
||||
Galaxy.masthead = new Masthead.View(options);
|
||||
Galaxy.modal = new Modal.View();
|
||||
$("#masthead").replaceWith(Galaxy.masthead.render().$el);
|
||||
}
|
||||
}
|
||||
|
||||
export function adminToolshedEntry(options) {
|
||||
new AdminToolshed.GalaxyApp(options);
|
||||
}
|
||||
|
||||
export function tracksterEntry(options) {
|
||||
new Trackster.GalaxyApp(options);
|
||||
}
|
||||
|
||||
export function circsterEntry(options) {
|
||||
new Circster.GalaxyApp(options);
|
||||
}
|
||||
|
||||
export function workflowEntry(options) {
|
||||
new WorkflowView(options);
|
||||
}
|
||||
|
||||
function libraryEntry(options) {
|
||||
new GalaxyLibrary.GalaxyApp(options);
|
||||
}
|
||||
|
||||
export const bundleEntries = {
|
||||
library: libraryEntry,
|
||||
masthead: mastheadEntry,
|
||||
workflow: workflowEntry,
|
||||
trackster: tracksterEntry,
|
||||
circster: circsterEntry,
|
||||
adminToolshed: adminToolshedEntry
|
||||
};
|
||||
|
||||
window.bundleEntries = bundleEntries;
|
||||
@@ -1,7 +0,0 @@
|
||||
import GalaxyLibrary from "galaxy.library";
|
||||
|
||||
export function App(options) {
|
||||
new GalaxyLibrary.GalaxyApp(options);
|
||||
}
|
||||
|
||||
window.libraryApp = App;
|
||||
@@ -1,16 +0,0 @@
|
||||
import Masthead from "layout/masthead";
|
||||
import user from "mvc/user/user-model";
|
||||
import Modal from "mvc/ui/ui-modal";
|
||||
|
||||
export default function masthead(options) {
|
||||
if (!Galaxy.user) {
|
||||
Galaxy.user = new user.User(options.user_json);
|
||||
}
|
||||
if (!Galaxy.masthead) {
|
||||
Galaxy.masthead = new Masthead.View(options);
|
||||
Galaxy.modal = new Modal.View();
|
||||
$("#masthead").replaceWith(Galaxy.masthead.render().$el);
|
||||
}
|
||||
}
|
||||
|
||||
window.masthead = masthead;
|
||||
@@ -1,13 +0,0 @@
|
||||
import Trackster from "viz/trackster";
|
||||
import Circster from "viz/circster";
|
||||
|
||||
export function tracksterApp(options) {
|
||||
new Trackster.GalaxyApp(options);
|
||||
}
|
||||
|
||||
export function circsterApp(options) {
|
||||
new Circster.GalaxyApp(options);
|
||||
}
|
||||
|
||||
window.tracksterApp = tracksterApp;
|
||||
window.circsterApp = circsterApp;
|
||||
@@ -1,7 +0,0 @@
|
||||
import WorkflowView from "mvc/workflow/workflow-view";
|
||||
|
||||
export default function workflowApp(options) {
|
||||
new WorkflowView(options);
|
||||
}
|
||||
|
||||
window.workflowApp = workflowApp;
|
||||
@@ -1,6 +1,5 @@
|
||||
/* This class maps the form dom to an api compatible javascript dictionary. */
|
||||
import Utils from "utils/utils";
|
||||
var Manager = Backbone.Model.extend({
|
||||
export var Manager = Backbone.Model.extend({
|
||||
initialize: function(app) {
|
||||
this.app = app;
|
||||
},
|
||||
@@ -33,7 +32,9 @@ var Manager = Backbone.Model.extend({
|
||||
function add(flat_id, input_id, input_value) {
|
||||
self.flat_dict[flat_id] = input_id;
|
||||
result_dict[flat_id] = input_value;
|
||||
self.app.element_list[input_id] && self.app.element_list[input_id].$el.attr("tour_id", flat_id);
|
||||
if (self.app.element_list[input_id]) {
|
||||
self.app.element_list[input_id].$el.attr("tour_id", flat_id);
|
||||
}
|
||||
}
|
||||
// converter between raw dictionary and job dictionary
|
||||
function convert(identifier, head) {
|
||||
@@ -42,7 +43,7 @@ var Manager = Backbone.Model.extend({
|
||||
if (node.input) {
|
||||
var input = node.input;
|
||||
var flat_id = identifier;
|
||||
if (identifier != "") {
|
||||
if (identifier !== "") {
|
||||
flat_id += "|";
|
||||
}
|
||||
flat_id += input.name;
|
||||
@@ -62,7 +63,7 @@ var Manager = Backbone.Model.extend({
|
||||
}
|
||||
}
|
||||
block_indices.sort((a, b) => a - b);
|
||||
var index = 0;
|
||||
index = 0;
|
||||
for (var i in block_indices) {
|
||||
convert(`${flat_id}_${index++}`, node[block_prefix + block_indices[i]]);
|
||||
}
|
||||
@@ -81,7 +82,7 @@ var Manager = Backbone.Model.extend({
|
||||
default:
|
||||
var field = self.app.field_list[input.id];
|
||||
if (field && field.value) {
|
||||
var value = field.value();
|
||||
value = field.value();
|
||||
if (input.ignore === undefined || input.ignore != value) {
|
||||
if (field.collapsed && input.collapsible_value) {
|
||||
value = input.collapsible_value;
|
||||
@@ -120,7 +121,9 @@ var Manager = Backbone.Model.extend({
|
||||
matchModel: function(model, callback) {
|
||||
var self = this;
|
||||
visitInputs(model.inputs, (input, name) => {
|
||||
self.flat_dict[name] && callback(input, self.flat_dict[name]);
|
||||
if (self.flat_dict[name]) {
|
||||
callback(input, self.flat_dict[name]);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
@@ -132,7 +135,9 @@ var Manager = Backbone.Model.extend({
|
||||
function search(id, head) {
|
||||
if (typeof head === "string") {
|
||||
var input_id = self.flat_dict[id];
|
||||
input_id && (result[input_id] = head);
|
||||
if (input_id) {
|
||||
result[input_id] = head;
|
||||
}
|
||||
} else {
|
||||
for (var i in head) {
|
||||
var new_id = i;
|
||||
@@ -174,7 +179,7 @@ var Manager = Backbone.Model.extend({
|
||||
* @param{dict} input - Definition of conditional input parameter
|
||||
* @param{dict} value - Current value
|
||||
*/
|
||||
var matchCase = (input, value) => {
|
||||
export var matchCase = (input, value) => {
|
||||
if (input.test_param.type == "boolean") {
|
||||
if (value == "true") {
|
||||
value = input.test_param.truevalue || "true";
|
||||
@@ -194,7 +199,7 @@ var matchCase = (input, value) => {
|
||||
* @param{dict} inputs - Nested dictionary of input elements
|
||||
* @param{dict} callback - Called with the mapped dictionary object and corresponding model node
|
||||
*/
|
||||
var visitInputs = (inputs, callback, prefix, context) => {
|
||||
export var visitInputs = (inputs, callback, prefix, context) => {
|
||||
context = $.extend(true, {}, context);
|
||||
_.each(inputs, input => {
|
||||
if (input && input.type && input.name) {
|
||||
|
||||
@@ -41,7 +41,9 @@ export default Backbone.Model.extend({
|
||||
field = input_def.options ? this._fieldSelect(input_def) : this._fieldText(input_def);
|
||||
Galaxy.emit.debug("form-parameters::_addRow()", `Auto matched field type (${input_def.type}).`);
|
||||
}
|
||||
input_def.value === undefined && (input_def.value = null);
|
||||
if (input_def.value === undefined) {
|
||||
input_def.value = null;
|
||||
}
|
||||
field.value(input_def.value);
|
||||
return field;
|
||||
},
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import Utils from "utils/utils";
|
||||
import Portlet from "mvc/ui/ui-portlet";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
var View = Backbone.View.extend({
|
||||
|
||||
export var View = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
this.list = {};
|
||||
this.options = Utils.merge(options, {
|
||||
@@ -17,7 +18,9 @@ var View = Backbone.View.extend({
|
||||
tooltip: `Add new ${this.options.title} block`,
|
||||
cls: "ui-button-icon ui-clear-float form-repeat-add",
|
||||
onclick: function() {
|
||||
options.onnew && options.onnew();
|
||||
if (options.onnew) {
|
||||
options.onnew();
|
||||
}
|
||||
}
|
||||
});
|
||||
this.setElement(
|
||||
@@ -43,7 +46,9 @@ var View = Backbone.View.extend({
|
||||
tooltip: "Delete this repeat block",
|
||||
cls: "ui-button-icon-plain form-repeat-delete",
|
||||
onclick: function() {
|
||||
options.ondel && options.ondel();
|
||||
if (options.ondel) {
|
||||
options.ondel();
|
||||
}
|
||||
}
|
||||
});
|
||||
var portlet = new Portlet.View({
|
||||
@@ -56,7 +61,9 @@ var View = Backbone.View.extend({
|
||||
portlet.$el.addClass("section-row").hide();
|
||||
this.list[options.id] = portlet;
|
||||
this.$list.append(portlet.$el.fadeIn("fast"));
|
||||
this.options.max > 0 && this.size() >= this.options.max && this.button_new.disable();
|
||||
if (this.options.max > 0 && this.size() >= this.options.max) {
|
||||
this.button_new.disable();
|
||||
}
|
||||
this._refresh();
|
||||
},
|
||||
|
||||
@@ -85,12 +92,13 @@ var View = Backbone.View.extend({
|
||||
_.each(this.list, portlet => {
|
||||
portlet.hideOperation("button_delete");
|
||||
});
|
||||
_.isEmpty(this.list) &&
|
||||
if (_.isEmpty(this.list)) {
|
||||
this.$el.append(
|
||||
$("<div/>")
|
||||
.addClass("ui-form-info")
|
||||
.html(this.options.empty_text)
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
/** Refresh view */
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
/**
|
||||
This is the main class of the form plugin. It is referenced as 'app' in lower level modules.
|
||||
*/
|
||||
import Utils from "utils/utils";
|
||||
import Portlet from "mvc/ui/ui-portlet";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
import FormSection from "mvc/form/form-section";
|
||||
import FormData from "mvc/form/form-data";
|
||||
export default Backbone.View.extend({
|
||||
|
||||
export var View = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
this.model = new Backbone.Model({
|
||||
initial_errors: false,
|
||||
@@ -95,7 +95,6 @@ export default Backbone.View.extend({
|
||||
if (options && options.errors) {
|
||||
var error_messages = this.data.matchResponse(options.errors);
|
||||
for (var input_id in this.element_list) {
|
||||
var input = this.element_list[input_id];
|
||||
if (error_messages[input_id]) {
|
||||
this.highlight(input_id, error_messages[input_id], true);
|
||||
}
|
||||
@@ -118,7 +117,9 @@ export default Backbone.View.extend({
|
||||
this.data = new FormData.Manager(this);
|
||||
this._renderForm();
|
||||
this.data.create();
|
||||
this.model.get("initial_errors") && this.errors(this.model.attributes);
|
||||
if (this.model.get("initial_errors")) {
|
||||
this.errors(this.model.attributes);
|
||||
}
|
||||
// add listener which triggers on checksum change, and reset the form input wrappers
|
||||
var current_check = this.data.checksum();
|
||||
this.on("change", input_id => {
|
||||
@@ -160,13 +161,18 @@ export default Backbone.View.extend({
|
||||
this.portlet.append(this.message.$el);
|
||||
this.portlet.append(this.section.$el);
|
||||
this.$el.empty();
|
||||
options.inputs && this.$el.append(this.portlet.$el);
|
||||
options.message &&
|
||||
if (options.inputs) {
|
||||
this.$el.append(this.portlet.$el);
|
||||
}
|
||||
if (options.message) {
|
||||
this.message.update({
|
||||
persistent: true,
|
||||
status: options.status,
|
||||
message: options.message
|
||||
});
|
||||
}
|
||||
Galaxy.emit.debug("form-view::initialize()", "Completed");
|
||||
}
|
||||
});
|
||||
|
||||
export default View;
|
||||
|
||||
@@ -23,6 +23,8 @@ var View = Backbone.View.extend({
|
||||
message: options.message,
|
||||
status: options.status || "warning",
|
||||
icon: options.icon,
|
||||
initial_errors: true,
|
||||
errors: options.errors,
|
||||
inputs: options.inputs,
|
||||
buttons: {
|
||||
submit: new Ui.Button({
|
||||
|
||||
@@ -1519,8 +1519,8 @@ var FolderToolbarView = Backbone.View.extend({
|
||||
"<br>",
|
||||
"<div>",
|
||||
'<label class="checkbox-inline tag-files">',
|
||||
"Tag datasets based on file names.",
|
||||
'<input class="tag-files" type="checkbox" value="tag_using_filenames" checked="checked">',
|
||||
"Tag datasets based on file names",
|
||||
'<input class="tag-files" type="checkbox" value="tag_using_filenames">',
|
||||
"</label>",
|
||||
"</div>",
|
||||
"</div>"
|
||||
@@ -1561,8 +1561,8 @@ var FolderToolbarView = Backbone.View.extend({
|
||||
"</div>",
|
||||
"<div>",
|
||||
'<label class="checkbox-inline tag-files">',
|
||||
"Tag datasets based on file names.",
|
||||
'<input class="tag-files" type="checkbox" value="tag_using_filenames" checked="checked">',
|
||||
"Tag datasets based on file names",
|
||||
'<input class="tag-files" type="checkbox" value="tag_using_filenames">',
|
||||
"</label>",
|
||||
"</div>",
|
||||
"</div>"
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
/**
|
||||
* This class contains backbone wrappers for basic ui elements such as Images, Labels, Buttons, Input fields etc.
|
||||
*/
|
||||
import Utils from "utils/utils";
|
||||
import Select from "mvc/ui/ui-select-default";
|
||||
import Slider from "mvc/ui/ui-slider";
|
||||
import Options from "mvc/ui/ui-options";
|
||||
import Drilldown from "mvc/ui/ui-drilldown";
|
||||
import Buttons from "mvc/ui/ui-buttons";
|
||||
import Modal from "mvc/ui/ui-modal";
|
||||
|
||||
/** Label wrapper */
|
||||
var Label = Backbone.View.extend({
|
||||
export var Label = Backbone.View.extend({
|
||||
tagName: "label",
|
||||
initialize: function(options) {
|
||||
this.model = (options && options.model) || new Backbone.Model(options);
|
||||
@@ -35,7 +35,7 @@ var Label = Backbone.View.extend({
|
||||
});
|
||||
|
||||
/** Displays messages used e.g. in the tool form */
|
||||
var Message = Backbone.View.extend({
|
||||
export var Message = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
this.model =
|
||||
(options && options.model) ||
|
||||
@@ -85,14 +85,14 @@ var Message = Backbone.View.extend({
|
||||
}
|
||||
});
|
||||
|
||||
var UnescapedMessage = Message.extend({
|
||||
export var UnescapedMessage = Message.extend({
|
||||
messageForDisplay: function() {
|
||||
return this.model.get("message");
|
||||
}
|
||||
});
|
||||
|
||||
/** Renders an input element used e.g. in the tool form */
|
||||
var Input = Backbone.View.extend({
|
||||
export var Input = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
this.model =
|
||||
(options && options.model) ||
|
||||
@@ -158,7 +158,7 @@ var Input = Backbone.View.extend({
|
||||
});
|
||||
|
||||
/** Creates a hidden element input field used e.g. in the tool form */
|
||||
var Hidden = Backbone.View.extend({
|
||||
export var Hidden = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
this.model = (options && options.model) || new Backbone.Model(options);
|
||||
this.setElement(
|
||||
@@ -182,7 +182,7 @@ var Hidden = Backbone.View.extend({
|
||||
});
|
||||
|
||||
/** Creates a upload element input field */
|
||||
var Upload = Backbone.View.extend({
|
||||
export var Upload = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
this.model = (options && options.model) || new Backbone.Model(options);
|
||||
@@ -232,6 +232,21 @@ var Upload = Backbone.View.extend({
|
||||
}
|
||||
});
|
||||
|
||||
/* Make more Ui stuff directly available at this namespace (for backwards
|
||||
* compatibility). We should eliminate this practice, though, and just require
|
||||
* what we need where we need it, allowing for better package optimization.
|
||||
*/
|
||||
|
||||
export let Button = Buttons.ButtonDefault;
|
||||
export let ButtonIcon = Buttons.ButtonIcon;
|
||||
export let ButtonCheck = Buttons.ButtonCheck;
|
||||
export let ButtonMenu = Buttons.ButtonMenu;
|
||||
export let ButtonLink = Buttons.ButtonLink;
|
||||
export let Checkbox = Options.Checkbox;
|
||||
export let RadioButton = Options.RadioButton;
|
||||
export let Radio = Options.Radio;
|
||||
export { Select, Slider, Drilldown };
|
||||
|
||||
export default {
|
||||
Button: Buttons.ButtonDefault,
|
||||
ButtonIcon: Buttons.ButtonIcon,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
var View = Backbone.View.extend({
|
||||
export var View = Backbone.View.extend({
|
||||
className: "ui-modal",
|
||||
|
||||
// defaults
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import Utils from "utils/utils";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
var View = Backbone.View.extend({
|
||||
|
||||
export var View = Backbone.View.extend({
|
||||
visible: false,
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import Utils from "utils/utils";
|
||||
|
||||
var View = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
|
||||
@@ -1,10 +1,8 @@
|
||||
/**
|
||||
* Renders tabs e.g. used in the charts editor, behaves similar to repeat and section rendering
|
||||
*/
|
||||
import Utils from "utils/utils";
|
||||
var View = Backbone.View.extend({
|
||||
export var View = Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
this.collection = new Backbone.Collection();
|
||||
this.model =
|
||||
(options && options.model) ||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
/** This class renders the selection grid. */
|
||||
import Utils from "utils/utils";
|
||||
import Ui from "mvc/ui/ui-misc";
|
||||
import Tabs from "mvc/ui/ui-tabs";
|
||||
var View = Backbone.View.extend({
|
||||
|
||||
export var View = Backbone.View.extend({
|
||||
events: {
|
||||
"click .ui-thumbnails-item": "_onclick",
|
||||
"dblclick .ui-thumbnails-item": "_ondblclick"
|
||||
@@ -26,8 +26,6 @@ var View = Backbone.View.extend({
|
||||
},
|
||||
|
||||
_renderDefault: function() {
|
||||
var self = this;
|
||||
var index = [];
|
||||
var title_length = 20;
|
||||
var $el = $("<div/>").addClass("ui-thumbnails-grid");
|
||||
this.collection.each(model => {
|
||||
@@ -35,7 +33,7 @@ var View = Backbone.View.extend({
|
||||
var title = model.get("title");
|
||||
$el.append(
|
||||
$(
|
||||
self._templateThumbnailItem({
|
||||
this._templateThumbnailItem({
|
||||
id: model.id,
|
||||
title: title.length < title_length ? title : `${title.substr(0, title_length)}...`,
|
||||
title_icon: model.get("title_icon"),
|
||||
@@ -51,7 +49,7 @@ var View = Backbone.View.extend({
|
||||
if ($el.children().length > 0) {
|
||||
this.tabs.add({
|
||||
id: Utils.uid(),
|
||||
title: self.model.get("title_default"),
|
||||
title: this.model.get("title_default"),
|
||||
$el: $el
|
||||
});
|
||||
}
|
||||
@@ -82,7 +80,9 @@ var View = Backbone.View.extend({
|
||||
this.$(`[value="${new_value}"]`).addClass("ui-thumbnail-current");
|
||||
var after = this.$(".ui-thumbnail-current").attr("value");
|
||||
var change_handler = this.model.get("onchange");
|
||||
after != before && change_handler && change_handler(after);
|
||||
if (after != before && change_handler) {
|
||||
change_handler(after);
|
||||
}
|
||||
}
|
||||
return this.$(".ui-thumbnail-current").attr("value");
|
||||
},
|
||||
@@ -97,8 +97,10 @@ var View = Backbone.View.extend({
|
||||
},
|
||||
|
||||
/** Add double click handler */
|
||||
_ondblclick: function(e) {
|
||||
this.model.get("ondblclick") && this.model.get("ondblclick")(this.value());
|
||||
_ondblclick: function() {
|
||||
if (this.model.get("ondblclick")) {
|
||||
this.model.get("ondblclick")(this.value());
|
||||
}
|
||||
},
|
||||
|
||||
/* Thumbnail template with image */
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import * as Backbone from "libs/backbone";
|
||||
//==============================================================================
|
||||
/** @class Model for a saved Galaxy visualization.
|
||||
*
|
||||
* @augments Backbone.Model
|
||||
* @constructs
|
||||
*/
|
||||
var Visualization = Backbone.Model.extend(
|
||||
export var Visualization = Backbone.Model.extend(
|
||||
/** @lends Visualization.prototype */ {
|
||||
///** logger used to record this.log messages, commonly set to console */
|
||||
//// comment this out to suppress log output
|
||||
@@ -76,7 +77,7 @@ var Visualization = Backbone.Model.extend(
|
||||
*
|
||||
* @constructs
|
||||
*/
|
||||
var VisualizationCollection = Backbone.Collection.extend(
|
||||
export var VisualizationCollection = Backbone.Collection.extend(
|
||||
/** @lends VisualizationCollection.prototype */ {
|
||||
model: Visualization,
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ function CanvasManager(app, canvas_viewport, overview) {
|
||||
this.ov = overview.find("#overview-viewport");
|
||||
// Make overview box draggable
|
||||
this.init_drag();
|
||||
// Initialize Copy & Paste events
|
||||
this.init_copy_paste();
|
||||
}
|
||||
$.extend(CanvasManager.prototype, {
|
||||
init_drag: function() {
|
||||
@@ -33,6 +35,9 @@ $.extend(CanvasManager.prototype, {
|
||||
var x_adjust;
|
||||
var y_adjust;
|
||||
this.cv
|
||||
.bind("click", function() {
|
||||
document.activeElement.blur();
|
||||
})
|
||||
.bind("dragstart", function() {
|
||||
var o = $(this).offset();
|
||||
var p = self.cc.position();
|
||||
@@ -96,6 +101,42 @@ $.extend(CanvasManager.prototype, {
|
||||
only be done by dragging the borders */
|
||||
$("#overview-border div").bind("drag", () => {});
|
||||
},
|
||||
init_copy_paste: function() {
|
||||
document.addEventListener("copy", e => {
|
||||
// If it appears that the user is trying to copy/paste text, we
|
||||
// pass that through.
|
||||
if (window.getSelection().toString() === "") {
|
||||
if (this.app.workflow.active_node) {
|
||||
e.clipboardData.setData(
|
||||
"application/json",
|
||||
JSON.stringify({
|
||||
nodeId: this.app.workflow.active_node.id
|
||||
})
|
||||
);
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
|
||||
document.addEventListener("paste", e => {
|
||||
// If it appears that the user is trying to paste into a text box,
|
||||
// pass that through and skip the workflow copy/paste logic.
|
||||
if (
|
||||
document.activeElement &&
|
||||
document.activeElement.type !== "textarea" &&
|
||||
document.activeElement.type !== "text"
|
||||
) {
|
||||
var nodeId;
|
||||
try {
|
||||
nodeId = JSON.parse(e.clipboardData.getData("application/json")).nodeId;
|
||||
} catch (error) {}
|
||||
if (nodeId && this.app.workflow.nodes.hasOwnProperty(nodeId)) {
|
||||
this.app.workflow.nodes[nodeId].clone();
|
||||
}
|
||||
e.preventDefault();
|
||||
}
|
||||
});
|
||||
},
|
||||
update_viewport_overlay: function() {
|
||||
var cc = this.cc;
|
||||
var cv = this.cv;
|
||||
@@ -229,27 +270,28 @@ $.extend(ScrollPanel.prototype, {
|
||||
close_dist = 5;
|
||||
|
||||
var nudge = 23;
|
||||
var t = 0;
|
||||
if (x - close_dist < min_x) {
|
||||
if (panel_pos.left < p_max_x) {
|
||||
var t = Math.min(nudge, p_max_x - panel_pos.left);
|
||||
t = Math.min(nudge, p_max_x - panel_pos.left);
|
||||
panel.css("left", panel_pos.left + t);
|
||||
moved = true;
|
||||
}
|
||||
} else if (x + close_dist > max_x) {
|
||||
if (panel_pos.left > p_min_x) {
|
||||
var t = Math.min(nudge, panel_pos.left - p_min_x);
|
||||
t = Math.min(nudge, panel_pos.left - p_min_x);
|
||||
panel.css("left", panel_pos.left - t);
|
||||
moved = true;
|
||||
}
|
||||
} else if (y - close_dist < min_y) {
|
||||
if (panel_pos.top < p_max_y) {
|
||||
var t = Math.min(nudge, p_max_y - panel_pos.top);
|
||||
t = Math.min(nudge, p_max_y - panel_pos.top);
|
||||
panel.css("top", panel_pos.top + t);
|
||||
moved = true;
|
||||
}
|
||||
} else if (y + close_dist > max_y) {
|
||||
if (panel_pos.top > p_min_y) {
|
||||
var t = Math.min(nudge, panel_pos.top - p_min_x);
|
||||
t = Math.min(nudge, panel_pos.top - p_min_x);
|
||||
panel.css("top", `${panel_pos.top - t}px`);
|
||||
moved = true;
|
||||
}
|
||||
@@ -257,13 +299,12 @@ $.extend(ScrollPanel.prototype, {
|
||||
if (moved) {
|
||||
// Keep moving even if mouse doesn't move
|
||||
onmove();
|
||||
var panel = this;
|
||||
this.timeout = setTimeout(() => {
|
||||
panel.test(e, onmove);
|
||||
this.test(e, onmove);
|
||||
}, 50);
|
||||
}
|
||||
},
|
||||
stop: function(e, ui) {
|
||||
stop: function() {
|
||||
clearTimeout(this.timeout);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -300,6 +300,7 @@ $.extend(Workflow.prototype, {
|
||||
this.active_node.make_inactive();
|
||||
this.active_node = null;
|
||||
}
|
||||
document.activeElement.blur();
|
||||
this.app.showAttributes();
|
||||
},
|
||||
activate_node: function(node) {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import Utils from "utils/utils";
|
||||
import NodeView from "mvc/workflow/workflow-view-node";
|
||||
var Node = Backbone.Model.extend({
|
||||
initialize: function(app, attr) {
|
||||
@@ -129,6 +130,31 @@ var Node = Backbone.Model.extend({
|
||||
t.redraw();
|
||||
});
|
||||
},
|
||||
clone: function() {
|
||||
var copiedData = {
|
||||
name: this.name,
|
||||
label: this.label,
|
||||
annotation: this.annotation,
|
||||
post_job_actions: this.post_job_actions
|
||||
};
|
||||
var node = this.app.workflow.create_node(this.type, this.name, this.content_id);
|
||||
|
||||
Utils.request({
|
||||
type: "POST",
|
||||
url: `${Galaxy.root}api/workflows/build_module`,
|
||||
data: {
|
||||
type: this.type,
|
||||
tool_id: this.content_id,
|
||||
inputs: this.tool_state
|
||||
},
|
||||
success: data => {
|
||||
var newData = Object.assign({}, data, copiedData);
|
||||
node.init_field_data(newData);
|
||||
node.update_field_data(newData);
|
||||
this.app.workflow.activate_node(node);
|
||||
}
|
||||
});
|
||||
},
|
||||
destroy: function() {
|
||||
$.each(this.input_terminals, (k, t) => {
|
||||
t.destroy();
|
||||
|
||||
@@ -763,6 +763,13 @@ export default Backbone.View.extend({
|
||||
// Fix width to computed width
|
||||
// Now add floats
|
||||
var buttons = $("<div class='buttons' style='float: right;'></div>");
|
||||
buttons.append(
|
||||
$("<div/>")
|
||||
.addClass("fa-icon-button fa fa-files-o")
|
||||
.click(e => {
|
||||
node.clone();
|
||||
})
|
||||
);
|
||||
buttons.append(
|
||||
$("<div/>")
|
||||
.addClass("fa-icon-button fa fa-times")
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
*/
|
||||
import _l from "utils/localization";
|
||||
/** Builds a basic iframe */
|
||||
function iframe(src) {
|
||||
export function iframe(src) {
|
||||
return `<iframe src="${src}" frameborder="0" style="width: 100%; height: 100%;"/>`;
|
||||
}
|
||||
|
||||
/** Traverse through json */
|
||||
function deepeach(dict, callback) {
|
||||
export function deepeach(dict, callback) {
|
||||
for (var i in dict) {
|
||||
var d = dict[i];
|
||||
if (_.isObject(d)) {
|
||||
@@ -21,7 +21,7 @@ function deepeach(dict, callback) {
|
||||
}
|
||||
|
||||
/** Identifies urls and replaces them with anchors */
|
||||
function linkify(inputText) {
|
||||
export function linkify(inputText) {
|
||||
var replacedText;
|
||||
var replacePattern1;
|
||||
var replacePattern2;
|
||||
@@ -43,7 +43,7 @@ function linkify(inputText) {
|
||||
}
|
||||
|
||||
/** Clone */
|
||||
function clone(obj) {
|
||||
export function clone(obj) {
|
||||
return JSON.parse(JSON.stringify(obj) || null);
|
||||
}
|
||||
|
||||
@@ -51,7 +51,7 @@ function clone(obj) {
|
||||
* Check if a string is a json string
|
||||
* @param{String} text - Content to be validated
|
||||
*/
|
||||
function isJSON(text) {
|
||||
export function isJSON(text) {
|
||||
return /^[\],:{}\s]*$/.test(
|
||||
text
|
||||
.replace(/\\["\\\/bfnrtu]/g, "@")
|
||||
@@ -64,7 +64,7 @@ function isJSON(text) {
|
||||
* Sanitize/escape a string
|
||||
* @param{String} content - Content to be sanitized
|
||||
*/
|
||||
function sanitize(content) {
|
||||
export function sanitize(content) {
|
||||
return $("<div/>")
|
||||
.text(content)
|
||||
.html();
|
||||
@@ -75,7 +75,7 @@ function sanitize(content) {
|
||||
* usually used for selectable options
|
||||
* @param{String} value - Value or list to be validated
|
||||
*/
|
||||
function isEmpty(value) {
|
||||
export function isEmpty(value) {
|
||||
if (!(value instanceof Array)) {
|
||||
value = [value];
|
||||
}
|
||||
@@ -94,9 +94,9 @@ function isEmpty(value) {
|
||||
* Convert list to pretty string
|
||||
* @param{String} lst - List of strings to be converted in human readable list sentence
|
||||
*/
|
||||
function textify(lst) {
|
||||
export function textify(lst) {
|
||||
if ($.isArray(lst)) {
|
||||
var lst = lst.toString().replace(/,/g, ", ");
|
||||
lst = lst.toString().replace(/,/g, ", ");
|
||||
var pos = lst.lastIndexOf(", ");
|
||||
if (pos != -1) {
|
||||
lst = `${lst.substr(0, pos)} or ${lst.substr(pos + 2)}`;
|
||||
@@ -113,7 +113,7 @@ function textify(lst) {
|
||||
* @param{Function} error - Callback on error
|
||||
* @param{Boolean} cache - Use cached data if available
|
||||
*/
|
||||
function get(options) {
|
||||
export function get(options) {
|
||||
top.__utils__get__ = top.__utils__get__ || {};
|
||||
var cache_key = JSON.stringify(options);
|
||||
if (options.cache && top.__utils__get__[cache_key]) {
|
||||
@@ -142,7 +142,7 @@ function get(options) {
|
||||
* @param{Function} success - Callback on success
|
||||
* @param{Function} error - Callback on error
|
||||
*/
|
||||
function request(options) {
|
||||
export function request(options) {
|
||||
// prepare ajax
|
||||
var ajaxConfig = {
|
||||
contentType: "application/json",
|
||||
@@ -195,7 +195,7 @@ function request(options) {
|
||||
* @param{String} classname - CSS class
|
||||
* @param{String} name - CSS property
|
||||
*/
|
||||
function cssGetAttribute(classname, name) {
|
||||
export function cssGetAttribute(classname, name) {
|
||||
var el = $(`<div class="${classname}"></div>`);
|
||||
el.appendTo(":eq(0)");
|
||||
var value = el.css(name);
|
||||
@@ -207,7 +207,7 @@ function cssGetAttribute(classname, name) {
|
||||
* Load a CSS file
|
||||
* @param{String} url - Url of CSS file
|
||||
*/
|
||||
function cssLoadFile(url) {
|
||||
export function cssLoadFile(url) {
|
||||
if (!$(`link[href^="${url}"]`).length) {
|
||||
$(`<link href="${Galaxy.root}${url}" rel="stylesheet">`).appendTo("head");
|
||||
}
|
||||
@@ -218,7 +218,7 @@ function cssLoadFile(url) {
|
||||
* @param{Object} options - Target dictionary
|
||||
* @param{Object} optionsDefault - Source dictionary
|
||||
*/
|
||||
function merge(options, optionsDefault) {
|
||||
export function merge(options, optionsDefault) {
|
||||
if (options) {
|
||||
return _.defaults(options, optionsDefault);
|
||||
} else {
|
||||
@@ -231,7 +231,7 @@ function merge(options, optionsDefault) {
|
||||
* @param{Object} number a floaing point number
|
||||
* @param{Object} numPlaces number of decimal places
|
||||
*/
|
||||
function roundToDecimalPlaces(number, numPlaces) {
|
||||
export function roundToDecimalPlaces(number, numPlaces) {
|
||||
var placesMultiplier = 1;
|
||||
for (var i = 0; i < numPlaces; i++) {
|
||||
placesMultiplier *= 10;
|
||||
@@ -250,7 +250,7 @@ var tb = gb * kb;
|
||||
* @param{Integer} size - Size in bytes
|
||||
* @param{Boolean} normal_font - Switches font between normal and bold
|
||||
*/
|
||||
function bytesToString(size, normal_font, numberPlaces) {
|
||||
export function bytesToString(size, normal_font, numberPlaces) {
|
||||
numberPlaces = numberPlaces !== undefined ? numberPlaces : 1;
|
||||
// identify unit
|
||||
var unit = "";
|
||||
@@ -281,13 +281,13 @@ function bytesToString(size, normal_font, numberPlaces) {
|
||||
}
|
||||
|
||||
/** Create a unique id */
|
||||
function uid() {
|
||||
export function uid() {
|
||||
top.__utils__uid__ = top.__utils__uid__ || 0;
|
||||
return `uid-${top.__utils__uid__++}`;
|
||||
}
|
||||
|
||||
/** Create a time stamp */
|
||||
function time() {
|
||||
export function time() {
|
||||
var d = new Date();
|
||||
var hours = (d.getHours() < 10 ? "0" : "") + d.getHours();
|
||||
var minutes = (d.getMinutes() < 10 ? "0" : "") + d.getMinutes();
|
||||
@@ -295,7 +295,7 @@ function time() {
|
||||
}
|
||||
|
||||
/** Append script and style tags to Galaxy main application */
|
||||
function appendScriptStyle(data) {
|
||||
export function appendScriptStyle(data) {
|
||||
// create a script tag inside head tag
|
||||
if (data.script && data.script !== "") {
|
||||
$("<script/>", { type: "text/javascript" })
|
||||
@@ -311,7 +311,7 @@ function appendScriptStyle(data) {
|
||||
}
|
||||
|
||||
/** Get querystrings from url */
|
||||
function getQueryString(key) {
|
||||
export function getQueryString(key) {
|
||||
return decodeURIComponent(
|
||||
window.location.search.replace(
|
||||
new RegExp(`^(?:.*[&\\?]${encodeURIComponent(key).replace(/[\.\+\*]/g, "\\$&")}(?:\\=([^&]*))?)?.*$`, "i"),
|
||||
@@ -320,7 +320,7 @@ function getQueryString(key) {
|
||||
);
|
||||
}
|
||||
|
||||
function setWindowTitle(title) {
|
||||
export function setWindowTitle(title) {
|
||||
if (title) {
|
||||
window.document.title = `Galaxy ${window.Galaxy.config.brand ? ` | ${window.Galaxy.config.brand}` : ""} | ${_l(
|
||||
title
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
"axios": "^0.17.0",
|
||||
"backbone": "1.3",
|
||||
"bibtex-parse-js": "^0.0.24",
|
||||
"bootstrap": "^3.3.7",
|
||||
"d3": "3",
|
||||
"jquery": "2",
|
||||
"jquery-migrate": "~1.4",
|
||||
"jquery-mousewheel": "^3.1.13",
|
||||
"jquery-ui-bundle": "^1.12.1",
|
||||
"jquery.complexify": "^0.5.2",
|
||||
"jquery.cookie": "^1.4.1",
|
||||
"latex-parser": "^0.6.2",
|
||||
@@ -47,6 +49,7 @@
|
||||
"build-toolshed": "grunt --app=toolshed",
|
||||
"jshint": "jshint --exclude='galaxy/scripts/libs/**' galaxy/scripts/**/*.js",
|
||||
"build-charts": "webpack -p --config ../config/plugins/visualizations/charts/webpack.config.js",
|
||||
"build-scatterplot": "NODE_PATH=./node_modules webpack -p --config ../config/plugins/visualizations/scatterplot/webpack.config.js",
|
||||
"prettier": "prettier --write --tab-width 4 --print-width 120 \"galaxy/scripts/{,!(libs)/**/}/*.js\""
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -43,11 +43,7 @@ let buildconfig = {
|
||||
login: "./galaxy/scripts/apps/login.js",
|
||||
analysis: "./galaxy/scripts/apps/analysis.js",
|
||||
admin: "./galaxy/scripts/apps/admin.js",
|
||||
workflow: "./galaxy/scripts/apps/workflow.js",
|
||||
masthead: "./galaxy/scripts/apps/masthead.js",
|
||||
viz: "./galaxy/scripts/apps/viz.js",
|
||||
library: "./galaxy/scripts/apps/library.js",
|
||||
adminToolshed: "./galaxy/scripts/apps/admin-toolshed.js"
|
||||
extended: "./galaxy/scripts/apps/extended.js"
|
||||
},
|
||||
output: {
|
||||
path: path.join(__dirname, "../", "static/scripts/bundled"),
|
||||
|
||||
+25
-69
@@ -1142,6 +1142,10 @@ boom@5.x.x:
|
||||
dependencies:
|
||||
hoek "4.x.x"
|
||||
|
||||
bootstrap@^3.3.7:
|
||||
version "3.3.7"
|
||||
resolved "https://registry.yarnpkg.com/bootstrap/-/bootstrap-3.3.7.tgz#5a389394549f23330875a3b150656574f8a9eb71"
|
||||
|
||||
bower@~1.8.0:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/bower/-/bower-1.8.2.tgz#adf53529c8d4af02ef24fb8d5341c1419d33e2f7"
|
||||
@@ -2245,11 +2249,7 @@ ee-first@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
|
||||
|
||||
electron-to-chromium@^1.2.7:
|
||||
version "1.3.27"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.27.tgz#78ecb8a399066187bb374eede35d9c70565a803d"
|
||||
|
||||
electron-to-chromium@^1.3.24:
|
||||
electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.24:
|
||||
version "1.3.25"
|
||||
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.25.tgz#453b21009836d0997d86035601ff6cae4791c460"
|
||||
|
||||
@@ -2478,9 +2478,9 @@ espower-location-detector@^1.0.0:
|
||||
source-map "^0.5.0"
|
||||
xtend "^4.0.0"
|
||||
|
||||
esprima@^1.0.3:
|
||||
version "1.2.5"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.2.5.tgz#0993502feaf668138325756f30f9a51feeec11e9"
|
||||
esprima@^1.0.3, "esprima@~ 1.0.2", esprima@~1.0.2:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad"
|
||||
|
||||
esprima@^2.6.0:
|
||||
version "2.7.3"
|
||||
@@ -2490,10 +2490,6 @@ esprima@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
|
||||
|
||||
"esprima@~ 1.0.2", esprima@~1.0.2:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad"
|
||||
|
||||
esprima@~1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.1.1.tgz#5b6f1547f4d102e670e140c509be6771d6aeb549"
|
||||
@@ -4004,6 +4000,10 @@ jquery-mousewheel@^3.1.13:
|
||||
version "3.1.13"
|
||||
resolved "https://registry.yarnpkg.com/jquery-mousewheel/-/jquery-mousewheel-3.1.13.tgz#06f0335f16e353a695e7206bf50503cb523a6ee5"
|
||||
|
||||
jquery-ui-bundle@^1.12.1:
|
||||
version "1.12.1"
|
||||
resolved "https://registry.yarnpkg.com/jquery-ui-bundle/-/jquery-ui-bundle-1.12.1.tgz#d6be2e4c377494e2378b1cae2920a91d1182d8c4"
|
||||
|
||||
jquery.complexify@^0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/jquery.complexify/-/jquery.complexify-0.5.2.tgz#8c8834ca08cee9476f1d975128d49526adcc4ae9"
|
||||
@@ -4787,7 +4787,7 @@ minimatch@~0.2.11, minimatch@~0.2.12:
|
||||
lru-cache "2"
|
||||
sigmund "~1.0.0"
|
||||
|
||||
minimist@0.0.8:
|
||||
minimist@0.0.8, minimist@~0.0.1:
|
||||
version "0.0.8"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
|
||||
|
||||
@@ -4795,10 +4795,6 @@ minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
|
||||
|
||||
minimist@~0.0.1:
|
||||
version "0.0.10"
|
||||
resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.10.tgz#de3f98543dbf96082be48ad1a0c7cda836301dcf"
|
||||
|
||||
mkdirp@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.0.tgz#1d73076a6df986cd9344e15e71fcc05a4c9abf12"
|
||||
@@ -5214,7 +5210,7 @@ os-locale@^2.0.0:
|
||||
lcid "^1.0.0"
|
||||
mem "^1.1.0"
|
||||
|
||||
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2:
|
||||
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1, os-tmpdir@~1.0.1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
|
||||
|
||||
@@ -5898,11 +5894,7 @@ preserve@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b"
|
||||
|
||||
prettier@^1.7.0:
|
||||
version "1.8.1"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.1.tgz#91064d778c08c85ac1cbe6b23195c34310d039f9"
|
||||
|
||||
prettier@^1.7.4:
|
||||
prettier@^1.7.0, prettier@^1.7.4:
|
||||
version "1.8.2"
|
||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.8.2.tgz#bff83e7fd573933c607875e5ba3abbdffb96aeb8"
|
||||
|
||||
@@ -6067,16 +6059,7 @@ raw-body@2.3.2:
|
||||
iconv-lite "0.4.19"
|
||||
unpipe "1.0.0"
|
||||
|
||||
rc@^1.0.1, rc@^1.1.6:
|
||||
version "1.2.2"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.2.tgz#d8ce9cb57e8d64d9c7badd9876c7c34cbe3c7077"
|
||||
dependencies:
|
||||
deep-extend "~0.4.0"
|
||||
ini "~1.3.0"
|
||||
minimist "^1.2.0"
|
||||
strip-json-comments "~2.0.1"
|
||||
|
||||
rc@^1.1.7:
|
||||
rc@^1.0.1, rc@^1.1.6, rc@^1.1.7:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95"
|
||||
dependencies:
|
||||
@@ -6137,7 +6120,7 @@ read-pkg@^2.0.0:
|
||||
normalize-package-data "^2.3.2"
|
||||
path-type "^2.0.0"
|
||||
|
||||
readable-stream@1.1:
|
||||
readable-stream@1.1, readable-stream@~1.1.9:
|
||||
version "1.1.13"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.13.tgz#f6eef764f514c89e2b9e23146a75ba106756d23e"
|
||||
dependencies:
|
||||
@@ -6167,15 +6150,6 @@ readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable
|
||||
string_decoder "~1.0.3"
|
||||
util-deprecate "~1.0.1"
|
||||
|
||||
readable-stream@~1.1.9:
|
||||
version "1.1.14"
|
||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
||||
dependencies:
|
||||
core-util-is "~1.0.0"
|
||||
inherits "~2.0.1"
|
||||
isarray "0.0.1"
|
||||
string_decoder "~0.10.x"
|
||||
|
||||
readdirp@^2.0.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78"
|
||||
@@ -6410,13 +6384,7 @@ resolve@1.3.2:
|
||||
dependencies:
|
||||
path-parse "^1.0.5"
|
||||
|
||||
resolve@^1.1.6, resolve@^1.1.7:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.4.0.tgz#a75be01c53da25d934a98ebd0e4c4a7312f92a86"
|
||||
dependencies:
|
||||
path-parse "^1.0.5"
|
||||
|
||||
resolve@^1.4.0:
|
||||
resolve@^1.1.6, resolve@^1.1.7, resolve@^1.4.0:
|
||||
version "1.5.0"
|
||||
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.5.0.tgz#1f09acce796c9a762579f31b2c1cc4c3cddf9f36"
|
||||
dependencies:
|
||||
@@ -6714,7 +6682,11 @@ source-map@0.1.34:
|
||||
dependencies:
|
||||
amdefine ">=0.0.4"
|
||||
|
||||
source-map@0.X, "source-map@>= 0.1.2", source-map@^0.6.1:
|
||||
source-map@0.X, source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
|
||||
"source-map@>= 0.1.2", source-map@^0.6.1:
|
||||
version "0.6.1"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
|
||||
|
||||
@@ -6724,10 +6696,6 @@ source-map@^0.1.38, source-map@^0.1.40, source-map@~0.1.33, source-map@~0.1.7:
|
||||
dependencies:
|
||||
amdefine ">=0.0.4"
|
||||
|
||||
source-map@^0.5.0, source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3:
|
||||
version "0.5.7"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
|
||||
|
||||
source-map@~0.4.1:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
|
||||
@@ -6980,18 +6948,12 @@ supports-color@^3.1.0, supports-color@^3.2.3:
|
||||
dependencies:
|
||||
has-flag "^1.0.0"
|
||||
|
||||
supports-color@^4.0.0, supports-color@^4.4.0:
|
||||
supports-color@^4.0.0, supports-color@^4.2.1, supports-color@^4.4.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b"
|
||||
dependencies:
|
||||
has-flag "^2.0.0"
|
||||
|
||||
supports-color@^4.2.1:
|
||||
version "4.4.0"
|
||||
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.4.0.tgz#883f7ddabc165142b2a61427f3352ded195d1a3e"
|
||||
dependencies:
|
||||
has-flag "^2.0.0"
|
||||
|
||||
svgo@^0.7.0:
|
||||
version "0.7.2"
|
||||
resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5"
|
||||
@@ -7140,18 +7102,12 @@ tiny-lr-fork@0.0.5:
|
||||
noptify "~0.0.3"
|
||||
qs "~0.5.2"
|
||||
|
||||
tmp@0.0.31:
|
||||
tmp@0.0.31, tmp@0.0.x:
|
||||
version "0.0.31"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.31.tgz#8f38ab9438e17315e5dbd8b3657e8bfb277ae4a7"
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.1"
|
||||
|
||||
tmp@0.0.x:
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
|
||||
dependencies:
|
||||
os-tmpdir "~1.0.2"
|
||||
|
||||
to-array@0.1.4:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
|
||||
|
||||
@@ -705,7 +705,7 @@
|
||||
<sniffer type="galaxy.datatypes.binary:Fast5ArchiveBz2" />
|
||||
<sniffer type="galaxy.datatypes.binary:Fast5Archive" />
|
||||
<sniffer type="galaxy.datatypes.binary:PostgresqlArchive"/>
|
||||
<sniffer type="galaxy.datatypes.annotation:ICM" />
|
||||
<sniffer type="galaxy.datatypes.binary:ICM" />
|
||||
<sniffer type="galaxy.datatypes.annotation:Augustus" />
|
||||
<sniffer type="galaxy.datatypes.triples:Rdf"/>
|
||||
<sniffer type="galaxy.datatypes.blast:BlastXml"/>
|
||||
|
||||
@@ -1,68 +1,93 @@
|
||||
/**
|
||||
* Main application class.
|
||||
*/
|
||||
define( [ 'mvc/ui/ui-modal', 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc', 'utils/utils', 'plugin/components/model', 'utils/deferred', 'plugin/views/viewer', 'plugin/views/editor' ],
|
||||
function( Modal, Portlet, Ui, Utils, Chart, Deferred, Viewer, Editor ) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function( options ) {
|
||||
var self = this;
|
||||
require( [ 'repository/build/registry' ], function( Registry ) {
|
||||
console.debug( 'app::initialize() - Loaded Registry:' );
|
||||
console.debug( Registry );
|
||||
Utils.get({
|
||||
url : Galaxy.root + 'api/datasets/' + options.dataset_id,
|
||||
success : function( dataset ) {
|
||||
self.dataset = dataset;
|
||||
self.types = {};
|
||||
_.each( Registry, function( type, type_id ) {
|
||||
if ( !type.datatypes || type.datatypes.indexOf( dataset.file_ext ) != -1 ) {
|
||||
self.types[ type_id ] = type;
|
||||
define(
|
||||
[
|
||||
"mvc/ui/ui-modal",
|
||||
"mvc/ui/ui-portlet",
|
||||
"mvc/ui/ui-misc",
|
||||
"utils/utils",
|
||||
"plugin/components/model",
|
||||
"utils/deferred",
|
||||
"plugin/views/viewer",
|
||||
"plugin/views/editor"
|
||||
],
|
||||
function(Modal, Portlet, Ui, Utils, Chart, Deferred, Viewer, Editor) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function(options) {
|
||||
var self = this;
|
||||
require(["repository/build/registry"], function(Registry) {
|
||||
console.debug("app::initialize() - Loaded Registry:");
|
||||
console.debug(Registry);
|
||||
Utils.get({
|
||||
url: Galaxy.root + "api/datasets/" + options.dataset_id,
|
||||
success: function(dataset) {
|
||||
self.dataset = dataset;
|
||||
self.types = {};
|
||||
_.each(Registry, function(type, type_id) {
|
||||
if (!type.datatypes || type.datatypes.indexOf(dataset.file_ext) != -1) {
|
||||
self.types[type_id] = type;
|
||||
}
|
||||
});
|
||||
if (_.size(self.types) === 0) {
|
||||
self.$el.append(
|
||||
$("<div/>")
|
||||
.addClass("errormessagelarge")
|
||||
.append(
|
||||
$("<p/>").text(
|
||||
"Unfortunately we could not identify a suitable plugin. Feel free to contact us if you are aware of visualizations for this datatype."
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
self._build(options);
|
||||
}
|
||||
});
|
||||
if ( _.size( self.types ) === 0 ) {
|
||||
self.$el.append( $( '<div/>' ).addClass( 'errormessagelarge' )
|
||||
.append( $( '<p/>' ).text( 'Unfortunately we could not identify a suitable plugin. Feel free to contact us if you are aware of visualizations for this datatype.' ) ) );
|
||||
} else {
|
||||
self._build( options );
|
||||
}
|
||||
}
|
||||
});
|
||||
}, function(err) {
|
||||
self.$el.append(
|
||||
$("<div/>")
|
||||
.addClass("errormessagelarge")
|
||||
.append($("<p/>").text("Unable to access the plugin repository:"))
|
||||
.append($("<pre/>").text("charts_repository_url = " + repository_root))
|
||||
.append(
|
||||
$("<p/>").html(
|
||||
"Please verify that your internet connection works properly and that the above url is correct. Contact your admin if this error persists."
|
||||
)
|
||||
)
|
||||
);
|
||||
});
|
||||
}, function( err ) {
|
||||
self.$el.append( $( '<div/>' ).addClass( 'errormessagelarge' )
|
||||
.append( $( '<p/>' ).text( 'Unable to access the plugin repository:' ) )
|
||||
.append( $( '<pre/>' ).text( 'charts_repository_url = ' + repository_root ) )
|
||||
.append( $( '<p/>' ).html( 'Please verify that your internet connection works properly and that the above url is correct. Contact your admin if this error persists.' ) ) );
|
||||
});
|
||||
},
|
||||
},
|
||||
|
||||
_build: function( options ) {
|
||||
this.options = options;
|
||||
this.modal = parent.Galaxy && parent.Galaxy.modal || new Modal.View();
|
||||
this.chart = new Chart( {}, options );
|
||||
this.deferred = new Deferred();
|
||||
this.viewer = new Viewer( this );
|
||||
this.editor = new Editor( this );
|
||||
this.$el.append( this.viewer.$el );
|
||||
this.$el.append( this.editor.$el );
|
||||
this.go( this.chart.load() ? 'viewer' : 'editor' );
|
||||
},
|
||||
_build: function(options) {
|
||||
this.options = options;
|
||||
this.modal = (parent.Galaxy && parent.Galaxy.modal) || new Modal.View();
|
||||
this.chart = new Chart({}, options);
|
||||
this.deferred = new Deferred.default();
|
||||
this.viewer = new Viewer(this);
|
||||
this.editor = new Editor(this);
|
||||
this.$el.append(this.viewer.$el);
|
||||
this.$el.append(this.editor.$el);
|
||||
this.go(this.chart.load() ? "viewer" : "editor");
|
||||
},
|
||||
|
||||
/** Loads a view and makes sure that all others are hidden */
|
||||
go: function( view_id ) {
|
||||
$( '.tooltip' ).hide();
|
||||
this.viewer.hide();
|
||||
this.editor.hide();
|
||||
this[ view_id ].show();
|
||||
},
|
||||
/** Loads a view and makes sure that all others are hidden */
|
||||
go: function(view_id) {
|
||||
$(".tooltip").hide();
|
||||
this.viewer.hide();
|
||||
this.editor.hide();
|
||||
this[view_id].show();
|
||||
},
|
||||
|
||||
/** Split chart type into path components */
|
||||
split: function( chart_type ) {
|
||||
var path = chart_type.split( /_(.+)/ );
|
||||
if ( path.length >= 2 ) {
|
||||
return path[ 0 ] + '/' + path[ 1 ];
|
||||
} else {
|
||||
return chart_type;
|
||||
/** Split chart type into path components */
|
||||
split: function(chart_type) {
|
||||
var path = chart_type.split(/_(.+)/);
|
||||
if (path.length >= 2) {
|
||||
return path[0] + "/" + path[1];
|
||||
} else {
|
||||
return chart_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,98 +1,101 @@
|
||||
define( [ 'utils/utils', 'mvc/visualization/visualization-model' ], function( Utils ) {
|
||||
define(["utils/utils", "mvc/visualization/visualization-model"], function(Utils) {
|
||||
return Backbone.Model.extend({
|
||||
defaults : {
|
||||
title : '',
|
||||
type : '',
|
||||
date : null,
|
||||
state : '',
|
||||
state_info : '',
|
||||
modified : false,
|
||||
dataset_id : '',
|
||||
dataset_id_job : ''
|
||||
defaults: {
|
||||
title: "",
|
||||
type: "",
|
||||
date: null,
|
||||
state: "",
|
||||
state_info: "",
|
||||
modified: false,
|
||||
dataset_id: "",
|
||||
dataset_id_job: ""
|
||||
},
|
||||
|
||||
initialize: function( options, viz_options ) {
|
||||
this.groups = new Backbone.Collection();
|
||||
this.settings = new Backbone.Model();
|
||||
this.definition = {};
|
||||
this.viz_options = viz_options;
|
||||
console.debug( 'model::initialize() - Initialized with configuration:' );
|
||||
console.debug( viz_options );
|
||||
initialize: function(options, viz_options) {
|
||||
this.groups = new Backbone.Collection();
|
||||
this.settings = new Backbone.Model();
|
||||
this.definition = {};
|
||||
this.viz_options = viz_options;
|
||||
console.debug("model::initialize() - Initialized with configuration:");
|
||||
console.debug(viz_options);
|
||||
},
|
||||
|
||||
reset: function() {
|
||||
this.clear().set({
|
||||
title : 'New Chart',
|
||||
type : '__first',
|
||||
dataset_id : this.viz_options.dataset_id
|
||||
title: "New Chart",
|
||||
type: "__first",
|
||||
dataset_id: this.viz_options.dataset_id
|
||||
});
|
||||
this.settings.clear();
|
||||
this.groups.reset();
|
||||
this.groups.add( { id : Utils.uid() } );
|
||||
this.groups.add({ id: Utils.uid() });
|
||||
},
|
||||
|
||||
state: function( value, info ) {
|
||||
this.set( { state : value, state_info : info } );
|
||||
this.trigger( 'set:state' );
|
||||
console.debug( 'model::state() - ' + info + ' (' + value + ')' );
|
||||
state: function(value, info) {
|
||||
this.set({ state: value, state_info: info });
|
||||
this.trigger("set:state");
|
||||
console.debug("model::state() - " + info + " (" + value + ")");
|
||||
},
|
||||
|
||||
/** Pack and save nested chart model */
|
||||
save: function( options ) {
|
||||
save: function(options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
var chart_dict = {
|
||||
attributes : this.attributes,
|
||||
settings : this.settings.attributes,
|
||||
groups : []
|
||||
attributes: this.attributes,
|
||||
settings: this.settings.attributes,
|
||||
groups: []
|
||||
};
|
||||
this.groups.each( function( group ) {
|
||||
chart_dict.groups.push( group.attributes );
|
||||
this.groups.each(function(group) {
|
||||
chart_dict.groups.push(group.attributes);
|
||||
});
|
||||
var viz = new Visualization({
|
||||
id : this.viz_options.visualization_id || undefined,
|
||||
type : 'charts',
|
||||
title : this.get( 'title' ) || '',
|
||||
config : {
|
||||
dataset_id : this.viz_options.dataset_id,
|
||||
chart_dict : this.viz_options.chart_dict = chart_dict
|
||||
id: this.viz_options.visualization_id || undefined,
|
||||
type: "charts",
|
||||
title: this.get("title") || "",
|
||||
config: {
|
||||
dataset_id: this.viz_options.dataset_id,
|
||||
chart_dict: (this.viz_options.chart_dict = chart_dict)
|
||||
}
|
||||
});
|
||||
viz.save().then( function( response ) {
|
||||
if ( response && response.id ) {
|
||||
self.viz_options.visualization_id = response.id;
|
||||
options.success && options.success();
|
||||
console.debug( 'model::save() - Received visualization id: ' + response.id );
|
||||
} else {
|
||||
viz
|
||||
.save()
|
||||
.then(function(response) {
|
||||
if (response && response.id) {
|
||||
self.viz_options.visualization_id = response.id;
|
||||
options.success && options.success();
|
||||
console.debug("model::save() - Received visualization id: " + response.id);
|
||||
} else {
|
||||
options.error && options.error();
|
||||
console.debug("model::save() - Unrecognized response. Saving may have failed.");
|
||||
}
|
||||
})
|
||||
.fail(function(response) {
|
||||
options.error && options.error();
|
||||
console.debug( 'model::save() - Unrecognized response. Saving may have failed.' );
|
||||
}
|
||||
}).fail( function( response ) {
|
||||
options.error && options.error();
|
||||
console.debug( 'model::save() - Saving failed.' );
|
||||
});
|
||||
console.debug( 'model::save() - Saved with configuration:' );
|
||||
console.debug( this.viz_options );
|
||||
console.debug("model::save() - Saving failed.");
|
||||
});
|
||||
console.debug("model::save() - Saved with configuration:");
|
||||
console.debug(this.viz_options);
|
||||
},
|
||||
|
||||
/** Load nested models/collections from packed dictionary */
|
||||
load: function() {
|
||||
console.debug( 'model::load() - Attempting to load with configuration:' );
|
||||
console.debug( this.viz_options );
|
||||
console.debug("model::load() - Attempting to load with configuration:");
|
||||
console.debug(this.viz_options);
|
||||
var chart_dict = this.viz_options.chart_dict;
|
||||
if ( chart_dict && chart_dict.attributes ) {
|
||||
this.set( chart_dict.attributes );
|
||||
this.state( 'ok', 'Loading saved visualization...' );
|
||||
this.settings.set( chart_dict.settings );
|
||||
if (chart_dict && chart_dict.attributes) {
|
||||
this.set(chart_dict.attributes);
|
||||
this.state("ok", "Loading saved visualization...");
|
||||
this.settings.set(chart_dict.settings);
|
||||
this.groups.reset();
|
||||
this.groups.add( chart_dict.groups );
|
||||
this.set( 'modified', false );
|
||||
console.debug( 'model::load() - Loading chart model ' + chart_dict.attributes.type + '.' );
|
||||
this.trigger( 'redraw' );
|
||||
this.groups.add(chart_dict.groups);
|
||||
this.set("modified", false);
|
||||
console.debug("model::load() - Loading chart model " + chart_dict.attributes.type + ".");
|
||||
this.trigger("redraw");
|
||||
return true;
|
||||
}
|
||||
console.debug( 'model::load() - Visualization attributes unavailable.' );
|
||||
console.debug("model::load() - Visualization attributes unavailable.");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,169 +1,188 @@
|
||||
/** This class enables users to export/download a chart as PNG, SVG or PDF. */
|
||||
define( [ 'libs/underscore' ], function( _ ) {
|
||||
define(["libs/underscore"], function(_) {
|
||||
/** PNG export */
|
||||
function createPNG (options) {
|
||||
if ( options.$el.find( 'svg' ).length > 0 ) {
|
||||
_svg2png( options );
|
||||
function createPNG(options) {
|
||||
if (options.$el.find("svg").length > 0) {
|
||||
_svg2png(options);
|
||||
} else {
|
||||
_canvas2png( options.$el.find( '.charts-viewport-canvas' ) );
|
||||
_canvas2png(options.$el.find(".charts-viewport-canvas"));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Convert canvas to png */
|
||||
function _canvas2png( $canvas ) {
|
||||
function _canvas2png($canvas) {
|
||||
try {
|
||||
if ( $canvas.width() !== 0 && $canvas.height() !== 0) {
|
||||
var newCanvas = document.createElement( 'canvas' );
|
||||
newCanvas.width = $canvas.outerWidth( true );
|
||||
newCanvas.height = $canvas.outerHeight( true );
|
||||
var newContext = newCanvas.getContext( '2d' );
|
||||
if ($canvas.width() !== 0 && $canvas.height() !== 0) {
|
||||
var newCanvas = document.createElement("canvas");
|
||||
newCanvas.width = $canvas.outerWidth(true);
|
||||
newCanvas.height = $canvas.outerHeight(true);
|
||||
var newContext = newCanvas.getContext("2d");
|
||||
newContext.save();
|
||||
newContext.fillStyle = 'rgb(255,255,255)';
|
||||
newContext.fillRect( 0,0, newCanvas.width, newCanvas.height );
|
||||
newContext.fillStyle = "rgb(255,255,255)";
|
||||
newContext.fillRect(0, 0, newCanvas.width, newCanvas.height);
|
||||
newContext.restore();
|
||||
newContext.translate( 0, 0 );
|
||||
newContext.textAlign = 'left';
|
||||
newContext.textBaseline = 'top';
|
||||
function _toImage( $el, x_offset, y_offset ) {
|
||||
var tagname = $el.prop( 'tagName' ).toLowerCase();
|
||||
newContext.translate(0, 0);
|
||||
newContext.textAlign = "left";
|
||||
newContext.textBaseline = "top";
|
||||
function _toImage($el, x_offset, y_offset) {
|
||||
var tagname = $el.prop("tagName").toLowerCase();
|
||||
var p = $el.position();
|
||||
var left = x_offset + p.left + parseInt( $el.css( 'marginLeft' ), 10 ) + parseInt( $el.css( 'borderLeftWidth' ), 10 ) + parseInt( $el.css( 'paddingLeft' ), 10 );
|
||||
var top = y_offset + p.top + parseInt( $el.css( 'marginTop' ), 10 ) + parseInt( $el.css( 'borderTopWidth' ), 10 ) + parseInt( $el.css( 'paddingTop' ), 10 );
|
||||
var left =
|
||||
x_offset +
|
||||
p.left +
|
||||
parseInt($el.css("marginLeft"), 10) +
|
||||
parseInt($el.css("borderLeftWidth"), 10) +
|
||||
parseInt($el.css("paddingLeft"), 10);
|
||||
var top =
|
||||
y_offset +
|
||||
p.top +
|
||||
parseInt($el.css("marginTop"), 10) +
|
||||
parseInt($el.css("borderTopWidth"), 10) +
|
||||
parseInt($el.css("paddingTop"), 10);
|
||||
var w = newCanvas.width;
|
||||
if ( tagname == 'div' || tagname == 'span' ) {
|
||||
$el.children().each( function() { _toImage( $( this ), left, top ) } );
|
||||
} else if ( tagname == 'canvas' ) {
|
||||
newContext.drawImage( $el[ 0 ], left, top );
|
||||
if (tagname == "div" || tagname == "span") {
|
||||
$el.children().each(function() {
|
||||
_toImage($(this), left, top);
|
||||
});
|
||||
} else if (tagname == "canvas") {
|
||||
newContext.drawImage($el[0], left, top);
|
||||
}
|
||||
}
|
||||
$canvas.children().each( function() { _toImage( $( this ), 0, 0 ) } );
|
||||
var imgData = newCanvas.toDataURL( 'image/png' );
|
||||
if ( imgData ) {
|
||||
window.location.href = imgData.replace( 'image/png', 'image/octet-stream' );
|
||||
$canvas.children().each(function() {
|
||||
_toImage($(this), 0, 0);
|
||||
});
|
||||
var imgData = newCanvas.toDataURL("image/png");
|
||||
if (imgData) {
|
||||
window.location.href = imgData.replace("image/png", "image/octet-stream");
|
||||
}
|
||||
}
|
||||
} catch ( err ) {
|
||||
console.debug( 'FAILED - screenshot::_canvas2png() - ' + err );
|
||||
} catch (err) {
|
||||
console.debug("FAILED - screenshot::_canvas2png() - " + err);
|
||||
if (options.error) {
|
||||
options.error( 'Please reduce your visualization to a single panel and try again.' );
|
||||
options.error("Please reduce your visualization to a single panel and try again.");
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** Convert svg to png */
|
||||
function _svg2png ( options ) {
|
||||
function _svg2png(options) {
|
||||
var scale = 5;
|
||||
var xml = toXML( options );
|
||||
var canvas = document.createElement( 'canvas' );
|
||||
var context = canvas.getContext( '2d' );
|
||||
var xml = toXML(options);
|
||||
var canvas = document.createElement("canvas");
|
||||
var context = canvas.getContext("2d");
|
||||
var source = new Image();
|
||||
var $container = $( '<div style="display:none;"/>' ).append( $ ( canvas ) );
|
||||
$( 'body' ).append( $container );
|
||||
var $container = $('<div style="display:none;"/>').append($(canvas));
|
||||
$("body").append($container);
|
||||
canvas.width = xml.width * scale;
|
||||
canvas.height = xml.height * scale;
|
||||
source.src = 'data:image/svg+xml;base64,' + btoa( xml.string );
|
||||
source.src = "data:image/svg+xml;base64," + btoa(xml.string);
|
||||
source.onload = function() {
|
||||
context.drawImage( source, 0, 0, canvas.width, canvas.height );
|
||||
window.location.href = canvas.toDataURL( 'image/png' ).replace( 'image/png', 'image/octet-stream' );
|
||||
context.drawImage(source, 0, 0, canvas.width, canvas.height);
|
||||
window.location.href = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
|
||||
$container.remove();
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/** SVG export */
|
||||
function createSVG (options) {
|
||||
window.location.href = 'data:none/none;base64,' + btoa(toXML(options).string);
|
||||
};
|
||||
function createSVG(options) {
|
||||
window.location.href = "data:none/none;base64," + btoa(toXML(options).string);
|
||||
}
|
||||
|
||||
/** PDF export */
|
||||
function createPDF( options ) {
|
||||
var xml = toXML( options );
|
||||
function createPDF(options) {
|
||||
var xml = toXML(options);
|
||||
var data = {
|
||||
filename : 'visualization',
|
||||
type : 'application/pdf',
|
||||
height : xml.height,
|
||||
width : xml.width,
|
||||
scale : 2,
|
||||
svg : xml.string
|
||||
filename: "visualization",
|
||||
type: "application/pdf",
|
||||
height: xml.height,
|
||||
width: xml.width,
|
||||
scale: 2,
|
||||
svg: xml.string
|
||||
};
|
||||
var $el = $( 'body' );
|
||||
var form = $el.find( '#viewport-form' );
|
||||
if ( form.length === 0 ) {
|
||||
form = $( '<form>', {
|
||||
id : 'viewport-form',
|
||||
method : 'post',
|
||||
action : 'http://export.highcharts.com/',
|
||||
display : 'none'
|
||||
var $el = $("body");
|
||||
var form = $el.find("#viewport-form");
|
||||
if (form.length === 0) {
|
||||
form = $("<form>", {
|
||||
id: "viewport-form",
|
||||
method: "post",
|
||||
action: "http://export.highcharts.com/",
|
||||
display: "none"
|
||||
});
|
||||
$el.append( form );
|
||||
$el.append(form);
|
||||
}
|
||||
form.empty();
|
||||
for (var name in data ) {
|
||||
var input = $( '<input/>', {
|
||||
type : 'hidden',
|
||||
name : name,
|
||||
value : data[ name ]
|
||||
for (var name in data) {
|
||||
var input = $("<input/>", {
|
||||
type: "hidden",
|
||||
name: name,
|
||||
value: data[name]
|
||||
});
|
||||
form.append( input );
|
||||
form.append(input);
|
||||
}
|
||||
try {
|
||||
form.submit();
|
||||
} catch( err ) {
|
||||
console.log( err );
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** XML export */
|
||||
function toXML( options ) {
|
||||
var $svg = options.$el.find( 'svg' );
|
||||
if ( $svg.length == 0 ) {
|
||||
if ( options.error ) {
|
||||
options.error( 'No SVG found. This visualization type does not support SVG/PDF export.' );
|
||||
function toXML(options) {
|
||||
var $svg = options.$el.find("svg");
|
||||
if ($svg.length == 0) {
|
||||
if (options.error) {
|
||||
options.error("No SVG found. This visualization type does not support SVG/PDF export.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
var $el = options.$el;
|
||||
var nsvgs = $svg.length;
|
||||
var height = parseInt( $svg.first().css( 'height' ) );
|
||||
var width = parseInt( $svg.first().css( 'width' ) );
|
||||
var nsvgs = $svg.length;
|
||||
var height = parseInt($svg.first().css("height"));
|
||||
var width = parseInt($svg.first().css("width"));
|
||||
var serializer = new XMLSerializer();
|
||||
var $composite = $( '<svg/>' ).attr( { version: '1.1', xmlns: 'http://www.w3.org/2000/svg', width: width * nsvgs, height: height } );
|
||||
var xmlString = '';
|
||||
var $composite = $("<svg/>").attr({
|
||||
version: "1.1",
|
||||
xmlns: "http://www.w3.org/2000/svg",
|
||||
width: width * nsvgs,
|
||||
height: height
|
||||
});
|
||||
var xmlString = "";
|
||||
var offsetX = 0;
|
||||
$svg.each(function() {
|
||||
var $svg = $( this ).clone();
|
||||
_inline( $svg );
|
||||
var $g = $( '<g transform="translate(' + offsetX + ', 0)">' ).attr( 'xmlns', 'http://www.w3.org/2000/svg' );
|
||||
$g.append( $svg.find( 'g' ).first() );
|
||||
$composite.append( $g );
|
||||
var $svg = $(this).clone();
|
||||
_inline($svg);
|
||||
var $g = $('<g transform="translate(' + offsetX + ', 0)">').attr("xmlns", "http://www.w3.org/2000/svg");
|
||||
$g.append($svg.find("g").first());
|
||||
$composite.append($g);
|
||||
offsetX += width;
|
||||
});
|
||||
return {
|
||||
string : serializer.serializeToString( $composite[ 0 ] ),
|
||||
height : height,
|
||||
width : width
|
||||
}
|
||||
};
|
||||
string: serializer.serializeToString($composite[0]),
|
||||
height: height,
|
||||
width: width
|
||||
};
|
||||
}
|
||||
|
||||
/** inlines CSS code */
|
||||
function _inline( $target ) {
|
||||
for ( var sheet_id in document.styleSheets ) {
|
||||
var sheet = document.styleSheets[ sheet_id ];
|
||||
function _inline($target) {
|
||||
for (var sheet_id in document.styleSheets) {
|
||||
var sheet = document.styleSheets[sheet_id];
|
||||
var rules = sheet.cssRules;
|
||||
if ( rules ) {
|
||||
for ( var idx = 0, len = rules.length; idx < len; idx++ ) {
|
||||
if (rules) {
|
||||
for (var idx = 0, len = rules.length; idx < len; idx++) {
|
||||
try {
|
||||
$target.find( rules[ idx ].selectorText ).each( function ( i, elem ) {
|
||||
$target.find(rules[idx].selectorText).each(function(i, elem) {
|
||||
elem.style.cssText += rules[idx].style.cssText;
|
||||
});
|
||||
} catch( err ) {}
|
||||
} catch (err) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
createPNG: createPNG,
|
||||
createSVG: createSVG,
|
||||
createPDF: createPDF
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,41 +1,48 @@
|
||||
/** This class renders the chart configuration form. */
|
||||
define( [ 'utils/utils' ], function( Utils ) {
|
||||
define(["utils/utils"], function(Utils) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function( app, options ) {
|
||||
initialize: function(app, options) {
|
||||
var self = this;
|
||||
this.chart = app.chart;
|
||||
this.app = app;
|
||||
this.setElement( this._template() );
|
||||
this.$title = this.$( '.charts-description-title' );
|
||||
this.$image = this.$( '.charts-description-image' );
|
||||
this.$text = this.$( '.charts-description-text' );
|
||||
this.listenTo( this.chart, 'change', function() { self.render() } );
|
||||
this.setElement(this._template());
|
||||
this.$title = this.$(".charts-description-title");
|
||||
this.$image = this.$(".charts-description-image");
|
||||
this.$text = this.$(".charts-description-text");
|
||||
this.listenTo(this.chart, "change", function() {
|
||||
self.render();
|
||||
});
|
||||
this.render();
|
||||
},
|
||||
render: function() {
|
||||
if ( this.chart.get( 'type' ) ) {
|
||||
this.$image.attr( 'src', repository_root + '/visualizations/' + this.app.split( this.chart.get( 'type' ) ) + '/logo.png' );
|
||||
this.$title.html( this.chart.definition.title + ' (' + this.chart.definition.library + ')' );
|
||||
this.$text.html( Utils.linkify( this.chart.definition.description || '' ) );
|
||||
if (this.chart.get("type")) {
|
||||
this.$image.attr(
|
||||
"src",
|
||||
repository_root + "/visualizations/" + this.app.split(this.chart.get("type")) + "/logo.png"
|
||||
);
|
||||
this.$title.html(this.chart.definition.title + " (" + this.chart.definition.library + ")");
|
||||
this.$text.html(Utils.linkify(this.chart.definition.description || ""));
|
||||
this.$el.show();
|
||||
} else {
|
||||
this.$el.hide();
|
||||
}
|
||||
},
|
||||
_template: function() {
|
||||
return '<div class="charts-description">' +
|
||||
'<table>' +
|
||||
'<tr>' +
|
||||
'<td class="charts-description-image-td">' +
|
||||
'<img class="charts-description-image"/>' +
|
||||
'</td>' +
|
||||
'<td>' +
|
||||
'<div class="charts-description-title ui-form-info"/>' +
|
||||
'<div class="charts-description-text ui-form-info"/>' +
|
||||
'</td>' +
|
||||
'</tr>' +
|
||||
'</table>' +
|
||||
'</div>';
|
||||
return (
|
||||
'<div class="charts-description">' +
|
||||
"<table>" +
|
||||
"<tr>" +
|
||||
'<td class="charts-description-image-td">' +
|
||||
'<img class="charts-description-image"/>' +
|
||||
"</td>" +
|
||||
"<td>" +
|
||||
'<div class="charts-description-title ui-form-info"/>' +
|
||||
'<div class="charts-description-text ui-form-info"/>' +
|
||||
"</td>" +
|
||||
"</tr>" +
|
||||
"</table>" +
|
||||
"</div>"
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,171 +2,207 @@
|
||||
* The charts editor holds the tabs for selecting chart types, chart configuration
|
||||
* and data group selections.
|
||||
*/
|
||||
define( [ 'mvc/ui/ui-tabs', 'mvc/ui/ui-misc', 'mvc/ui/ui-portlet', 'mvc/ui/ui-thumbnails', 'utils/utils', 'plugin/views/settings', 'plugin/views/groups' ],
|
||||
function( Tabs, Ui, Portlet, Thumbnails, Utils, SettingsView, GroupsView ) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function( app, options ){
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = this.app.chart;
|
||||
this.message = new Ui.Message( { cls: 'ui-margin-bottom' } );
|
||||
this.portlet = new Portlet.View({
|
||||
icon : 'fa-bar-chart-o',
|
||||
title: 'Editor',
|
||||
operations : {
|
||||
'draw' : new Ui.ButtonIcon({
|
||||
icon : 'fa-line-chart',
|
||||
tooltip : 'Render Visualization',
|
||||
title : 'Visualize',
|
||||
onclick : function() {
|
||||
self._drawChart();
|
||||
}
|
||||
define(
|
||||
[
|
||||
"mvc/ui/ui-tabs",
|
||||
"mvc/ui/ui-misc",
|
||||
"mvc/ui/ui-portlet",
|
||||
"mvc/ui/ui-thumbnails",
|
||||
"utils/utils",
|
||||
"plugin/views/settings",
|
||||
"plugin/views/groups"
|
||||
],
|
||||
function(Tabs, Ui, Portlet, Thumbnails, Utils, SettingsView, GroupsView) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function(app, options) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = this.app.chart;
|
||||
this.message = new Ui.Message({ cls: "ui-margin-bottom" });
|
||||
this.portlet = new Portlet.View({
|
||||
icon: "fa-bar-chart-o",
|
||||
title: "Editor",
|
||||
operations: {
|
||||
draw: new Ui.ButtonIcon({
|
||||
icon: "fa-line-chart",
|
||||
tooltip: "Render Visualization",
|
||||
title: "Visualize",
|
||||
onclick: function() {
|
||||
self._drawChart();
|
||||
}
|
||||
}),
|
||||
back: new Ui.ButtonIcon({
|
||||
icon: "fa-caret-left",
|
||||
tooltip: "Return to Viewer",
|
||||
title: "Cancel",
|
||||
onclick: function() {
|
||||
self.app.go("viewer");
|
||||
self.chart.load();
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// grid with chart types
|
||||
this.types = new Thumbnails.View({
|
||||
title_default: "Suggested visualizations",
|
||||
title_list: "List of available visualizations",
|
||||
collection: _.map(this.app.types, function(type, type_id) {
|
||||
return {
|
||||
id: type_id,
|
||||
keywords: type.keywords,
|
||||
title: type.title + " (" + type.library + ")",
|
||||
title_icon: type.zoomable && "fa-search-plus",
|
||||
image_src: repository_root + "/visualizations/" + self.app.split(type_id) + "/logo.png",
|
||||
description: type.description
|
||||
};
|
||||
}),
|
||||
'back' : new Ui.ButtonIcon({
|
||||
icon : 'fa-caret-left',
|
||||
tooltip : 'Return to Viewer',
|
||||
title : 'Cancel',
|
||||
onclick : function() {
|
||||
self.app.go( 'viewer' );
|
||||
self.chart.load();
|
||||
ondblclick: function(chart_type) {
|
||||
self._drawChart();
|
||||
},
|
||||
onchange: function(chart_type) {
|
||||
var chart_definition = self.app.types[chart_type];
|
||||
if (!chart_definition) {
|
||||
self.tabs.hideTab("settings");
|
||||
self.tabs.hideTab("groups");
|
||||
self.portlet.hideOperation("draw");
|
||||
console.debug("editor::onchange() - Chart type not found.");
|
||||
self.message.update({
|
||||
message:
|
||||
"The requested visualization type could not be found. Please select a new type from below or contact us.",
|
||||
status: "danger",
|
||||
persistent: true
|
||||
});
|
||||
} else {
|
||||
self.tabs.showTab("settings");
|
||||
self.tabs.showTab("groups");
|
||||
self.portlet.showOperation("draw");
|
||||
self.chart.definition = chart_definition;
|
||||
self.chart.set({ type: chart_type, modified: true });
|
||||
self.message.model.set("message", "");
|
||||
console.debug("editor::onchange() - Switched visualization type.");
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// grid with chart types
|
||||
this.types = new Thumbnails.View({
|
||||
title_default : 'Suggested visualizations',
|
||||
title_list : 'List of available visualizations',
|
||||
collection : _.map( this.app.types, function( type, type_id ) {
|
||||
return {
|
||||
id : type_id,
|
||||
keywords : type.keywords,
|
||||
title : type.title + ' (' + type.library + ')',
|
||||
title_icon : type.zoomable && 'fa-search-plus',
|
||||
image_src : repository_root + '/visualizations/' + self.app.split( type_id ) + '/logo.png',
|
||||
description : type.description
|
||||
}
|
||||
}),
|
||||
ondblclick : function( chart_type ) { self._drawChart() },
|
||||
onchange : function( chart_type ) {
|
||||
var chart_definition = self.app.types[ chart_type ];
|
||||
if ( !chart_definition ) {
|
||||
self.tabs.hideTab( 'settings' );
|
||||
self.tabs.hideTab( 'groups' );
|
||||
self.portlet.hideOperation( 'draw' );
|
||||
console.debug( 'editor::onchange() - Chart type not found.' );
|
||||
self.message.update( { message: 'The requested visualization type could not be found. Please select a new type from below or contact us.', status: 'danger', persistent: true } );
|
||||
} else {
|
||||
self.tabs.showTab( 'settings' );
|
||||
self.tabs.showTab( 'groups' );
|
||||
self.portlet.showOperation( 'draw' );
|
||||
self.chart.definition = chart_definition;
|
||||
self.chart.set( { type : chart_type, modified : true } );
|
||||
self.message.model.set( 'message', '' );
|
||||
console.debug( 'editor::onchange() - Switched visualization type.' );
|
||||
});
|
||||
|
||||
// input field for chart title
|
||||
this.title = new Ui.Input({
|
||||
placeholder: "Chart title",
|
||||
onchange: function() {
|
||||
self.chart.set("title", self.title.value());
|
||||
}
|
||||
});
|
||||
|
||||
// create tabs
|
||||
this.tabs = new Tabs.View({});
|
||||
this.tabs.add({
|
||||
id: "main",
|
||||
title: "Start",
|
||||
icon: "fa fa-bars",
|
||||
tooltip: "Start by selecting a visualization.",
|
||||
$el: $("<div/>")
|
||||
.append(new Ui.Label({ title: "Provide a title:" }).$el)
|
||||
.append(this.title.$el)
|
||||
.append(
|
||||
$("<div/>")
|
||||
.addClass("ui-form-info ui-margin-bottom")
|
||||
.html("This title will appear in the list of 'Saved Visualizations'.")
|
||||
)
|
||||
.append(new Ui.Label({ title: "Select a visualization:" }).$el.addClass("ui-margin-top"))
|
||||
.append(this.types.$el)
|
||||
});
|
||||
this.tabs.add({
|
||||
id: "settings",
|
||||
title: "Customize",
|
||||
icon: "fa-gear",
|
||||
tooltip: "Customize the visualization.",
|
||||
$el: new SettingsView(this.app).$el
|
||||
});
|
||||
this.tabs.add({
|
||||
id: "groups",
|
||||
title: "Select data",
|
||||
icon: "fa-database",
|
||||
tooltip: "Specify data options.",
|
||||
$el: new GroupsView(this.app).$el
|
||||
});
|
||||
|
||||
// set elements
|
||||
this.portlet.append(this.message.$el);
|
||||
this.portlet.append(this.tabs.$el.addClass("ui-margin-top-large"));
|
||||
this.portlet.hideOperation("back");
|
||||
this.setElement(this.portlet.$el);
|
||||
|
||||
// chart events
|
||||
this.listenTo(this.chart, "change:title", function(chart) {
|
||||
self._refreshTitle();
|
||||
});
|
||||
this.listenTo(this.chart, "change:type", function(chart) {
|
||||
self.types.value(chart.get("type"));
|
||||
});
|
||||
this.listenTo(this.chart, "redraw", function(chart) {
|
||||
self.portlet.showOperation("back");
|
||||
});
|
||||
this.chart.reset();
|
||||
},
|
||||
|
||||
/** Show editor */
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
/** Hide editor */
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
},
|
||||
|
||||
/** Refresh title handler */
|
||||
_refreshTitle: function() {
|
||||
var title = this.chart.get("title");
|
||||
this.portlet.title(title);
|
||||
this.title.value(title);
|
||||
},
|
||||
|
||||
/** Draw chart data */
|
||||
_drawChart: function() {
|
||||
var self = this;
|
||||
this.chart.set({
|
||||
type: this.types.value(),
|
||||
title: this.title.value(),
|
||||
date: Utils.time()
|
||||
});
|
||||
if (this.chart.groups.length == 0) {
|
||||
this.message.update({
|
||||
message: "Please specify data options before rendering the visualization.",
|
||||
persistent: false
|
||||
});
|
||||
this.tabs.show("groups");
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// input field for chart title
|
||||
this.title = new Ui.Input({
|
||||
placeholder: 'Chart title',
|
||||
onchange: function() {
|
||||
self.chart.set( 'title', self.title.value() );
|
||||
}
|
||||
});
|
||||
|
||||
// create tabs
|
||||
this.tabs = new Tabs.View( {} );
|
||||
this.tabs.add({
|
||||
id : 'main',
|
||||
title : 'Start',
|
||||
icon : 'fa fa-bars',
|
||||
tooltip : 'Start by selecting a visualization.',
|
||||
$el : $( '<div/>' ).append( ( new Ui.Label( { title : 'Provide a title:' } ).$el ) )
|
||||
.append( this.title.$el )
|
||||
.append( $( '<div/>' ).addClass( 'ui-form-info ui-margin-bottom' ).html( 'This title will appear in the list of \'Saved Visualizations\'.' ) )
|
||||
.append( ( new Ui.Label( { title : 'Select a visualization:' } ).$el.addClass( 'ui-margin-top' ) ) )
|
||||
.append( this.types.$el )
|
||||
});
|
||||
this.tabs.add({
|
||||
id : 'settings',
|
||||
title : 'Customize',
|
||||
icon : 'fa-gear',
|
||||
tooltip : 'Customize the visualization.',
|
||||
$el : ( new SettingsView( this.app ) ).$el
|
||||
});
|
||||
this.tabs.add({
|
||||
id : 'groups',
|
||||
title : 'Select data',
|
||||
icon : 'fa-database',
|
||||
tooltip : 'Specify data options.',
|
||||
$el : ( new GroupsView( this.app ) ).$el
|
||||
});
|
||||
|
||||
// set elements
|
||||
this.portlet.append( this.message.$el );
|
||||
this.portlet.append( this.tabs.$el.addClass( 'ui-margin-top-large' ) );
|
||||
this.portlet.hideOperation( 'back' );
|
||||
this.setElement( this.portlet.$el );
|
||||
|
||||
// chart events
|
||||
this.listenTo( this.chart, 'change:title', function( chart ) { self._refreshTitle() } );
|
||||
this.listenTo( this.chart, 'change:type', function( chart ) { self.types.value( chart.get( 'type' ) ) } );
|
||||
this.listenTo( this.chart, 'redraw', function( chart ) { self.portlet.showOperation( 'back' ) } );
|
||||
this.chart.reset();
|
||||
},
|
||||
|
||||
/** Show editor */
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
},
|
||||
|
||||
/** Hide editor */
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
},
|
||||
|
||||
/** Refresh title handler */
|
||||
_refreshTitle: function() {
|
||||
var title = this.chart.get( 'title' );
|
||||
this.portlet.title( title );
|
||||
this.title.value( title );
|
||||
},
|
||||
|
||||
/** Draw chart data */
|
||||
_drawChart: function() {
|
||||
var self = this;
|
||||
this.chart.set({
|
||||
type : this.types.value(),
|
||||
title : this.title.value(),
|
||||
date : Utils.time()
|
||||
});
|
||||
if ( this.chart.groups.length == 0 ) {
|
||||
this.message.update( { message: 'Please specify data options before rendering the visualization.', persistent: false } );
|
||||
this.tabs.show( 'groups' );
|
||||
return;
|
||||
}
|
||||
var valid = true;
|
||||
var chart_def = this.chart.definition;
|
||||
this.chart.groups.each( function( group ) {
|
||||
if ( valid ) {
|
||||
_.each( group.get( '__data_columns' ), function( data_columns, name ) {
|
||||
if ( group.attributes[ name ] === null ) {
|
||||
self.message.update( { status: 'danger', message: 'This visualization type requires column types not found in your tabular file.', persistent: false } );
|
||||
self.tabs.show( 'groups' );
|
||||
valid = false;
|
||||
}
|
||||
var valid = true;
|
||||
var chart_def = this.chart.definition;
|
||||
this.chart.groups.each(function(group) {
|
||||
if (valid) {
|
||||
_.each(group.get("__data_columns"), function(data_columns, name) {
|
||||
if (group.attributes[name] === null) {
|
||||
self.message.update({
|
||||
status: "danger",
|
||||
message:
|
||||
"This visualization type requires column types not found in your tabular file.",
|
||||
persistent: false
|
||||
});
|
||||
self.tabs.show("groups");
|
||||
valid = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
if (valid) {
|
||||
this.app.go("viewer");
|
||||
this.app.deferred.execute(function() {
|
||||
self.chart.trigger("redraw");
|
||||
});
|
||||
}
|
||||
});
|
||||
if ( valid ) {
|
||||
this.app.go( 'viewer' );
|
||||
this.app.deferred.execute( function() {
|
||||
self.chart.trigger( 'redraw' );
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,105 +1,143 @@
|
||||
/** This class renders the chart data selection form with repeats. */
|
||||
define( [ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-repeat', 'mvc/form/form-data', 'plugin/views/description' ],
|
||||
function( Utils, Ui, Form, Repeat, FormData, Description ) {
|
||||
var GroupView = Backbone.View.extend({
|
||||
initialize: function( app, options ) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = app.chart;
|
||||
this.group = options.group;
|
||||
this.setElement( $( '<div/>' ) );
|
||||
this.listenTo( this.chart, 'change:dataset_id change:type', function() { self.render() } );
|
||||
this.render();
|
||||
},
|
||||
define(
|
||||
[
|
||||
"utils/utils",
|
||||
"mvc/ui/ui-misc",
|
||||
"mvc/form/form-view",
|
||||
"mvc/form/form-repeat",
|
||||
"mvc/form/form-data",
|
||||
"plugin/views/description"
|
||||
],
|
||||
function(Utils, Ui, Form, Repeat, FormData, Description) {
|
||||
var GroupView = Backbone.View.extend({
|
||||
initialize: function(app, options) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = app.chart;
|
||||
this.group = options.group;
|
||||
this.setElement($("<div/>"));
|
||||
this.listenTo(this.chart, "change:dataset_id change:type", function() {
|
||||
self.render();
|
||||
});
|
||||
this.render();
|
||||
},
|
||||
|
||||
render: function() {
|
||||
var self = this;
|
||||
var inputs = this.chart.definition.groups ? Utils.clone( this.chart.definition.groups ) : {};
|
||||
var dataset_id = this.chart.get( 'dataset_id' );
|
||||
var chart_type = this.chart.get( 'type' );
|
||||
var chart_definition = this.chart.definition;
|
||||
if ( dataset_id && chart_type ) {
|
||||
this.chart.state( 'wait', 'Loading metadata...' );
|
||||
this.app.deferred.execute( function( process ) {
|
||||
Utils.get({
|
||||
url : Galaxy.root + 'api/datasets/' + dataset_id,
|
||||
cache : true,
|
||||
success : function( dataset ) {
|
||||
var data_columns = {};
|
||||
FormData.visitInputs( inputs, function( input, prefixed ) {
|
||||
if ( input.type == 'data_column' ) {
|
||||
data_columns[ prefixed ] = Utils.clone( input );
|
||||
var columns = [];
|
||||
input.is_auto && columns.push( { 'label': 'Column: Row Number', 'value': 'auto' } );
|
||||
input.is_zero && columns.push( { 'label' : 'Column: None', 'value' : 'zero' } );
|
||||
var meta = dataset.metadata_column_types;
|
||||
for ( var key in meta ) {
|
||||
var valid = ( [ 'int', 'float' ].indexOf( meta[ key ] ) != -1 && input.is_numeric ) || input.is_label;
|
||||
valid && columns.push( { 'label' : 'Column: ' + ( parseInt( key ) + 1 ), 'value' : key } );
|
||||
render: function() {
|
||||
var self = this;
|
||||
var inputs = this.chart.definition.groups ? Utils.clone(this.chart.definition.groups) : {};
|
||||
var dataset_id = this.chart.get("dataset_id");
|
||||
var chart_type = this.chart.get("type");
|
||||
var chart_definition = this.chart.definition;
|
||||
if (dataset_id && chart_type) {
|
||||
this.chart.state("wait", "Loading metadata...");
|
||||
this.app.deferred.execute(function(process) {
|
||||
Utils.get({
|
||||
url: Galaxy.root + "api/datasets/" + dataset_id,
|
||||
cache: true,
|
||||
success: function(dataset) {
|
||||
var data_columns = {};
|
||||
FormData.visitInputs(inputs, function(input, prefixed) {
|
||||
if (input.type == "data_column") {
|
||||
data_columns[prefixed] = Utils.clone(input);
|
||||
var columns = [];
|
||||
input.is_auto && columns.push({ label: "Column: Row Number", value: "auto" });
|
||||
input.is_zero && columns.push({ label: "Column: None", value: "zero" });
|
||||
var meta = dataset.metadata_column_types;
|
||||
for (var key in meta) {
|
||||
var valid =
|
||||
(["int", "float"].indexOf(meta[key]) != -1 && input.is_numeric) ||
|
||||
input.is_label;
|
||||
valid &&
|
||||
columns.push({ label: "Column: " + (parseInt(key) + 1), value: key });
|
||||
}
|
||||
input.data = columns;
|
||||
}
|
||||
input.data = columns;
|
||||
}
|
||||
var model_value = self.group.get( prefixed );
|
||||
model_value !== undefined && !input.hidden && ( input.value = model_value );
|
||||
});
|
||||
inputs[ '__data_columns' ] = { name: '__data_columns', type: 'hidden', hidden: true, value: data_columns };
|
||||
self.chart.state( 'ok', 'Metadata initialized...' );
|
||||
self.form = new Form( {
|
||||
inputs : inputs,
|
||||
cls : 'ui-portlet-plain',
|
||||
onchange: function() {
|
||||
self.group.set( self.form.data.create() );
|
||||
self.chart.set( 'modified', true );
|
||||
}
|
||||
} );
|
||||
self.group.set( self.form.data.create() );
|
||||
self.$el.empty().append( self.form.$el );
|
||||
process.resolve();
|
||||
var model_value = self.group.get(prefixed);
|
||||
model_value !== undefined && !input.hidden && (input.value = model_value);
|
||||
});
|
||||
inputs["__data_columns"] = {
|
||||
name: "__data_columns",
|
||||
type: "hidden",
|
||||
hidden: true,
|
||||
value: data_columns
|
||||
};
|
||||
self.chart.state("ok", "Metadata initialized...");
|
||||
self.form = new Form.View({
|
||||
inputs: inputs,
|
||||
cls: "ui-portlet-plain",
|
||||
onchange: function() {
|
||||
self.group.set(self.form.data.create());
|
||||
self.chart.set("modified", true);
|
||||
}
|
||||
});
|
||||
self.group.set(self.form.data.create());
|
||||
self.$el.empty().append(self.form.$el);
|
||||
process.resolve();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return Backbone.View.extend({
|
||||
initialize: function(app) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = app.chart;
|
||||
this.repeat = new Repeat.View({
|
||||
title: "Data series",
|
||||
title_new: "Data series",
|
||||
min: 1,
|
||||
onnew: function() {
|
||||
self.chart.groups.add({ id: Utils.uid() });
|
||||
}
|
||||
});
|
||||
this.description = new Description(this.app);
|
||||
this.message = new Ui.Message({
|
||||
message: "There are no options for this visualization type.",
|
||||
persistent: true,
|
||||
status: "info"
|
||||
});
|
||||
this.setElement(
|
||||
$("<div/>")
|
||||
.append(this.description.$el)
|
||||
.append(this.repeat.$el.addClass("ui-margin-bottom"))
|
||||
.append(this.message.$el.addClass("ui-margin-bottom"))
|
||||
);
|
||||
this.listenTo(this.chart, "change", function() {
|
||||
self.render();
|
||||
});
|
||||
this.listenTo(this.chart.groups, "add remove reset", function() {
|
||||
self.chart.set("modified", true);
|
||||
});
|
||||
this.listenTo(this.chart.groups, "remove", function(group) {
|
||||
self.repeat.del(group.id);
|
||||
});
|
||||
this.listenTo(this.chart.groups, "reset", function() {
|
||||
self.repeat.delAll();
|
||||
});
|
||||
this.listenTo(this.chart.groups, "add", function(group) {
|
||||
self.repeat.add({
|
||||
id: group.id,
|
||||
cls: "ui-portlet-panel",
|
||||
$el: new GroupView(self.app, { group: group }).$el,
|
||||
ondel: function() {
|
||||
self.chart.groups.remove(group);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
return Backbone.View.extend({
|
||||
initialize: function( app ) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = app.chart;
|
||||
this.repeat = new Repeat.View({
|
||||
title : 'Data series',
|
||||
title_new : 'Data series',
|
||||
min : 1,
|
||||
onnew : function() { self.chart.groups.add( { id : Utils.uid() } ) }
|
||||
});
|
||||
this.description = new Description( this.app );
|
||||
this.message = new Ui.Message( { message : 'There are no options for this visualization type.', persistent : true, status : 'info' } );
|
||||
this.setElement( $( '<div/>' ).append( this.description.$el )
|
||||
.append( this.repeat.$el.addClass( 'ui-margin-bottom' ) )
|
||||
.append( this.message.$el.addClass( 'ui-margin-bottom' ) ) );
|
||||
this.listenTo( this.chart, 'change', function() { self.render() } );
|
||||
this.listenTo( this.chart.groups, 'add remove reset', function() { self.chart.set( 'modified', true ) } );
|
||||
this.listenTo( this.chart.groups, 'remove', function( group ) { self.repeat.del( group.id ) } );
|
||||
this.listenTo( this.chart.groups, 'reset', function() { self.repeat.delAll() } );
|
||||
this.listenTo( this.chart.groups, 'add', function( group ) {
|
||||
self.repeat.add({
|
||||
id : group.id,
|
||||
cls : 'ui-portlet-panel',
|
||||
$el : ( new GroupView( self.app, { group: group } ) ).$el,
|
||||
ondel : function() { self.chart.groups.remove( group ) }
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
render: function() {
|
||||
if ( _.size( this.chart.definition.groups ) > 0 ) {
|
||||
this.repeat.$el.show();
|
||||
this.message.$el.hide();
|
||||
} else {
|
||||
this.repeat.$el.hide();
|
||||
this.message.$el.show();
|
||||
render: function() {
|
||||
if (_.size(this.chart.definition.groups) > 0) {
|
||||
this.repeat.$el.show();
|
||||
this.message.$el.hide();
|
||||
} else {
|
||||
this.repeat.$el.hide();
|
||||
this.message.$el.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,47 +1,61 @@
|
||||
/** This class renders the chart configuration form. */
|
||||
define( [ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/form/form-view', 'mvc/form/form-data', 'plugin/views/description' ], function( Utils, Ui, Form, FormData, Description ) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function( app, options ) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = app.chart;
|
||||
this.description = new Description( this.app );
|
||||
this.message = new Ui.Message( { message: 'There are no options for this visualization type.', persistent: true, status: 'info' } );
|
||||
this.setElement( $( '<div/>' ).append( this.description.$el )
|
||||
.append( this.message.$el.addClass( 'ui-margin-bottom' ) )
|
||||
.append( this.$form = $( '<div/>' ).addClass( 'ui-margin-bottom' ) ) );
|
||||
this.listenTo( this.chart, 'change', function() { self.render() } );
|
||||
},
|
||||
render: function() {
|
||||
var self = this;
|
||||
var inputs = Utils.clone( this.chart.definition.settings ) || {};
|
||||
var panel_option = this.chart.definition.use_panels;
|
||||
if ( panel_option == 'both' ) {
|
||||
inputs[ '__use_panels' ] = {
|
||||
type : 'boolean',
|
||||
label : 'Use multi-panels',
|
||||
help : 'Would you like to separate your data into individual panels?'
|
||||
};
|
||||
} else {
|
||||
this.chart.settings.set( '__use_panels', panel_option == 'yes' ? 'true' : 'false' );
|
||||
}
|
||||
if ( _.size( inputs ) > 0 ) {
|
||||
FormData.visitInputs( inputs, function( input, name ) {
|
||||
var model_value = self.chart.settings.get( name );
|
||||
model_value !== undefined && !input.hidden && ( input.value = model_value );
|
||||
define(
|
||||
["utils/utils", "mvc/ui/ui-misc", "mvc/form/form-view", "mvc/form/form-data", "plugin/views/description"],
|
||||
function(Utils, Ui, Form, FormData, Description) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function(app, options) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = app.chart;
|
||||
this.description = new Description(this.app);
|
||||
this.message = new Ui.Message({
|
||||
message: "There are no options for this visualization type.",
|
||||
persistent: true,
|
||||
status: "info"
|
||||
});
|
||||
this.form = new Form({
|
||||
inputs : inputs,
|
||||
cls : 'ui-portlet-plain',
|
||||
onchange : function() { self.chart.settings.set( self.form.data.create() ); }
|
||||
this.setElement(
|
||||
$("<div/>")
|
||||
.append(this.description.$el)
|
||||
.append(this.message.$el.addClass("ui-margin-bottom"))
|
||||
.append((this.$form = $("<div/>").addClass("ui-margin-bottom")))
|
||||
);
|
||||
this.listenTo(this.chart, "change", function() {
|
||||
self.render();
|
||||
});
|
||||
this.chart.settings.set( this.form.data.create() );
|
||||
this.$form.empty().append( this.form.$el );
|
||||
this.message.$el.hide();
|
||||
} else {
|
||||
this.$form.empty();
|
||||
this.message.$el.show();
|
||||
},
|
||||
render: function() {
|
||||
var self = this;
|
||||
var inputs = Utils.clone(this.chart.definition.settings) || {};
|
||||
var panel_option = this.chart.definition.use_panels;
|
||||
if (panel_option == "both") {
|
||||
inputs["__use_panels"] = {
|
||||
type: "boolean",
|
||||
label: "Use multi-panels",
|
||||
help: "Would you like to separate your data into individual panels?"
|
||||
};
|
||||
} else {
|
||||
this.chart.settings.set("__use_panels", panel_option == "yes" ? "true" : "false");
|
||||
}
|
||||
if (_.size(inputs) > 0) {
|
||||
FormData.visitInputs(inputs, function(input, name) {
|
||||
var model_value = self.chart.settings.get(name);
|
||||
model_value !== undefined && !input.hidden && (input.value = model_value);
|
||||
});
|
||||
this.form = new Form.View({
|
||||
inputs: inputs,
|
||||
cls: "ui-portlet-plain",
|
||||
onchange: function() {
|
||||
self.chart.settings.set(self.form.data.create());
|
||||
}
|
||||
});
|
||||
this.chart.settings.set(this.form.data.create());
|
||||
this.$form.empty().append(this.form.$el);
|
||||
this.message.$el.hide();
|
||||
} else {
|
||||
this.$form.empty();
|
||||
this.message.$el.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -1,137 +1,159 @@
|
||||
/** This class renders the chart viewer which encapsulates the chart viewport. */
|
||||
define( [ 'utils/utils', 'mvc/ui/ui-misc', 'mvc/ui/ui-portlet', 'plugin/views/viewport', 'plugin/components/screenshot' ],
|
||||
function( Utils, Ui, Portlet, Viewport, Screenshot ) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function(app, options){
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = this.app.chart;
|
||||
this.viewport = new Viewport( app );
|
||||
this.message = new Ui.Message();
|
||||
this.export_button = new Ui.ButtonMenu({
|
||||
icon : 'fa-camera',
|
||||
title : 'Export',
|
||||
tooltip : 'Export/Download Visualization'
|
||||
});
|
||||
this.export_button.addMenu({
|
||||
key : 'png',
|
||||
title : 'Save as PNG',
|
||||
icon : 'fa-file',
|
||||
onclick : function() {
|
||||
self._wait( self.chart, function() {
|
||||
Screenshot.createPNG({
|
||||
$el : self.viewport.$el,
|
||||
title : self.chart.get( 'title' ),
|
||||
error : function( err ) {
|
||||
self.message.update( { message: err, status: 'danger' } );
|
||||
}
|
||||
define(
|
||||
["utils/utils", "mvc/ui/ui-misc", "mvc/ui/ui-portlet", "plugin/views/viewport", "plugin/components/screenshot"],
|
||||
function(Utils, Ui, Portlet, Viewport, Screenshot) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function(app, options) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = this.app.chart;
|
||||
this.viewport = new Viewport(app);
|
||||
this.message = new Ui.Message();
|
||||
this.export_button = new Ui.ButtonMenu({
|
||||
icon: "fa-camera",
|
||||
title: "Export",
|
||||
tooltip: "Export/Download Visualization"
|
||||
});
|
||||
this.export_button.addMenu({
|
||||
key: "png",
|
||||
title: "Save as PNG",
|
||||
icon: "fa-file",
|
||||
onclick: function() {
|
||||
self._wait(self.chart, function() {
|
||||
Screenshot.createPNG({
|
||||
$el: self.viewport.$el,
|
||||
title: self.chart.get("title"),
|
||||
error: function(err) {
|
||||
self.message.update({ message: err, status: "danger" });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
this.export_button.addMenu({
|
||||
key : 'svg',
|
||||
title : 'Save as SVG',
|
||||
icon : 'fa-file-text-o',
|
||||
onclick : function() {
|
||||
self._wait( self.chart, function() {
|
||||
Screenshot.createSVG({
|
||||
$el : self.viewport.$el,
|
||||
title : self.chart.get( 'title' ),
|
||||
error : function( err ) {
|
||||
self.message.update( { message: err, status: 'danger' } );
|
||||
}
|
||||
}
|
||||
});
|
||||
this.export_button.addMenu({
|
||||
key: "svg",
|
||||
title: "Save as SVG",
|
||||
icon: "fa-file-text-o",
|
||||
onclick: function() {
|
||||
self._wait(self.chart, function() {
|
||||
Screenshot.createSVG({
|
||||
$el: self.viewport.$el,
|
||||
title: self.chart.get("title"),
|
||||
error: function(err) {
|
||||
self.message.update({ message: err, status: "danger" });
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
this.export_button.addMenu({
|
||||
key : 'pdf',
|
||||
title : 'Save as PDF',
|
||||
icon : 'fa-file-o',
|
||||
onclick : function() {
|
||||
self.app.modal.show({
|
||||
title : 'Send visualization data for PDF creation',
|
||||
body : 'Galaxy does not provide integrated PDF export scripts. You may click \'Continue\' to create the PDF by using a 3rd party service (https://export.highcharts.com).',
|
||||
buttons : {
|
||||
'Cancel' : function() { self.app.modal.hide() },
|
||||
'Continue' : function() {
|
||||
self.app.modal.hide();
|
||||
self._wait( self.chart, function() {
|
||||
Screenshot.createPDF({
|
||||
$el : self.viewport.$el,
|
||||
title : self.chart.get( 'title' ),
|
||||
error : function( err ) {
|
||||
self.message.update( { message: err, status: 'danger' } );
|
||||
}
|
||||
}
|
||||
});
|
||||
this.export_button.addMenu({
|
||||
key: "pdf",
|
||||
title: "Save as PDF",
|
||||
icon: "fa-file-o",
|
||||
onclick: function() {
|
||||
self.app.modal.show({
|
||||
title: "Send visualization data for PDF creation",
|
||||
body:
|
||||
"Galaxy does not provide integrated PDF export scripts. You may click 'Continue' to create the PDF by using a 3rd party service (https://export.highcharts.com).",
|
||||
buttons: {
|
||||
Cancel: function() {
|
||||
self.app.modal.hide();
|
||||
},
|
||||
Continue: function() {
|
||||
self.app.modal.hide();
|
||||
self._wait(self.chart, function() {
|
||||
Screenshot.createPDF({
|
||||
$el: self.viewport.$el,
|
||||
title: self.chart.get("title"),
|
||||
error: function(err) {
|
||||
self.message.update({ message: err, status: "danger" });
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
this.portlet = new Portlet.View({
|
||||
icon: "fa-bar-chart-o",
|
||||
title: "Viewport",
|
||||
cls: "ui-portlet charts-viewer",
|
||||
operations: {
|
||||
edit_button: new Ui.ButtonIcon({
|
||||
icon: "fa-edit",
|
||||
tooltip: "Customize this Visualization",
|
||||
title: "Editor",
|
||||
onclick: function() {
|
||||
self._wait(self.chart, function() {
|
||||
self.app.go("editor");
|
||||
});
|
||||
}
|
||||
}
|
||||
}),
|
||||
export_button: this.export_button,
|
||||
save_button: new Ui.ButtonIcon({
|
||||
icon: "fa-save",
|
||||
tooltip: "Save this Visualization",
|
||||
title: "Save",
|
||||
onclick: function() {
|
||||
self.message.update({
|
||||
message:
|
||||
"Saving '" +
|
||||
self.chart.get("title") +
|
||||
"'. It will appear in the list of 'Saved Visualizations'.",
|
||||
status: "success"
|
||||
});
|
||||
self.chart.save({
|
||||
error: function() {
|
||||
self.message.update({
|
||||
message: "Could not save visualization.",
|
||||
status: "danger"
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
this.portlet.append(this.message.$el);
|
||||
this.portlet.append(this.viewport.$el.addClass("ui-margin-top"));
|
||||
this.setElement(this.portlet.$el);
|
||||
this.listenTo(this.chart, "change", function() {
|
||||
self.render();
|
||||
});
|
||||
},
|
||||
|
||||
/** Show and refresh viewer */
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
$(window).trigger("resize");
|
||||
},
|
||||
|
||||
/** Hide viewer */
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
},
|
||||
|
||||
/** Change title */
|
||||
render: function() {
|
||||
var title = this.chart.get("title");
|
||||
this.portlet.title(title);
|
||||
var exports = (this.chart.definition && this.chart.definition.exports) || [];
|
||||
this.export_button.collection.each(function(model) {
|
||||
model.set("visible", exports.indexOf(model.get("key")) !== -1);
|
||||
});
|
||||
},
|
||||
|
||||
/** Check if chart is ready for export */
|
||||
_wait: function(chart, callback) {
|
||||
if (this.app.deferred.ready()) {
|
||||
callback();
|
||||
} else {
|
||||
this.message.update({
|
||||
message: "Your visualization is currently being processed. Please wait and try again."
|
||||
});
|
||||
}
|
||||
});
|
||||
this.portlet = new Portlet.View({
|
||||
icon : 'fa-bar-chart-o',
|
||||
title: 'Viewport',
|
||||
cls : 'ui-portlet charts-viewer',
|
||||
operations: {
|
||||
edit_button: new Ui.ButtonIcon({
|
||||
icon : 'fa-edit',
|
||||
tooltip : 'Customize this Visualization',
|
||||
title : 'Editor',
|
||||
onclick : function() {
|
||||
self._wait( self.chart, function() {
|
||||
self.app.go( 'editor' );
|
||||
});
|
||||
}
|
||||
}),
|
||||
export_button: this.export_button,
|
||||
save_button: new Ui.ButtonIcon({
|
||||
icon : 'fa-save',
|
||||
tooltip : 'Save this Visualization',
|
||||
title : 'Save',
|
||||
onclick : function() {
|
||||
self.message.update( { message: 'Saving \'' + self.chart.get( 'title' ) + '\'. It will appear in the list of \'Saved Visualizations\'.', status: 'success' } );
|
||||
self.chart.save( { error : function() { self.message.update( { message: 'Could not save visualization.', status: 'danger' } ) } } );
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
this.portlet.append( this.message.$el );
|
||||
this.portlet.append( this.viewport.$el.addClass( 'ui-margin-top' ) );
|
||||
this.setElement( this.portlet.$el );
|
||||
this.listenTo( this.chart, 'change', function() { self.render() } );
|
||||
},
|
||||
|
||||
/** Show and refresh viewer */
|
||||
show: function() {
|
||||
this.$el.show();
|
||||
$( window ).trigger( 'resize' );
|
||||
},
|
||||
|
||||
/** Hide viewer */
|
||||
hide: function() {
|
||||
this.$el.hide();
|
||||
},
|
||||
|
||||
/** Change title */
|
||||
render: function() {
|
||||
var title = this.chart.get( 'title' );
|
||||
this.portlet.title( title );
|
||||
var exports = this.chart.definition && this.chart.definition.exports || [];
|
||||
this.export_button.collection.each( function( model ) {
|
||||
model.set( 'visible', exports.indexOf( model.get( 'key' ) ) !== -1 );
|
||||
});
|
||||
},
|
||||
|
||||
/** Check if chart is ready for export */
|
||||
_wait: function( chart, callback ) {
|
||||
if ( this.app.deferred.ready() ) {
|
||||
callback();
|
||||
} else {
|
||||
this.message.update( { message: 'Your visualization is currently being processed. Please wait and try again.' } );
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
@@ -2,47 +2,53 @@
|
||||
* The viewport creates and manages the dom elements used by the visualization plugins to draw the chart.
|
||||
* This is the last class of the charts core classes before handing control over to the visualization plugins.
|
||||
*/
|
||||
define( [ 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc', 'utils/utils' ], function( Portlet, Ui, Utils ) {
|
||||
define(["mvc/ui/ui-portlet", "mvc/ui/ui-misc", "utils/utils"], function(Portlet, Ui, Utils) {
|
||||
return Backbone.View.extend({
|
||||
initialize: function( app, options ) {
|
||||
initialize: function(app, options) {
|
||||
var self = this;
|
||||
this.app = app;
|
||||
this.chart = this.app.chart;
|
||||
this.options = options;
|
||||
this.setElement( $( '<div/>' ).addClass( 'charts-viewport' )
|
||||
.append( $( '<div/>' ).addClass( 'info' )
|
||||
.append( $( '<span/>' ).addClass( 'icon' ) )
|
||||
.append( $( '<span/>' ).addClass( 'text' ) ) ) );
|
||||
this.$info = this.$( '.info' );
|
||||
this.$icon = this.$( '.icon' );
|
||||
this.$text = this.$( '.text' );
|
||||
this._fullscreen( this.$el, 55 );
|
||||
this._createContainer( 'div' );
|
||||
this.chart.on( 'redraw', function() {
|
||||
self.app.deferred.execute( function( process ) {
|
||||
self._draw( process, self.chart );
|
||||
this.setElement(
|
||||
$("<div/>")
|
||||
.addClass("charts-viewport")
|
||||
.append(
|
||||
$("<div/>")
|
||||
.addClass("info")
|
||||
.append($("<span/>").addClass("icon"))
|
||||
.append($("<span/>").addClass("text"))
|
||||
)
|
||||
);
|
||||
this.$info = this.$(".info");
|
||||
this.$icon = this.$(".icon");
|
||||
this.$text = this.$(".text");
|
||||
this._fullscreen(this.$el, 55);
|
||||
this._createContainer("div");
|
||||
this.chart.on("redraw", function() {
|
||||
self.app.deferred.execute(function(process) {
|
||||
self._draw(process, self.chart);
|
||||
});
|
||||
});
|
||||
this.chart.on( 'set:state', function() {
|
||||
var $container = self.$( '.charts-viewport-container' );
|
||||
this.chart.on("set:state", function() {
|
||||
var $container = self.$(".charts-viewport-container");
|
||||
var $info = self.$info;
|
||||
var $icon = self.$icon;
|
||||
var $text = self.$text;
|
||||
$icon.removeClass();
|
||||
$info.show();
|
||||
$text.html( self.chart.get( 'state_info' ) );
|
||||
var state = self.chart.get( 'state' );
|
||||
switch ( state ) {
|
||||
case 'ok':
|
||||
$text.html(self.chart.get("state_info"));
|
||||
var state = self.chart.get("state");
|
||||
switch (state) {
|
||||
case "ok":
|
||||
$info.hide();
|
||||
$container.show();
|
||||
break;
|
||||
case 'failed':
|
||||
$icon.addClass( 'icon fa fa-warning' );
|
||||
case "failed":
|
||||
$icon.addClass("icon fa fa-warning");
|
||||
$container.hide();
|
||||
break;
|
||||
default:
|
||||
$icon.addClass( 'icon fa fa-spinner fa-spin' );
|
||||
$icon.addClass("icon fa fa-spinner fa-spin");
|
||||
$container.show();
|
||||
}
|
||||
});
|
||||
@@ -59,42 +65,46 @@ define( [ 'mvc/ui/ui-portlet', 'mvc/ui/ui-misc', 'utils/utils' ], function( Port
|
||||
},
|
||||
|
||||
/** Force resize to fullscreen */
|
||||
_fullscreen: function( $el, margin ) {
|
||||
$el.css( 'height', $( window ).height() - margin );
|
||||
$( window ).resize( function() {
|
||||
$el.css( 'height', $( window ).height() - margin );
|
||||
_fullscreen: function($el, margin) {
|
||||
$el.css("height", $(window).height() - margin);
|
||||
$(window).resize(function() {
|
||||
$el.css("height", $(window).height() - margin);
|
||||
});
|
||||
},
|
||||
|
||||
/** A chart may contain multiple sub charts/containers which are created here */
|
||||
_createContainer: function( tag, n ) {
|
||||
tag = tag || 'div';
|
||||
_createContainer: function(tag, n) {
|
||||
tag = tag || "div";
|
||||
n = n || 1;
|
||||
this.$( '.charts-viewport-container' ).remove();
|
||||
this.$(".charts-viewport-container").remove();
|
||||
this.targets = [];
|
||||
for ( var i = 0; i < n; i++ ) {
|
||||
for (var i = 0; i < n; i++) {
|
||||
var container_id = Utils.uid();
|
||||
var container_el = $( '<div/>' ).addClass( 'charts-viewport-container' )
|
||||
.width( parseInt( 100 / n ) + '%' )
|
||||
.append( $( '<' + tag + ' class="charts-viewport-canvas" />' ).attr( 'id', container_id ) );
|
||||
this.$el.append( container_el );
|
||||
this.targets.push( container_id );
|
||||
var container_el = $("<div/>")
|
||||
.addClass("charts-viewport-container")
|
||||
.width(parseInt(100 / n) + "%")
|
||||
.append($("<" + tag + ' class="charts-viewport-canvas" />').attr("id", container_id));
|
||||
this.$el.append(container_el);
|
||||
this.targets.push(container_id);
|
||||
}
|
||||
},
|
||||
|
||||
/** Draws a new chart by loading and executing the corresponding chart wrapper */
|
||||
_draw: function( process, chart ) {
|
||||
_draw: function(process, chart) {
|
||||
var self = this;
|
||||
var n_panels = chart.settings.get( '__use_panels' ) == 'true' ? chart.groups.length : 1;
|
||||
this._createContainer( chart.definition.tag, n_panels );
|
||||
chart.state( 'wait', 'Please wait...' );
|
||||
require( [ 'repository/build/' + chart.get( 'type' ) ], function( ChartView ) {
|
||||
new ChartView( { process: process, chart: chart, dataset: self.app.dataset, targets: self.targets } );
|
||||
}, function( err ) {
|
||||
chart.state( 'failed', 'Please verify that your internet connection works properly. This visualization could not be accessed in the repository. Please contact the Galaxy Team if this error persists.' );
|
||||
console.debug( err );
|
||||
var n_panels = chart.settings.get("__use_panels") == "true" ? chart.groups.length : 1;
|
||||
this._createContainer(chart.definition.tag, n_panels);
|
||||
chart.state("wait", "Please wait...");
|
||||
require(["repository/build/" + chart.get("type")], function(ChartView) {
|
||||
new ChartView({ process: process, chart: chart, dataset: self.app.dataset, targets: self.targets });
|
||||
}, function(err) {
|
||||
chart.state(
|
||||
"failed",
|
||||
"Please verify that your internet connection works properly. This visualization could not be accessed in the repository. Please contact the Galaxy Team if this error persists."
|
||||
);
|
||||
console.debug(err);
|
||||
process.resolve();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,47 +1,47 @@
|
||||
var path = require( 'path' );
|
||||
var root = path.join( __dirname, 'static/repository' );
|
||||
var grunt = require( 'grunt' );
|
||||
var registry_json = grunt.file.readJSON( root + '/registry.json' );
|
||||
var path = require("path");
|
||||
var root = path.join(__dirname, "static/repository");
|
||||
var grunt = require("grunt");
|
||||
var registry_json = grunt.file.readJSON(root + "/registry.json");
|
||||
|
||||
// helper to visit registry values
|
||||
var visit = function( callback ) {
|
||||
for ( var lib in registry_json ) {
|
||||
var plugins = registry_json[ lib ];
|
||||
for ( var i in plugins ) {
|
||||
var plugin = plugins[ i ];
|
||||
callback( lib, plugin );
|
||||
var visit = function(callback) {
|
||||
for (var lib in registry_json) {
|
||||
var plugins = registry_json[lib];
|
||||
for (var i in plugins) {
|
||||
var plugin = plugins[i];
|
||||
callback(lib, plugin);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// identify entries from registry
|
||||
var entry = { registry : root + '/build/registry.tmp.js' };
|
||||
visit( function( lib, plugin ) {
|
||||
if ( !grunt.file.exists( root + '/build/' + lib + '_' + plugin + '.js' ) ) {
|
||||
entry[ lib + '_' + plugin ] = root + '/visualizations/' + lib + '/' + plugin + '/wrapper.js';
|
||||
grunt.log.writeln( 'Adding ' + lib + '_' + plugin + '.' );
|
||||
var entry = { registry: root + "/build/registry.tmp.js" };
|
||||
visit(function(lib, plugin) {
|
||||
if (!grunt.file.exists(root + "/build/" + lib + "_" + plugin + ".js")) {
|
||||
entry[lib + "_" + plugin] = root + "/visualizations/" + lib + "/" + plugin + "/wrapper.js";
|
||||
grunt.log.writeln("Adding " + lib + "_" + plugin + ".");
|
||||
}
|
||||
});
|
||||
|
||||
// build registry file
|
||||
var registry = 'define( [], function() { return {';
|
||||
visit( function( lib, plugin ) {
|
||||
registry += lib + '_' + plugin + ':' + 'require( "visualizations/' + lib + '/' + plugin + '/config" ), ';
|
||||
var registry = "define( [], function() { return {";
|
||||
visit(function(lib, plugin) {
|
||||
registry += lib + "_" + plugin + ":" + 'require( "visualizations/' + lib + "/" + plugin + '/config" ), ';
|
||||
});
|
||||
registry = registry.substr( 0, registry.length - 1 ) + '} } );';
|
||||
grunt.file.write( root + '/build/registry.tmp.js', registry );
|
||||
grunt.log.writeln( 'Writing Registry.' );
|
||||
registry = registry.substr(0, registry.length - 1) + "} } );";
|
||||
grunt.file.write(root + "/build/registry.tmp.js", registry);
|
||||
grunt.log.writeln("Writing Registry.");
|
||||
|
||||
// configure webpack
|
||||
module.exports = {
|
||||
devtool : 'source-map',
|
||||
entry : entry,
|
||||
output : {
|
||||
path : root + '/build',
|
||||
filename : '[name].js',
|
||||
libraryTarget : 'amd'
|
||||
devtool: "source-map",
|
||||
entry: entry,
|
||||
output: {
|
||||
path: root + "/build",
|
||||
filename: "[name].js",
|
||||
libraryTarget: "amd"
|
||||
},
|
||||
resolve : {
|
||||
resolve: {
|
||||
modules: [root]
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,46 +0,0 @@
|
||||
// NOTE: use 'sudo npm install .', then 'grunt' to use this file
|
||||
|
||||
module.exports = function(grunt) {
|
||||
|
||||
grunt.initConfig({
|
||||
pkg: grunt.file.readJSON( 'package.json' ),
|
||||
|
||||
concat: {
|
||||
// concat any js files in the src dir into a single file in the build dir
|
||||
options: {
|
||||
separator: ';\n'
|
||||
},
|
||||
dist: {
|
||||
src : [ 'src/**/*.js' ],
|
||||
dest: 'build/scatterplot-concat.js'
|
||||
}
|
||||
},
|
||||
|
||||
uglify: {
|
||||
// uglify the concat single file directly into the static dir
|
||||
options: {
|
||||
// uncomment these to allow better source mapping during development
|
||||
//mangle : false,
|
||||
//beautify : true
|
||||
},
|
||||
dist: {
|
||||
src : 'build/scatterplot-concat.js',
|
||||
dest: 'static/scatterplot-edit.js'
|
||||
}
|
||||
},
|
||||
|
||||
watch: {
|
||||
// watch for changes in the src dir
|
||||
files: [ 'src/**.js' ],
|
||||
tasks: [ 'default' ]
|
||||
}
|
||||
});
|
||||
|
||||
grunt.loadNpmTasks( 'grunt-contrib-concat' );
|
||||
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
|
||||
grunt.loadNpmTasks( 'grunt-contrib-watch' );
|
||||
|
||||
grunt.registerTask( 'default', [ 'concat', 'uglify' ]);
|
||||
// you can run grunt watch directly:
|
||||
// grunt watch
|
||||
};
|
||||
@@ -1,387 +0,0 @@
|
||||
/* =============================================================================
|
||||
todo:
|
||||
localize
|
||||
import button(display), func(model) - when user doesn't match
|
||||
Move margins into wid/hi calcs (so final svg dims are w/h)
|
||||
Better separation of AJAX in scatterplot.js (maybe pass in function?)
|
||||
Labels should auto fill in chart control when dataset has column_names
|
||||
Allow column selection/config using the peek output as a base for UI
|
||||
Allow setting perPage in chart controls
|
||||
Allow option to auto set width/height based on screen real estate avail.
|
||||
Handle large number of pages better (Known genes hg19)
|
||||
Use d3.nest to allow grouping, pagination/filtration by group (e.g. chromCol)
|
||||
Semantic HTML (figure, caption)
|
||||
Save as SVG/png
|
||||
Does it work w/ Galaxy.Frame?
|
||||
Embedding
|
||||
Small multiples
|
||||
Drag & Drop other splots onto current (redraw with new axis and differentiate the datasets)
|
||||
Remove 'chart' namessave
|
||||
Somehow link out from info box?
|
||||
|
||||
Subclass on specific datatypes? (vcf, cuffdiff, etc.)
|
||||
What can be common/useful to other visualizations?
|
||||
|
||||
============================================================================= */
|
||||
/**
|
||||
* Scatterplot config control UI as a backbone view
|
||||
* handles:
|
||||
* configuring which data will be used
|
||||
* configuring the plot display
|
||||
*/
|
||||
var ScatterplotConfigEditor = Backbone.View.extend({
|
||||
//TODO: !should be a view on a visualization model
|
||||
//logger : console,
|
||||
className : 'scatterplot-control-form',
|
||||
|
||||
/** initialize requires a configuration Object containing a dataset Object */
|
||||
initialize : function( attributes ){
|
||||
if( !this.model ){
|
||||
this.model = new Visualization({ type: 'scatterplot' });
|
||||
}
|
||||
//this.log( this + '.initialize, attributes:', attributes );
|
||||
|
||||
if( !attributes || !attributes.dataset ){
|
||||
throw new Error( "ScatterplotConfigEditor requires a dataset" );
|
||||
}
|
||||
this.dataset = attributes.dataset;
|
||||
//this.log( 'dataset:', this.dataset );
|
||||
|
||||
this.display = new ScatterplotDisplay({
|
||||
dataset : attributes.dataset,
|
||||
model : this.model
|
||||
});
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------------- CONTROLS RENDERING
|
||||
render : function(){
|
||||
//console.log( this + '.render' );
|
||||
// render the tab controls, areas and loading indicator
|
||||
this.$el.empty().append( ScatterplotConfigEditor.templates.mainLayout({}));
|
||||
if( this.model.id ){
|
||||
this.$el.find( '.copy-btn' ).show();
|
||||
this.$el.find( '.save-btn' ).text( 'Update saved' );
|
||||
}
|
||||
this.$el.find( '[title]' ).tooltip();
|
||||
|
||||
// render the tab content
|
||||
this._render_dataControl();
|
||||
this._render_chartControls();
|
||||
this._render_chartDisplay();
|
||||
|
||||
// set up behaviours
|
||||
|
||||
// auto render if given both x, y column choices
|
||||
var config = this.model.get( 'config' );
|
||||
if( this.model.id && _.isFinite( config.xColumn ) && _.isFinite( config.yColumn ) ){
|
||||
this.renderChart();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
/** get an object with arrays keyed with possible column types (numeric, text, all)
|
||||
* and if metadata_column_types is set on the dataset, add the indeces of each
|
||||
* column into the appropriate array.
|
||||
* Used to disable certain columns from being selected for x, y axes.
|
||||
*/
|
||||
_getColumnIndecesByType : function(){
|
||||
//TODO: not sure these contraints are necc. now
|
||||
var types = {
|
||||
numeric : [],
|
||||
text : [],
|
||||
all : []
|
||||
};
|
||||
_.each( this.dataset.metadata_column_types || [], function( type, i ){
|
||||
if( type === 'int' || type === 'float' ){
|
||||
types.numeric.push( i );
|
||||
} else if( type === 'str' || type === 'list' ){
|
||||
types.text.push( i );
|
||||
}
|
||||
types.all.push( i );
|
||||
});
|
||||
if( types.numeric.length < 2 ){
|
||||
types.numeric = [];
|
||||
}
|
||||
//console.log( 'types:', JSON.stringify( types ) );
|
||||
return types;
|
||||
},
|
||||
|
||||
/** controls for which columns are used to plot datapoints (and ids/additional info to attach if desired) */
|
||||
_render_dataControl : function( $where ){
|
||||
$where = $where || this.$el;
|
||||
var editor = this,
|
||||
//column_names = dataset.metadata_column_names || [],
|
||||
config = this.model.get( 'config' ),
|
||||
columnTypes = this._getColumnIndecesByType();
|
||||
|
||||
// render the html
|
||||
var $dataControl = $where.find( '.tab-pane#data-control' );
|
||||
$dataControl.html( ScatterplotConfigEditor.templates.dataControl({
|
||||
peek : this.dataset.peek
|
||||
}));
|
||||
|
||||
$dataControl.find( '.peek' ).peekColumnSelector({
|
||||
controls : [
|
||||
{ label: 'X Column', id: 'xColumn', selected: config.xColumn, disabled: columnTypes.text },
|
||||
{ label: 'Y Column', id: 'yColumn', selected: config.yColumn, disabled: columnTypes.text },
|
||||
{ label: 'ID Column', id: 'idColumn', selected: config.idColumn }
|
||||
]
|
||||
//renameColumns : true
|
||||
|
||||
}).on( 'peek-column-selector.change', function( ev, data ){
|
||||
//console.info( 'new selection:', data );
|
||||
editor.model.set( 'config', data );
|
||||
|
||||
}).on( 'peek-column-selector.rename', function( ev, data ){
|
||||
//console.info( 'new column names', data );
|
||||
});
|
||||
|
||||
$dataControl.find( '[title]' ).tooltip();
|
||||
return $dataControl;
|
||||
},
|
||||
|
||||
/** tab content to control how the chart is rendered (data glyph size, chart size, etc.) */
|
||||
_render_chartControls : function( $where ){
|
||||
//TODO: as controls on actual chart
|
||||
$where = $where || this.$el;
|
||||
var editor = this,
|
||||
config = this.model.get( 'config' ),
|
||||
$chartControls = $where.find( '#chart-control' );
|
||||
|
||||
// ---- skeleton/form for controls
|
||||
$chartControls.html( ScatterplotConfigEditor.templates.chartControl( config ) );
|
||||
//console.debug( '$chartControl:', $chartControls );
|
||||
|
||||
// ---- slider controls
|
||||
// limits for controls (by control/chartConfig id)
|
||||
var controlRanges = {
|
||||
'datapointSize' : { min: 2, max: 10, step: 1 },
|
||||
'width' : { min: 200, max: 800, step: 20 },
|
||||
'height' : { min: 200, max: 800, step: 20 }
|
||||
};
|
||||
|
||||
function onSliderChange(){
|
||||
// set the model config when changed and update the slider output text
|
||||
var $this = $( this ),
|
||||
//note: returns a number nicely enough
|
||||
newVal = $this.slider( 'value' );
|
||||
// parent of slide event target has html5 attr data-config-key
|
||||
editor.model.set( 'config', _.object([[ $this.parent().data( 'config-key' ), newVal ]]) );
|
||||
$this.siblings( '.slider-output' ).text( newVal );
|
||||
}
|
||||
|
||||
//console.debug( 'numeric sliders:', $chartControls.find( '.numeric-slider-input' ) );
|
||||
$chartControls.find( '.numeric-slider-input' ).each( function(){
|
||||
// set up the slider with control ranges, change event; set output text to initial value
|
||||
var $this = $( this ),
|
||||
configKey = $this.attr( 'data-config-key' ),
|
||||
sliderSettings = _.extend( controlRanges[ configKey ], {
|
||||
value : config[ configKey ],
|
||||
change : onSliderChange,
|
||||
slide : onSliderChange
|
||||
});
|
||||
//console.debug( configKey + ' slider settings:', sliderSettings );
|
||||
$this.find( '.slider' ).slider( sliderSettings );
|
||||
$this.children( '.slider-output' ).text( config[ configKey ] );
|
||||
});
|
||||
|
||||
// ---- axes labels
|
||||
var columnNames = this.dataset.metadata_column_names || [];
|
||||
var xLabel = config.xLabel || columnNames[ config.xColumn ] || 'X';
|
||||
var yLabel = config.yLabel || columnNames[ config.yColumn ] || 'Y';
|
||||
// set label inputs to current x, y metadata_column_names (if any)
|
||||
$chartControls.find( 'input[name="X-axis-label"]' ).val( xLabel )
|
||||
.on( 'change', function(){
|
||||
editor.model.set( 'config', { xLabel: $( this ).val() });
|
||||
});
|
||||
$chartControls.find( 'input[name="Y-axis-label"]' ).val( yLabel )
|
||||
.on( 'change', function(){
|
||||
editor.model.set( 'config', { yLabel: $( this ).val() });
|
||||
});
|
||||
|
||||
//console.debug( '$chartControls:', $chartControls );
|
||||
$chartControls.find( '[title]' ).tooltip();
|
||||
return $chartControls;
|
||||
},
|
||||
|
||||
/** render the tab content where the chart is displayed (but not the chart itself) */
|
||||
_render_chartDisplay : function( $where ){
|
||||
$where = $where || this.$el;
|
||||
var $chartDisplay = $where.find( '.tab-pane#chart-display' );
|
||||
this.display.setElement( $chartDisplay );
|
||||
this.display.render();
|
||||
|
||||
$chartDisplay.find( '[title]' ).tooltip();
|
||||
return $chartDisplay;
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------------- EVENTS
|
||||
events : {
|
||||
'change #include-id-checkbox' : 'toggleThirdColumnSelector',
|
||||
'click #data-control .render-button' : 'renderChart',
|
||||
'click #chart-control .render-button' : 'renderChart',
|
||||
'click .save-btn' : 'saveVisualization',
|
||||
//'click .copy-btn' : function(e){ this.model.save(); }
|
||||
},
|
||||
|
||||
saveVisualization : function(){
|
||||
var editor = this;
|
||||
this.model.save()
|
||||
.fail( function( xhr, status, message ){
|
||||
console.error( xhr, status, message );
|
||||
editor.trigger( 'save:error', view );
|
||||
alert( 'Error loading data:\n' + xhr.responseText );
|
||||
})
|
||||
.then( function(){
|
||||
editor.display.render();
|
||||
});
|
||||
},
|
||||
|
||||
toggleThirdColumnSelector : function(){
|
||||
// show/hide the id selector on the data settings panel
|
||||
this.$el.find( 'select[name="idColumn"]' ).parent().toggle();
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------------- CHART/STATS RENDERING
|
||||
renderChart : function(){
|
||||
//console.log( this + '.renderChart' );
|
||||
// fetch the data, (re-)render the chart
|
||||
this.$el.find( '.nav li.disabled' ).removeClass( 'disabled' );
|
||||
this.$el.find( 'ul.nav' ).find( 'a[href="#chart-display"]' ).tab( 'show' );
|
||||
this.display.fetchData();
|
||||
//console.debug( this.display.$el );
|
||||
},
|
||||
|
||||
toString : function(){
|
||||
return 'ScatterplotConfigEditor(' + (( this.dataset )?( this.dataset.id ):( '' )) + ')';
|
||||
}
|
||||
});
|
||||
|
||||
ScatterplotConfigEditor.templates = {
|
||||
// tabbed, main layout for the editor (not used for scatterplot-display)
|
||||
mainLayout : _.template([
|
||||
'<div class="scatterplot-editor tabbable tabs-left">',
|
||||
// tab buttons/headers using Bootstrap
|
||||
'<ul class="nav nav-tabs">',
|
||||
// start with the data controls as the displayed tab
|
||||
'<li class="active">',
|
||||
'<a title="Use this tab to change which data are used"',
|
||||
'href="#data-control" data-toggle="tab">Data Controls</a>',
|
||||
'</li>',
|
||||
'<li>',
|
||||
'<a title="Use this tab to change how the chart is drawn"',
|
||||
'href="#chart-control" data-toggle="tab" >Chart Controls</a>',
|
||||
'</li>',
|
||||
// chart starts as disabled since there's no info yet
|
||||
'<li class="disabled">',
|
||||
'<a title="This tab will display the chart"',
|
||||
'href="#chart-display" data-toggle="tab">Chart</a>',
|
||||
'</li>',
|
||||
// button for saving the visualization config on the server
|
||||
'<li class="file-controls">',
|
||||
'<button class="save-btn btn btn-default">Save</button>',
|
||||
'</li>',
|
||||
'</ul>',
|
||||
|
||||
// data form, chart config form, chart all get their own tab
|
||||
'<div class="tab-content">',
|
||||
// tab for data settings form
|
||||
'<div id="data-control" class="scatterplot-config-control tab-pane active"></div>',
|
||||
|
||||
// tab for chart graphics control form
|
||||
'<div id="chart-control" class="scatterplot-config-control tab-pane"></div>',
|
||||
|
||||
// tab for actual chart
|
||||
'<div id="chart-display" class="scatterplot-display tab-pane"></div>',
|
||||
|
||||
'</div>',
|
||||
'</div>',
|
||||
].join('')),
|
||||
|
||||
// the controls for data selection (this is mostly done with column selector now)
|
||||
// TODO: this could be moved to the main template above
|
||||
// TODO: localize
|
||||
dataControl : _.template([
|
||||
'<p class="help-text">',
|
||||
'Use the following control to change which columns are used by the chart. Click any cell ',
|
||||
'from the last three rows of the table to select the column for the appropriate data. ',
|
||||
'Use the \'Draw\' button to render (or re-render) the chart with the current settings. ',
|
||||
'</p>',
|
||||
|
||||
'<ul class="help-text" style="margin-left: 8px">',
|
||||
'<li><b>X Column</b>: which column values will be used for the x axis of the chart.</li>',
|
||||
'<li><b>Y Column</b>: which column values will be used for the y axis of the chart.</li>',
|
||||
'<li><b>ID Column</b>: an additional column value displayed when the user hovers over a data point. ',
|
||||
'It may be useful to select unique or categorical identifiers here (such as gene ids).',
|
||||
'</li>',
|
||||
'</ul>',
|
||||
|
||||
'<div class="column-selection">',
|
||||
// the only dynamic thing
|
||||
'<pre class="peek"><%= peek %></pre>',
|
||||
'</div>',
|
||||
|
||||
'<p class="help-text help-text-small">',
|
||||
'<b>Note</b>: If it can be determined from the dataset\'s filetype that a column is not numeric, ',
|
||||
'that column choice may be disabled for either the x or y axis.',
|
||||
'</p>',
|
||||
|
||||
'<button class="render-button btn btn-primary active">Draw</button>',
|
||||
].join('')),
|
||||
|
||||
chartControl : _.template([
|
||||
'<p class="help-text">',
|
||||
'Use the following controls to how the chart is displayed. The slide controls can be moved ',
|
||||
'by the mouse or, if the \'handle\' is in focus, your keyboard\'s arrow keys. ',
|
||||
'Move the focus between controls by using the tab or shift+tab keys on your keyboard. ',
|
||||
'Use the \'Draw\' button to render (or re-render) the chart with the current settings. ',
|
||||
'</p>',
|
||||
|
||||
'<div data-config-key="datapointSize" class="form-input numeric-slider-input">',
|
||||
'<label for="datapointSize">Size of data point: </label>',
|
||||
'<div class="slider-output"><%- datapointSize %></div>',
|
||||
'<div class="slider"></div>',
|
||||
'<p class="form-help help-text-small">',
|
||||
'Size of the graphic representation of each data point',
|
||||
'</p>',
|
||||
'</div>',
|
||||
|
||||
'<div data-config-key="width" class="form-input numeric-slider-input">',
|
||||
'<label for="width">Chart width: </label>',
|
||||
'<div class="slider-output"><%- width %></div>',
|
||||
'<div class="slider"></div>',
|
||||
'<p class="form-help help-text-small">',
|
||||
'(not including chart margins and axes)',
|
||||
'</p>',
|
||||
'</div>',
|
||||
|
||||
'<div data-config-key="height" class="form-input numeric-slider-input">',
|
||||
'<label for="height">Chart height: </label>',
|
||||
'<div class="slider-output"><%- height %></div>',
|
||||
'<div class="slider"></div>',
|
||||
'<p class="form-help help-text-small">',
|
||||
'(not including chart margins and axes)',
|
||||
'</p>',
|
||||
'</div>',
|
||||
|
||||
'<div data-config-key="X-axis-label"class="text-input form-input">',
|
||||
'<label for="X-axis-label">Re-label the X axis: </label>',
|
||||
'<input type="text" name="X-axis-label" id="X-axis-label" value="<%- xLabel %>" />',
|
||||
'<p class="form-help help-text-small"></p>',
|
||||
'</div>',
|
||||
|
||||
'<div data-config-key="Y-axis-label" class="text-input form-input">',
|
||||
'<label for="Y-axis-label">Re-label the Y axis: </label>',
|
||||
'<input type="text" name="Y-axis-label" id="Y-axis-label" value="<%- yLabel %>" />',
|
||||
'<p class="form-help help-text-small"></p>',
|
||||
'</div>',
|
||||
|
||||
'<button class="render-button btn btn-primary active">Draw</button>',
|
||||
].join('')),
|
||||
|
||||
// mainLayout : scatterplot.editor,
|
||||
// dataControl : scatterplot.datacontrol,
|
||||
// chartControl : scatterplot.chartcontrol
|
||||
};
|
||||
|
||||
//==============================================================================
|
||||
@@ -1,214 +0,0 @@
|
||||
// =============================================================================
|
||||
/**
|
||||
* Scatterplot display control UI as a backbone view
|
||||
* handles:
|
||||
* fetching the data (if needed)
|
||||
* computing and displaying data stats
|
||||
* controls for pagination of data (if needed)
|
||||
*/
|
||||
var ScatterplotDisplay = Backbone.View.extend({
|
||||
|
||||
initialize : function( attributes ){
|
||||
this.data = null,
|
||||
this.dataset = attributes.dataset;
|
||||
this.lineCount = this.dataset.metadata_data_lines || null;
|
||||
},
|
||||
|
||||
fetchData : function(){
|
||||
this.showLoadingIndicator();
|
||||
//console.debug( 'currPage', this.config.pagination.currPage );
|
||||
var view = this,
|
||||
config = this.model.get( 'config' ),
|
||||
//TODO: very tied to datasets - should be generalized eventually
|
||||
baseUrl = ( window.parent && parent.galaxy_config )? parent.galaxy_config.root : '/',
|
||||
xhr = jQuery.getJSON( baseUrl + 'api/datasets/' + this.dataset.id, {
|
||||
data_type : 'raw_data',
|
||||
provider : 'dataset-column',
|
||||
limit : config.pagination.perPage,
|
||||
offset : ( config.pagination.currPage * config.pagination.perPage )
|
||||
});
|
||||
xhr.done( function( data ){
|
||||
// no need to hide loading indicator, line info will write over that
|
||||
view.data = data.data;
|
||||
view.trigger( 'data:fetched', view );
|
||||
view.renderData();
|
||||
});
|
||||
xhr.fail( function( xhr, status, message ){
|
||||
console.error( xhr, status, message );
|
||||
view.trigger( 'data:error', view );
|
||||
alert( 'Error loading data:\n' + xhr.responseText );
|
||||
});
|
||||
return xhr;
|
||||
},
|
||||
|
||||
showLoadingIndicator : function(){
|
||||
// display the loading indicator over the tab panels if hidden, update message (if passed)
|
||||
this.$el.find( '.scatterplot-data-info' ).html([
|
||||
'<div class="loading-indicator">',
|
||||
'<span class="fa fa-spinner fa-spin"></span>',
|
||||
'<span class="loading-indicator-message">loading...</span>',
|
||||
'</div>'
|
||||
].join( '' ));
|
||||
},
|
||||
|
||||
template : function(){
|
||||
var html = [
|
||||
'<div class="controls clear">',
|
||||
'<div class="right">',
|
||||
'<p class="scatterplot-data-info"></p>',
|
||||
'<button class="stats-toggle-btn">Stats</button>',
|
||||
'<button class="rerender-btn">Redraw</button>',
|
||||
'</div>',
|
||||
'<div class="left">',
|
||||
'<div class="page-control"></div>',
|
||||
'</div>',
|
||||
'</div>',
|
||||
'<svg/>', //TODO: id
|
||||
'<div class="stats-display"></div>'
|
||||
].join( '' );
|
||||
return html;
|
||||
},
|
||||
|
||||
render : function(){
|
||||
this.$el.addClass( 'scatterplot-display' ).html( this.template() );
|
||||
if( this.data ){
|
||||
this.renderData();
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
renderData : function(){
|
||||
this.renderLeftControls();
|
||||
this.renderRightControls();
|
||||
this.renderPlot( this.data );
|
||||
this.getStats();
|
||||
},
|
||||
|
||||
renderLeftControls : function(){
|
||||
var display = this,
|
||||
config = this.model.get( 'config' );
|
||||
|
||||
this.$el.find( '.controls .left .page-control' ).pagination({
|
||||
startingPage : config.pagination.currPage,
|
||||
perPage : config.pagination.perPage,
|
||||
totalDataSize: this.lineCount,
|
||||
currDataSize : this.data.length
|
||||
|
||||
//TODO: move to named function and remove only named
|
||||
}).off().on( 'pagination.page-change', function( event, page ){
|
||||
//console.debug( 'pagination:page-change', page );
|
||||
config.pagination.currPage = page;
|
||||
display.model.set( 'config', { pagination: config.pagination });
|
||||
//console.debug( pagination, display.model.get( 'config' ).pagination );
|
||||
display.resetZoom();
|
||||
display.fetchData();
|
||||
});
|
||||
return this;
|
||||
},
|
||||
|
||||
renderRightControls : function(){
|
||||
var view = this;
|
||||
this.setLineInfo( this.data );
|
||||
// clear prev. handlers due to closure around data
|
||||
this.$el.find( '.stats-toggle-btn' )
|
||||
.off().click( function(){
|
||||
view.toggleStats();
|
||||
});
|
||||
this.$el.find( '.rerender-btn' )
|
||||
.off().click( function(){
|
||||
view.resetZoom();
|
||||
view.renderPlot( this.data );
|
||||
});
|
||||
},
|
||||
|
||||
/** render and show the d3 plot into the svg node of the view */
|
||||
renderPlot : function(){
|
||||
var view = this,
|
||||
$svg = this.$el.find( 'svg' );
|
||||
// turn off stats, clear previous svg, and make it visible
|
||||
this.toggleStats( false );
|
||||
$svg.off().empty().show()
|
||||
// set up listeners for events from plot
|
||||
.on( 'zoom.scatterplot', function( ev, zoom ){
|
||||
//TODO: possibly throttle this
|
||||
//console.debug( 'zoom.scatterplot', zoom.scale, zoom.translate );
|
||||
view.model.set( 'config', zoom );
|
||||
});
|
||||
//TODO: may not be necessary to off/on this more than the initial on
|
||||
// call the sep. d3 function to generate the plot
|
||||
scatterplot( $svg.get( 0 ), this.model.get( 'config' ), this.data );
|
||||
},
|
||||
|
||||
setLineInfo : function( data, contents ){
|
||||
if( data ){
|
||||
var config = this.model.get( 'config' ),
|
||||
totalLines = this.lineCount || 'an unknown total',
|
||||
lineStart = config.pagination.currPage * config.pagination.perPage,
|
||||
lineEnd = lineStart + data.length;
|
||||
this.$el.find( '.controls p.scatterplot-data-info' )
|
||||
.text([ lineStart + 1, 'to', lineEnd, 'of', totalLines ].join( ' ' ));
|
||||
} else {
|
||||
this.$el.find( '.controls p.scatterplot-data-info' ).html( contents || '' );
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
resetZoom : function( scale, translate ){
|
||||
scale = ( scale !== undefined )?( scale ):( 1 );
|
||||
translate = ( translate !== undefined )?( translate ):( [ 0, 0 ] );
|
||||
this.model.set( 'config', { scale: scale, translate: translate } );
|
||||
return this;
|
||||
},
|
||||
|
||||
// ------------------------------------------------------------------------ statistics display
|
||||
/** create a webworker to calc stats for data given */
|
||||
getStats : function(){
|
||||
if( !this.data ){ return; }
|
||||
var view = this,
|
||||
config = this.model.get( 'config' ),
|
||||
meanWorker = new Worker( '/plugins/visualizations/scatterplot/static/worker-stats.js' );
|
||||
meanWorker.postMessage({
|
||||
data : this.data,
|
||||
keys : [ config.xColumn, config.yColumn ]
|
||||
});
|
||||
meanWorker.onerror = function( event ){
|
||||
meanWorker.terminate();
|
||||
};
|
||||
meanWorker.onmessage = function( event ){
|
||||
view.renderStats( event.data );
|
||||
};
|
||||
},
|
||||
|
||||
renderStats : function( stats, error ){
|
||||
//console.debug( 'renderStats:', stats, error );
|
||||
//console.debug( JSON.stringify( stats, null, ' ' ) );
|
||||
var config = this.model.get( 'config' ),
|
||||
$statsTable = this.$el.find( '.stats-display' ),
|
||||
xLabel = config.xLabel, yLabel = config.yLabel,
|
||||
$table = $( '<table/>' ).addClass( 'table' )
|
||||
.append([ '<thead><th></th><th>', xLabel, '</th><th>', yLabel, '</th></thead>' ].join( '' ))
|
||||
.append( _.map( stats, function( stat, key ){
|
||||
return $([ '<tr><td>', key, '</td><td>', stat[0], '</td><td>', stat[1], '</td></tr>' ].join( '' ));
|
||||
}));
|
||||
$statsTable.empty().append( $table );
|
||||
},
|
||||
|
||||
toggleStats : function( showStats ){
|
||||
var $statsDisplay = this.$el.find( '.stats-display' );
|
||||
showStats = ( showStats === undefined )?( $statsDisplay.is( ':hidden' ) ):( showStats );
|
||||
if( showStats ){
|
||||
this.$el.find( 'svg' ).hide();
|
||||
$statsDisplay.show();
|
||||
this.$el.find( '.controls .stats-toggle-btn' ).text( 'Plot' );
|
||||
} else {
|
||||
$statsDisplay.hide();
|
||||
this.$el.find( 'svg' ).show();
|
||||
this.$el.find( '.controls .stats-toggle-btn' ).text( 'Stats' );
|
||||
}
|
||||
},
|
||||
|
||||
toString : function(){
|
||||
return 'ScatterplotView()';
|
||||
}
|
||||
});
|
||||
@@ -1,39 +0,0 @@
|
||||
var ScatterplotModel = Visualization.extend({
|
||||
|
||||
defaults : {
|
||||
type : 'scatterplot',
|
||||
|
||||
config : {
|
||||
// shouldn't be needed for properly saved splots - also often incorrect
|
||||
//xColumn : 0,
|
||||
//yColumn : 1,
|
||||
|
||||
pagination : {
|
||||
currPage : 0,
|
||||
perPage : 3000
|
||||
},
|
||||
|
||||
// graph style
|
||||
width : 400,
|
||||
height : 400,
|
||||
|
||||
margin : {
|
||||
top : 16,
|
||||
right : 16,
|
||||
bottom : 40,
|
||||
left : 54
|
||||
},
|
||||
|
||||
xTicks : 10,
|
||||
xLabel : 'X',
|
||||
yTicks : 10,
|
||||
yLabel : 'Y',
|
||||
|
||||
datapointSize : 4,
|
||||
animDuration : 500,
|
||||
|
||||
scale : 1,
|
||||
translate : [ 0, 0 ]
|
||||
}
|
||||
}
|
||||
});
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,88 +1,92 @@
|
||||
var numericColumnStats = function( data, keys ){
|
||||
var console = console || { debug: function(){} },
|
||||
var numericColumnStats = function(data, keys) {
|
||||
var console = console || { debug: function() {} },
|
||||
stats = {};
|
||||
|
||||
// precondition: keys is an array of keys accessible on each data in data
|
||||
if( !keys || !keys.length ){
|
||||
throw new Error( 'keys is a required parameter and must be an array:' + keys );
|
||||
if (!keys || !keys.length) {
|
||||
throw new Error("keys is a required parameter and must be an array:" + keys);
|
||||
}
|
||||
if( !data || !data.length ){
|
||||
if (!data || !data.length) {
|
||||
return stats;
|
||||
}
|
||||
|
||||
function parseVal( val ){
|
||||
if( val === null ){
|
||||
throw new Error( 'Null value' );
|
||||
function parseVal(val) {
|
||||
if (val === null) {
|
||||
throw new Error("Null value");
|
||||
}
|
||||
val = Number( val );
|
||||
if( isNaN( val ) || !isFinite( val ) ){
|
||||
throw new Error( 'NaN or non-finite number' );
|
||||
val = Number(val);
|
||||
if (isNaN(val) || !isFinite(val)) {
|
||||
throw new Error("NaN or non-finite number");
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
// does this effect the data in the other thread?
|
||||
[ 'min', 'max', 'sum', 'mean', 'median', 'count' ].forEach( function( name, i ){
|
||||
stats[ name ] = new Array( keys.length );
|
||||
["min", "max", "sum", "mean", "median", "count"].forEach(function(name, i) {
|
||||
stats[name] = new Array(keys.length);
|
||||
});
|
||||
|
||||
var keyIndex = 0,
|
||||
separatedCols = new Array( keys.length );
|
||||
keys.forEach( function( key, keyIndex ){
|
||||
stats.min[ keyIndex ] = 0;
|
||||
stats.max[ keyIndex ] = 0;
|
||||
stats.sum[ keyIndex ] = 0;
|
||||
separatedCols[ keyIndex ] = [];
|
||||
separatedCols = new Array(keys.length);
|
||||
keys.forEach(function(key, keyIndex) {
|
||||
stats.min[keyIndex] = 0;
|
||||
stats.max[keyIndex] = 0;
|
||||
stats.sum[keyIndex] = 0;
|
||||
separatedCols[keyIndex] = [];
|
||||
});
|
||||
|
||||
// work backwards to prevent co-modification problems while splitting up data into columns
|
||||
for( var dataIndex=( data.length - 1 ); dataIndex>=0; dataIndex-=1 ){
|
||||
var datum = data.pop( dataIndex );
|
||||
for (var dataIndex = data.length - 1; dataIndex >= 0; dataIndex -= 1) {
|
||||
var datum = data.pop(dataIndex);
|
||||
|
||||
for( keyIndex=0; keyIndex<keys.length; keyIndex+=1 ){
|
||||
var key = keys[ keyIndex ],
|
||||
datumColVal = datum[ key ];
|
||||
for (keyIndex = 0; keyIndex < keys.length; keyIndex += 1) {
|
||||
var key = keys[keyIndex],
|
||||
datumColVal = datum[key];
|
||||
|
||||
try {
|
||||
//NOTE: parsing value as number
|
||||
datumColVal = parseVal( datumColVal );
|
||||
} catch( e ){
|
||||
datumColVal = parseVal(datumColVal);
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// separate the columns
|
||||
separatedCols[ keyIndex ].unshift( datumColVal );
|
||||
separatedCols[keyIndex].unshift(datumColVal);
|
||||
// get the other stats
|
||||
stats.min[ keyIndex ] = Math.min( stats.min[ keyIndex ], datumColVal );
|
||||
stats.max[ keyIndex ] = Math.max( stats.max[ keyIndex ], datumColVal );
|
||||
stats.sum[ keyIndex ] += datumColVal;
|
||||
stats.min[keyIndex] = Math.min(stats.min[keyIndex], datumColVal);
|
||||
stats.max[keyIndex] = Math.max(stats.max[keyIndex], datumColVal);
|
||||
stats.sum[keyIndex] += datumColVal;
|
||||
}
|
||||
}
|
||||
|
||||
// get counts, mean, median
|
||||
function comparator( a, b ){
|
||||
if( a < b ){ return -1; }
|
||||
if( a < b ){ return 1; }
|
||||
function comparator(a, b) {
|
||||
if (a < b) {
|
||||
return -1;
|
||||
}
|
||||
if (a < b) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
for( keyIndex=0; keyIndex<keys.length; keyIndex+=1 ){
|
||||
var count = separatedCols[ keyIndex ].length,
|
||||
sum = stats.sum[ keyIndex ];
|
||||
stats.count[ keyIndex ] = count;
|
||||
stats.mean[ keyIndex ] = ( sum / count );
|
||||
for (keyIndex = 0; keyIndex < keys.length; keyIndex += 1) {
|
||||
var count = separatedCols[keyIndex].length,
|
||||
sum = stats.sum[keyIndex];
|
||||
stats.count[keyIndex] = count;
|
||||
stats.mean[keyIndex] = sum / count;
|
||||
|
||||
// sort columns for median
|
||||
separatedCols[ keyIndex ].sort( comparator );
|
||||
separatedCols[keyIndex].sort(comparator);
|
||||
|
||||
// odd count -> straight forward median
|
||||
var middleDataIndex = Math.floor( count / 2 );
|
||||
if( count % 2 === 1 ){
|
||||
stats.median[ keyIndex ] = separatedCols[ keyIndex ][ middleDataIndex ];
|
||||
var middleDataIndex = Math.floor(count / 2);
|
||||
if (count % 2 === 1) {
|
||||
stats.median[keyIndex] = separatedCols[keyIndex][middleDataIndex];
|
||||
} else {
|
||||
var middleValA = separatedCols[ keyIndex ][ middleDataIndex ],
|
||||
middleValB = separatedCols[ keyIndex ][( middleDataIndex + 1 )];
|
||||
stats.median[ keyIndex ] = ( middleValA + middleValB ) / 2;
|
||||
var middleValA = separatedCols[keyIndex][middleDataIndex],
|
||||
middleValB = separatedCols[keyIndex][middleDataIndex + 1];
|
||||
stats.median[keyIndex] = (middleValA + middleValB) / 2;
|
||||
}
|
||||
}
|
||||
return stats;
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,5 +1,5 @@
|
||||
onmessage = function( event ){
|
||||
importScripts( 'numeric-column-stats.js' );
|
||||
postMessage( numericColumnStats( event.data.data, event.data.keys ) );
|
||||
onmessage = function(event) {
|
||||
importScripts("numeric-column-stats.js");
|
||||
postMessage(numericColumnStats(event.data.data, event.data.keys));
|
||||
self.close();
|
||||
};
|
||||
|
||||
@@ -24,33 +24,25 @@ ${h.stylesheet_link( root + 'plugins/visualizations/scatterplot/static/scatterpl
|
||||
|
||||
## ----------------------------------------------------------------------------
|
||||
<script type="text/javascript">
|
||||
// TODO: blah
|
||||
window.Galaxy = { root: '${ root }' };
|
||||
</script>
|
||||
${h.js( 'libs/jquery/jquery',
|
||||
'libs/jquery/jquery.migrate',
|
||||
'libs/jquery/jquery-ui',
|
||||
'libs/bootstrap',
|
||||
'libs/underscore',
|
||||
'libs/backbone',
|
||||
'libs/d3',
|
||||
'ui/peek-column-selector',
|
||||
'ui/pagination',
|
||||
'mvc/visualization/visualization-model' )}
|
||||
|
||||
${h.javascript_link( root + 'plugins/visualizations/scatterplot/static/scatterplot-edit.js' )}
|
||||
'libs/d3')}
|
||||
${h.javascript_link( root + 'plugins/visualizations/scatterplot/static/scatterplot.bundle.js' )}
|
||||
|
||||
<script type="text/javascript">
|
||||
function getModel(){
|
||||
return new ScatterplotModel({
|
||||
id : ${h.dumps( visualization_id )} || undefined,
|
||||
title : "${title or default_title}",
|
||||
config : ${h.dumps( config, indent=2 )}
|
||||
});
|
||||
}
|
||||
function getHDAJSON(){
|
||||
return ${h.dumps( trans.security.encode_dict_ids( hda.to_dict() ), indent=2 )};
|
||||
}
|
||||
function getModel(){
|
||||
return new ScatterplotModel({
|
||||
id : ${h.dumps( visualization_id )} || undefined,
|
||||
title : "${title or default_title}",
|
||||
config : ${h.dumps( config, indent=2 )}
|
||||
});
|
||||
}
|
||||
function getHDAJSON(){
|
||||
return ${h.dumps( trans.security.encode_dict_ids( hda.to_dict() ), indent=2 )};
|
||||
}
|
||||
window.jQuery = window.jquery = window.$;
|
||||
</script>
|
||||
|
||||
</head>
|
||||
@@ -73,8 +65,6 @@ function getHDAJSON(){
|
||||
embedded: "${embedded}"
|
||||
}).render();
|
||||
display.fetchData();
|
||||
//window.model = model;
|
||||
//window.display = display;
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
var path = require("path");
|
||||
var croot = path.resolve(__dirname, "../../../../");
|
||||
var webpack = require("webpack");
|
||||
var lroot = path.resolve(croot, "client/galaxy/scripts/libs");
|
||||
|
||||
module.exports = {
|
||||
entry: path.resolve(__dirname, "./src/scatterplot.js"),
|
||||
output: {
|
||||
path: path.resolve(__dirname, "static"),
|
||||
filename: "scatterplot.bundle.js"
|
||||
},
|
||||
resolve: {
|
||||
modules: [path.resolve(croot, "client/galaxy/scripts"), path.resolve(croot, "client/node_modules")],
|
||||
alias: {
|
||||
jquery: path.join(lroot, "jquery/jquery"),
|
||||
underscore: path.join(lroot, "underscore.js"),
|
||||
backbone: path.join(lroot, "backbone.js"),
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: [/(node_modules|bower_components)/, lroot],
|
||||
loader: "babel-loader"
|
||||
}
|
||||
]
|
||||
},
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
jquery: "jquery",
|
||||
jQuery: "jquery",
|
||||
$: "jquery"
|
||||
})
|
||||
]
|
||||
};
|
||||
@@ -33,7 +33,6 @@ log = logging.getLogger(__name__)
|
||||
class Binary(data.Data):
|
||||
"""Binary data"""
|
||||
edam_format = "format_2333"
|
||||
unsniffable_binary_formats = []
|
||||
|
||||
@staticmethod
|
||||
def register_sniffable_binary_format(data_type, ext, type_class):
|
||||
@@ -42,11 +41,8 @@ class Binary(data.Data):
|
||||
|
||||
@staticmethod
|
||||
def register_unsniffable_binary_ext(ext):
|
||||
Binary.unsniffable_binary_formats.append(ext.lower())
|
||||
|
||||
@staticmethod
|
||||
def is_ext_unsniffable(ext):
|
||||
return ext in Binary.unsniffable_binary_formats
|
||||
"""Deprecated method."""
|
||||
pass
|
||||
|
||||
def set_peek(self, dataset, is_multi_byte=False):
|
||||
"""Set the peek and blurb text"""
|
||||
@@ -93,9 +89,6 @@ class Ab1(Binary):
|
||||
return "Binary ab1 sequence file (%s)" % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
Binary.register_unsniffable_binary_ext("ab1")
|
||||
|
||||
|
||||
class Idat(Binary):
|
||||
"""Binary data in idat format"""
|
||||
file_ext = "idat"
|
||||
@@ -164,9 +157,6 @@ class CompressedArchive(Binary):
|
||||
return "Compressed binary file (%s)" % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
Binary.register_unsniffable_binary_ext("compressed_archive")
|
||||
|
||||
|
||||
class CompressedZipArchive(CompressedArchive):
|
||||
"""
|
||||
Class describing an compressed binary file
|
||||
@@ -189,9 +179,6 @@ class CompressedZipArchive(CompressedArchive):
|
||||
return "Compressed zip file (%s)" % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
Binary.register_unsniffable_binary_ext("zip")
|
||||
|
||||
|
||||
class GenericAsn1Binary(Binary):
|
||||
"""Class for generic ASN.1 binary format"""
|
||||
file_ext = "asn1-binary"
|
||||
@@ -199,9 +186,6 @@ class GenericAsn1Binary(Binary):
|
||||
edam_data = "data_0849"
|
||||
|
||||
|
||||
Binary.register_unsniffable_binary_ext("asn1-binary")
|
||||
|
||||
|
||||
@dataproviders.decorators.has_dataproviders
|
||||
class Bam(Binary):
|
||||
"""Class describing a BAM binary file"""
|
||||
@@ -929,9 +913,6 @@ class Scf(Binary):
|
||||
return "Binary scf sequence file (%s)" % (nice_size(dataset.get_size()))
|
||||
|
||||
|
||||
Binary.register_unsniffable_binary_ext("scf")
|
||||
|
||||
|
||||
class Sff(Binary):
|
||||
""" Standard Flowgram Format (SFF) """
|
||||
edam_format = "format_3284"
|
||||
|
||||
@@ -92,9 +92,6 @@ class HmmerPress(Binary):
|
||||
self.add_composite_file('model.hmm.h3p', is_binary=True)
|
||||
|
||||
|
||||
Binary.register_unsniffable_binary_ext("hmmpress")
|
||||
|
||||
|
||||
class Stockholm_1_0(Text):
|
||||
edam_data = "data_0863"
|
||||
edam_format = "format_1961"
|
||||
|
||||
@@ -465,6 +465,10 @@ class Registry(object):
|
||||
if sniffer_class not in sniffer_elem_classes:
|
||||
self.sniffer_elems.append(elem)
|
||||
|
||||
def is_extension_unsniffable_binary(self, ext):
|
||||
datatype = self.get_datatype_by_extension(ext)
|
||||
return datatype is not None and isinstance(datatype, binary.Binary) and not hasattr(datatype, 'sniff')
|
||||
|
||||
def get_datatype_class_by_name(self, name):
|
||||
"""
|
||||
Return the datatype class where the datatype's `type` attribute
|
||||
|
||||
@@ -16,7 +16,6 @@ import zipfile
|
||||
from six import text_type
|
||||
|
||||
from galaxy import util
|
||||
from galaxy.datatypes.binary import Binary
|
||||
from galaxy.util import compression_utils
|
||||
from galaxy.util.checkers import (
|
||||
check_binary,
|
||||
@@ -478,7 +477,7 @@ def handle_uploaded_dataset_file(filename, datatypes_registry, ext='auto'):
|
||||
ext = guess_ext(filename, sniff_order=datatypes_registry.sniff_order)
|
||||
|
||||
if check_binary(filename):
|
||||
if not Binary.is_ext_unsniffable(ext) and not datatypes_registry.get_datatype_by_extension(ext).sniff(filename):
|
||||
if not datatypes_registry.is_extension_unsniffable_binary(ext) and not datatypes_registry.get_datatype_by_extension(ext).sniff(filename):
|
||||
raise InappropriateDatasetContentError('The binary uploaded file contains inappropriate content.')
|
||||
elif check_html(filename):
|
||||
raise InappropriateDatasetContentError('The uploaded file contains inappropriate HTML content.')
|
||||
|
||||
@@ -45,7 +45,7 @@ class SentryPlugin(ErrorPlugin):
|
||||
def submit_report(self, dataset, job, tool, **kwargs):
|
||||
"""Submit the error report to sentry
|
||||
"""
|
||||
if self.sentry_client:
|
||||
if self.sentry:
|
||||
user = job.get_user()
|
||||
extra = {
|
||||
'info': job.info,
|
||||
|
||||
@@ -56,7 +56,8 @@ class FilterFactory(object):
|
||||
for filter in filters:
|
||||
if validate is None or filter in validate or filter in self.default_filters:
|
||||
filter_function = self.build_filter_function(filter)
|
||||
toolbox_filters[key].append(filter_function)
|
||||
if filter_function is not None:
|
||||
toolbox_filters[key].append(filter_function)
|
||||
else:
|
||||
log.warning("Refusing to load %s filter '%s' which is not defined in config", key, filter)
|
||||
return toolbox_filters
|
||||
@@ -82,12 +83,11 @@ class FilterFactory(object):
|
||||
try:
|
||||
__import__(full_module_name)
|
||||
except ImportError:
|
||||
# log.debug("Failed to load module %s using sys.path %s", full_module_name, sys.path, exc_info=True)
|
||||
continue
|
||||
module = sys.modules[full_module_name]
|
||||
if hasattr(module, function_name):
|
||||
return getattr(module, function_name)
|
||||
raise Exception("Failed to find filter %s.%s" % (module_name, function_name))
|
||||
log.warning("Failed to load module for '%s.%s'.", module_name, function_name, exc_info=True)
|
||||
|
||||
|
||||
# Stock Filter Functions
|
||||
|
||||
@@ -675,10 +675,11 @@ class UserAPIController(BaseAPIController, UsesTagsMixin, CreatesUsersMixin, Cre
|
||||
if name in filter_types:
|
||||
saved_values[name] = listify(value, do_strip=True)
|
||||
inputs = []
|
||||
errors = {}
|
||||
factory = FilterFactory(trans.app.toolbox)
|
||||
for filter_type in filter_types:
|
||||
self._add_filter_inputs(factory, filter_types, inputs, filter_type, saved_values)
|
||||
return {'inputs': inputs}
|
||||
self._add_filter_inputs(factory, filter_types, inputs, errors, filter_type, saved_values)
|
||||
return {'inputs': inputs, 'errors': errors}
|
||||
|
||||
@expose_api
|
||||
def set_toolbox_filters(self, trans, id, payload={}, **kwd):
|
||||
@@ -690,36 +691,37 @@ class UserAPIController(BaseAPIController, UsesTagsMixin, CreatesUsersMixin, Cre
|
||||
for filter_type in filter_types:
|
||||
new_filters = []
|
||||
for prefixed_name in payload:
|
||||
prefix = filter_type + '|'
|
||||
if prefixed_name.startswith(filter_type):
|
||||
if payload.get(prefixed_name) == 'true' and prefixed_name.startswith(filter_type):
|
||||
prefix = filter_type + '|'
|
||||
new_filters.append(prefixed_name[len(prefix):])
|
||||
user.preferences[filter_type] = ','.join(new_filters)
|
||||
trans.sa_session.add(user)
|
||||
trans.sa_session.flush()
|
||||
return {'message': 'Toolbox filters have been saved.'}
|
||||
|
||||
def _add_filter_inputs(self, factory, filter_types, inputs, filter_type, saved_values):
|
||||
def _add_filter_inputs(self, factory, filter_types, inputs, errors, filter_type, saved_values):
|
||||
filter_inputs = list()
|
||||
filter_values = saved_values.get(filter_type, [])
|
||||
filter_config = filter_types[filter_type]['config']
|
||||
filter_title = filter_types[filter_type]['title']
|
||||
for filter_name in filter_config:
|
||||
function = factory.build_filter_function(filter_name)
|
||||
if function is None:
|
||||
errors['%s|%s' % (filter_type, filter_name)] = 'Filter function not found.'
|
||||
filter_inputs.append({
|
||||
'type': 'boolean',
|
||||
'name': filter_name,
|
||||
'label': filter_name,
|
||||
'help': docstring_trim(function.__doc__) or 'No description available.',
|
||||
'value': 'true' if filter_name in filter_values else 'false',
|
||||
'ignore': 'false'
|
||||
'value': 'true' if filter_name in filter_values else 'false'
|
||||
})
|
||||
if filter_inputs:
|
||||
inputs.append({'type': 'section', 'title': filter_title, 'name': filter_type, 'expanded': True, 'inputs': filter_inputs})
|
||||
|
||||
def _get_filter_types(self, trans):
|
||||
return odict([('toolbox_tool_filters', {'title': 'Tools', 'config': trans.app.config.user_tool_filters}),
|
||||
('toolbox_tool_section_filters', {'title': 'Sections', 'config': trans.app.config.user_tool_section_filters}),
|
||||
('toolbox_tool_label_filters', {'title': 'Labels', 'config': trans.app.config.user_tool_label_filters})])
|
||||
('toolbox_section_filters', {'title': 'Sections', 'config': trans.app.config.user_tool_section_filters}),
|
||||
('toolbox_label_filters', {'title': 'Labels', 'config': trans.app.config.user_tool_label_filters})])
|
||||
|
||||
@expose_api
|
||||
def api_key(self, trans, id, payload={}, **kwd):
|
||||
|
||||
@@ -173,13 +173,13 @@ class AdminToolshed(AdminGalaxy):
|
||||
@web.require_admin
|
||||
def browse_toolsheds(self, trans, **kwd):
|
||||
app = {
|
||||
'jscript': "adminToolshedApp"
|
||||
'jscript': "adminToolshed"
|
||||
}
|
||||
return trans.fill_template('galaxy.panels.mako',
|
||||
config={
|
||||
'title': 'Galaxy Tool Sheds',
|
||||
'app': app,
|
||||
'bundle': 'adminToolshed'})
|
||||
'bundle': 'extended'})
|
||||
|
||||
@web.expose
|
||||
@web.require_admin
|
||||
|
||||
@@ -13,10 +13,10 @@ class Library(BaseUIController):
|
||||
def list(self, trans, **kwd):
|
||||
# define app configuration for generic mako template
|
||||
app = {
|
||||
'jscript' : "libraryApp"
|
||||
'jscript' : "library"
|
||||
}
|
||||
return trans.fill_template('galaxy.panels.mako',
|
||||
config={
|
||||
'title': 'Data Libraries',
|
||||
'app': app,
|
||||
'bundle': 'library'})
|
||||
'bundle': 'extended'})
|
||||
|
||||
@@ -736,7 +736,7 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
"""
|
||||
|
||||
# define app configuration
|
||||
app = {"jscript" : "tracksterApp"}
|
||||
app = {"jscript" : "trackster"}
|
||||
|
||||
# get dataset to add
|
||||
id = kwargs.get("id", None)
|
||||
@@ -780,7 +780,7 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
}
|
||||
|
||||
# fill template
|
||||
return trans.fill_template('galaxy.panels.mako', config={'right_panel': True, 'app': app, 'bundle': 'viz'})
|
||||
return trans.fill_template('galaxy.panels.mako', config={'right_panel': True, 'app': app, 'bundle': 'extended'})
|
||||
|
||||
@web.expose
|
||||
def circster(self, trans, id=None, hda_ldda=None, dataset_id=None, dbkey=None):
|
||||
@@ -836,13 +836,13 @@ class VisualizationController(BaseUIController, SharableMixin, UsesVisualization
|
||||
|
||||
# define app configuration for generic mako template
|
||||
app = {
|
||||
'jscript' : "circsterApp",
|
||||
'jscript' : "circster",
|
||||
'viz_config' : viz_config,
|
||||
'genome' : genome
|
||||
}
|
||||
|
||||
# fill template
|
||||
return trans.fill_template('galaxy.panels.mako', config={'app' : app, 'bundle': 'viz'})
|
||||
return trans.fill_template('galaxy.panels.mako', config={'app' : app, 'bundle': 'extended'})
|
||||
|
||||
@web.expose
|
||||
def sweepster(self, trans, id=None, hda_ldda=None, dataset_id=None, regions=None):
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define("mvc/form/form-data",["exports","utils/utils"],function(t,a){"use strict";Object.defineProperty(t,"__esModule",{value:!0});!function(t){t&&t.__esModule}(a);var e=Backbone.Model.extend({initialize:function(t){this.app=t},checksum:function(){var t="",a=this;return this.app.section.$el.find(".section-row").each(function(){var e=$(this).attr("id"),i=a.app.field_list[e];i&&(t+=e+":"+JSON.stringify(i.value&&i.value())+":"+i.collapsed+";")}),t},create:function(){function t(t,a,i){e.flat_dict[t]=a,r[t]=i,e.app.element_list[a]&&e.app.element_list[a].$el.attr("tour_id",t)}function a(n,r){for(var s in r){var o=r[s];if(o.input){var c=o.input,l=n;switch(""!=n&&(l+="|"),l+=c.name,c.type){case"repeat":var u=[],f=null;for(var p in o){var d=p.indexOf("section-");-1!=d&&(d+="section-".length,u.push(parseInt(p.substr(d))),f||(f=p.substr(0,d)))}u.sort(function(t,a){return t-a});s=0;for(var v in u)a(l+"_"+s++,o[f+u[v]]);break;case"conditional":h=e.app.field_list[c.id].value();t(l+"|"+c.test_param.name,c.id,h);var _=i(c,h);-1!=_&&a(l,r[c.id+"-section-"+_]);break;case"section":a(!c.flat&&l||"",o);break;default:var m=e.app.field_list[c.id];if(m&&m.value){var h=m.value();if((void 0===c.ignore||c.ignore!=h)&&(m.collapsed&&c.collapsible_value&&(h=c.collapsible_value),t(l,c.id,h),c.payload))for(var b in c.payload)t(b,c.id,c.payload[b])}}}}}var e=this,n={};this._iterate(this.app.section.$el,n);var r={};return this.flat_dict={},a("",n),r},match:function(t){return this.flat_dict&&this.flat_dict[t]},matchCase:function(t,a){return i(t,a)},matchModel:function(t,a){var e=this;n(t.inputs,function(t,i){e.flat_dict[i]&&a(t,e.flat_dict[i])})},matchResponse:function(t){function a(t,n){if("string"==typeof n){var r=i.flat_dict[t];r&&(e[r]=n)}else for(var s in n){var o=s;if(""!==t){var c="|";n instanceof Array&&(c="_"),o=t+c+o}a(o,n[s])}}var e={},i=this;return a("",t),e},_iterate:function(t,a){var e=this;$(t).children().each(function(){var t=this,i=$(t).attr("id");if($(t).hasClass("section-row")){var n=e.app.input_list[i];a[i]=n&&{input:n}||{},e._iterate(t,a[i])}else e._iterate(t,a)})}}),i=function(t,a){"boolean"==t.test_param.type&&(a="true"==a?t.test_param.truevalue||"true":t.test_param.falsevalue||"false");for(var e in t.cases)if(t.cases[e].value==a)return e;return-1},n=function t(a,e,n,r){r=$.extend(!0,{},r),_.each(a,function(t){t&&t.type&&t.name&&(r[t.name]=t)});for(var s in a){var o=a[s];o.name=o.name||s;var c=n?n+"|"+o.name:o.name;switch(o.type){case"repeat":_.each(o.cache,function(a,i){t(a,e,c+"_"+i,r)});break;case"conditional":if(o.test_param){e(o.test_param,c+"|"+o.test_param.name,r);var l=i(o,o.test_param.value);-1!=l?t(o.cases[l].inputs,e,c,r):Galaxy.emit.debug("form-data::visitInputs() - Invalid case for "+c+".")}else Galaxy.emit.debug("form-data::visitInputs() - Conditional test parameter missing for "+c+".");break;case"section":t(o.inputs,e,c,r);break;default:e(o,c,r)}}};t.default={Manager:e,visitInputs:n}});
|
||||
define("mvc/form/form-data",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var a=t.Manager=Backbone.Model.extend({initialize:function(t){this.app=t},checksum:function(){var t="",a=this;return this.app.section.$el.find(".section-row").each(function(){var e=$(this).attr("id"),i=a.app.field_list[e];i&&(t+=e+":"+JSON.stringify(i.value&&i.value())+":"+i.collapsed+";")}),t},create:function(){function t(t,a,e){i.flat_dict[t]=a,r[t]=e,i.app.element_list[a]&&i.app.element_list[a].$el.attr("tour_id",t)}function a(n,r){for(var s in r){var c=r[s];if(c.input){var o=c.input,l=n;switch(""!==n&&(l+="|"),l+=o.name,o.type){case"repeat":var u=[],f=null;for(var p in c){var v=p.indexOf("section-");-1!=v&&(v+="section-".length,u.push(parseInt(p.substr(v))),f||(f=p.substr(0,v)))}u.sort(function(t,a){return t-a}),s=0;for(var d in u)a(l+"_"+s++,c[f+u[d]]);break;case"conditional":var _=i.app.field_list[o.id].value();t(l+"|"+o.test_param.name,o.id,_);var m=e(o,_);-1!=m&&a(l,r[o.id+"-section-"+m]);break;case"section":a(!o.flat&&l||"",c);break;default:var h=i.app.field_list[o.id];if(h&&h.value&&(_=h.value(),(void 0===o.ignore||o.ignore!=_)&&(h.collapsed&&o.collapsible_value&&(_=o.collapsible_value),t(l,o.id,_),o.payload)))for(var b in o.payload)t(b,o.id,o.payload[b])}}}}var i=this,n={};this._iterate(this.app.section.$el,n);var r={};return this.flat_dict={},a("",n),r},match:function(t){return this.flat_dict&&this.flat_dict[t]},matchCase:function(t,a){return e(t,a)},matchModel:function(t,a){var e=this;i(t.inputs,function(t,i){e.flat_dict[i]&&a(t,e.flat_dict[i])})},matchResponse:function(t){function a(t,n){if("string"==typeof n){var r=i.flat_dict[t];r&&(e[r]=n)}else for(var s in n){var c=s;if(""!==t){var o="|";n instanceof Array&&(o="_"),c=t+o+c}a(c,n[s])}}var e={},i=this;return a("",t),e},_iterate:function(t,a){var e=this;$(t).children().each(function(){var t=this,i=$(t).attr("id");if($(t).hasClass("section-row")){var n=e.app.input_list[i];a[i]=n&&{input:n}||{},e._iterate(t,a[i])}else e._iterate(t,a)})}}),e=function(t,a){"boolean"==t.test_param.type&&(a="true"==a?t.test_param.truevalue||"true":t.test_param.falsevalue||"false");for(var e in t.cases)if(t.cases[e].value==a)return e;return-1};t.matchCase=e;var i=t.visitInputs=function t(a,i,n,r){r=$.extend(!0,{},r),_.each(a,function(t){t&&t.type&&t.name&&(r[t.name]=t)});for(var s in a){var c=a[s];c.name=c.name||s;var o=n?n+"|"+c.name:c.name;switch(c.type){case"repeat":_.each(c.cache,function(a,e){t(a,i,o+"_"+e,r)});break;case"conditional":if(c.test_param){i(c.test_param,o+"|"+c.test_param.name,r);var l=e(c,c.test_param.value);-1!=l?t(c.cases[l].inputs,i,o,r):Galaxy.emit.debug("form-data::visitInputs() - Invalid case for "+o+".")}else Galaxy.emit.debug("form-data::visitInputs() - Conditional test parameter missing for "+o+".");break;case"section":t(c.inputs,i,o,r);break;default:i(c,o,r)}}};t.default={Manager:a,visitInputs:i}});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/form/form-repeat",["exports","utils/utils","mvc/ui/ui-portlet","mvc/ui/ui-misc"],function(t,e,i,n){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0});var s=o(e),l=o(i),a=o(n),d=Backbone.View.extend({initialize:function(t){this.list={},this.options=s.default.merge(t,{title:"Repeat",empty_text:"Not available.",max:null,min:null}),this.button_new=new a.default.ButtonIcon({icon:"fa-plus",title:"Insert "+this.options.title,tooltip:"Add new "+this.options.title+" block",cls:"ui-button-icon ui-clear-float form-repeat-add",onclick:function(){t.onnew&&t.onnew()}}),this.setElement($("<div/>").append(this.$list=$("<div/>")).append($("<div/>").append(this.button_new.$el)))},size:function(){return _.size(this.list)},add:function(t){if(t.id&&!this.list[t.id]){var e=new a.default.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this repeat block",cls:"ui-button-icon-plain form-repeat-delete",onclick:function(){t.ondel&&t.ondel()}}),i=new l.default.View({id:t.id,title:"placeholder",cls:t.cls||"ui-portlet-repeat",operations:{button_delete:e}});i.append(t.$el),i.$el.addClass("section-row").hide(),this.list[t.id]=i,this.$list.append(i.$el.fadeIn("fast")),this.options.max>0&&this.size()>=this.options.max&&this.button_new.disable(),this._refresh()}else Galaxy.emit.debug("form-repeat::add()","Duplicate or invalid repeat block id.")},del:function(t){this.list[t]?(this.$list.find("#"+t).remove(),delete this.list[t],this.button_new.enable(),this._refresh()):Galaxy.emit.debug("form-repeat::del()","Invalid repeat block id.")},delAll:function(){for(var t in this.list)this.del(t)},hideOptions:function(){this.button_new.$el.hide(),_.each(this.list,function(t){t.hideOperation("button_delete")}),_.isEmpty(this.list)&&this.$el.append($("<div/>").addClass("ui-form-info").html(this.options.empty_text))},_refresh:function(){var t=0;for(var e in this.list){var i=this.list[e];i.title(++t+": "+this.options.title),i[this.size()>this.options.min?"showOperation":"hideOperation"]("button_delete")}}});t.default={View:d}});
|
||||
define("mvc/form/form-repeat",["exports","utils/utils","mvc/ui/ui-portlet","mvc/ui/ui-misc"],function(t,e,i,n){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0}),t.View=void 0;var s=o(e),l=o(i),a=o(n),d=t.View=Backbone.View.extend({initialize:function(t){this.list={},this.options=s.default.merge(t,{title:"Repeat",empty_text:"Not available.",max:null,min:null}),this.button_new=new a.default.ButtonIcon({icon:"fa-plus",title:"Insert "+this.options.title,tooltip:"Add new "+this.options.title+" block",cls:"ui-button-icon ui-clear-float form-repeat-add",onclick:function(){t.onnew&&t.onnew()}}),this.setElement($("<div/>").append(this.$list=$("<div/>")).append($("<div/>").append(this.button_new.$el)))},size:function(){return _.size(this.list)},add:function(t){if(t.id&&!this.list[t.id]){var e=new a.default.ButtonIcon({icon:"fa-trash-o",tooltip:"Delete this repeat block",cls:"ui-button-icon-plain form-repeat-delete",onclick:function(){t.ondel&&t.ondel()}}),i=new l.default.View({id:t.id,title:"placeholder",cls:t.cls||"ui-portlet-repeat",operations:{button_delete:e}});i.append(t.$el),i.$el.addClass("section-row").hide(),this.list[t.id]=i,this.$list.append(i.$el.fadeIn("fast")),this.options.max>0&&this.size()>=this.options.max&&this.button_new.disable(),this._refresh()}else Galaxy.emit.debug("form-repeat::add()","Duplicate or invalid repeat block id.")},del:function(t){this.list[t]?(this.$list.find("#"+t).remove(),delete this.list[t],this.button_new.enable(),this._refresh()):Galaxy.emit.debug("form-repeat::del()","Invalid repeat block id.")},delAll:function(){for(var t in this.list)this.del(t)},hideOptions:function(){this.button_new.$el.hide(),_.each(this.list,function(t){t.hideOperation("button_delete")}),_.isEmpty(this.list)&&this.$el.append($("<div/>").addClass("ui-form-info").html(this.options.empty_text))},_refresh:function(){var t=0;for(var e in this.list){var i=this.list[e];i.title(++t+": "+this.options.title),i[this.size()>this.options.min?"showOperation":"hideOperation"]("button_delete")}}});t.default={View:d}});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/form/form-view",["exports","utils/utils","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/form/form-section","mvc/form/form-data"],function(t,e,i,s,n,o){"use strict";function a(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0});a(e);var r=a(i),l=a(s),h=a(n),u=a(o);t.default=Backbone.View.extend({initialize:function(t){this.model=new Backbone.Model({initial_errors:!1,cls:"ui-portlet-limited",icon:null,always_refresh:!0,status:"warning",hide_operations:!1,onchange:function(){}}).set(t),this.setElement("<div/>"),this.render()},update:function(t){var e=this;this.data.matchModel(t,function(t,i){var s=e.input_list[i];if(s&&s.options&&!_.isEqual(s.options,t.options)){s.options=t.options;var n=e.field_list[i];if(n.update){var o=[];if(-1!=["data","data_collection","drill_down"].indexOf(s.type))o=s.options;else for(var a in t.options){var r=t.options[a];r.length>2&&o.push({label:r[0],value:r[1]})}n.update(o),n.trigger("change"),Galaxy.emit.debug("form-view::update()","Updating options for "+i)}}})},wait:function(t){for(var e in this.input_list){var i=this.field_list[e];this.input_list[e].is_dynamic&&i.wait&&i.unwait&&i[t?"wait":"unwait"]()}},highlight:function(t,e,i){var s=this.element_list[t];if(s&&(s.error(e||"Please verify this parameter."),this.portlet.expand(),this.trigger("expand",t),!i)){var n=this.$el.parents().filter(function(){return-1!=["auto","scroll"].indexOf($(this).css("overflow"))}).first();n.animate({scrollTop:n.scrollTop()+s.$el.offset().top-120},500)}},errors:function(t){if(this.trigger("reset"),t&&t.errors){var e=this.data.matchResponse(t.errors);for(var i in this.element_list){this.element_list[i];e[i]&&this.highlight(i,e[i],!0)}}},render:function(){var t=this;this.off("change"),this.off("reset"),this.field_list={},this.input_list={},this.element_list={},this.data=new u.default.Manager(this),this._renderForm(),this.data.create(),this.model.get("initial_errors")&&this.errors(this.model.attributes);var e=this.data.checksum();return this.on("change",function(i){var s=t.input_list[i];if(!s||s.refresh_on_change||t.model.get("always_refresh")){var n=t.data.checksum();n!=e&&(e=n,t.model.get("onchange")())}}),this.on("reset",function(){_.each(t.element_list,function(t){t.reset()})}),this},_renderForm:function(){$(".tooltip").remove();var t=this.model.attributes;this.message=new l.default.UnescapedMessage,this.section=new h.default.View(this,{inputs:t.inputs}),this.portlet=new r.default.View({icon:t.icon,title:t.title,cls:t.cls,operations:!t.hide_operations&&t.operations,buttons:t.buttons,collapsible:t.collapsible,collapsed:t.collapsed,onchange_title:t.onchange_title}),this.portlet.append(this.message.$el),this.portlet.append(this.section.$el),this.$el.empty(),t.inputs&&this.$el.append(this.portlet.$el),t.message&&this.message.update({persistent:!0,status:t.status,message:t.message}),Galaxy.emit.debug("form-view::initialize()","Completed")}})});
|
||||
define("mvc/form/form-view",["exports","mvc/ui/ui-portlet","mvc/ui/ui-misc","mvc/form/form-section","mvc/form/form-data"],function(t,e,i,s,n){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0}),t.View=void 0;var a=o(e),r=o(i),l=o(s),h=o(n),u=t.View=Backbone.View.extend({initialize:function(t){this.model=new Backbone.Model({initial_errors:!1,cls:"ui-portlet-limited",icon:null,always_refresh:!0,status:"warning",hide_operations:!1,onchange:function(){}}).set(t),this.setElement("<div/>"),this.render()},update:function(t){var e=this;this.data.matchModel(t,function(t,i){var s=e.input_list[i];if(s&&s.options&&!_.isEqual(s.options,t.options)){s.options=t.options;var n=e.field_list[i];if(n.update){var o=[];if(-1!=["data","data_collection","drill_down"].indexOf(s.type))o=s.options;else for(var a in t.options){var r=t.options[a];r.length>2&&o.push({label:r[0],value:r[1]})}n.update(o),n.trigger("change"),Galaxy.emit.debug("form-view::update()","Updating options for "+i)}}})},wait:function(t){for(var e in this.input_list){var i=this.field_list[e];this.input_list[e].is_dynamic&&i.wait&&i.unwait&&i[t?"wait":"unwait"]()}},highlight:function(t,e,i){var s=this.element_list[t];if(s&&(s.error(e||"Please verify this parameter."),this.portlet.expand(),this.trigger("expand",t),!i)){var n=this.$el.parents().filter(function(){return-1!=["auto","scroll"].indexOf($(this).css("overflow"))}).first();n.animate({scrollTop:n.scrollTop()+s.$el.offset().top-120},500)}},errors:function(t){if(this.trigger("reset"),t&&t.errors){var e=this.data.matchResponse(t.errors);for(var i in this.element_list)e[i]&&this.highlight(i,e[i],!0)}},render:function(){var t=this;this.off("change"),this.off("reset"),this.field_list={},this.input_list={},this.element_list={},this.data=new h.default.Manager(this),this._renderForm(),this.data.create(),this.model.get("initial_errors")&&this.errors(this.model.attributes);var e=this.data.checksum();return this.on("change",function(i){var s=t.input_list[i];if(!s||s.refresh_on_change||t.model.get("always_refresh")){var n=t.data.checksum();n!=e&&(e=n,t.model.get("onchange")())}}),this.on("reset",function(){_.each(t.element_list,function(t){t.reset()})}),this},_renderForm:function(){$(".tooltip").remove();var t=this.model.attributes;this.message=new r.default.UnescapedMessage,this.section=new l.default.View(this,{inputs:t.inputs}),this.portlet=new a.default.View({icon:t.icon,title:t.title,cls:t.cls,operations:!t.hide_operations&&t.operations,buttons:t.buttons,collapsible:t.collapsible,collapsed:t.collapsed,onchange_title:t.onchange_title}),this.portlet.append(this.message.$el),this.portlet.append(this.section.$el),this.$el.empty(),t.inputs&&this.$el.append(this.portlet.$el),t.message&&this.message.update({persistent:!0,status:t.status,message:t.message}),Galaxy.emit.debug("form-view::initialize()","Completed")}});t.default=u});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/form/form-wrapper",["exports","mvc/form/form-view","mvc/ui/ui-misc"],function(e,t,s){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var a=i(t),n=i(s),o=Backbone.View.extend({initialize:function(e){this.model=new Backbone.Model(e),this.url=this.model.get("url"),this.redirect=this.model.get("redirect"),this.setElement("<div/>"),this.render()},render:function(){var e=this;$.ajax({url:Galaxy.root+this.url,type:"GET"}).done(function(t){var s=$.extend({},e.model.attributes,t),i=new a.default({title:s.title,message:s.message,status:s.status||"warning",icon:s.icon,inputs:s.inputs,buttons:{submit:new n.default.Button({tooltip:s.submit_tooltip,title:s.submit_title||"Save",icon:s.submit_icon||"fa-save",cls:"btn btn-primary ui-clear-float",onclick:function(){e._submit(i)}})}});e.$el.empty().append(i.$el)}).fail(function(t){e.$el.empty().append(new n.default.Message({message:"Failed to load resource "+e.url+".",status:"danger",persistent:!0}).$el)})},_submit:function(e){var t=this;$.ajax({url:Galaxy.root+t.url,data:JSON.stringify(e.data.create()),type:"PUT",contentType:"application/json"}).done(function(s){var i={};s.id?i.id=s.id:i={message:s.message,status:"success",persistent:!1},t.redirect?window.location=Galaxy.root+t.redirect+"?"+$.param(i):(e.data.matchModel(s,function(t,s){e.field_list[s].value(t.value)}),t._showMessage(e,success_message))}).fail(function(s){t._showMessage(e,{message:s.responseJSON.err_msg,status:"danger",persistent:!1})})},_showMessage:function(e,t){e.$el.parents().filter(function(){return-1!=["auto","scroll"].indexOf($(this).css("overflow"))}).first().animate({scrollTop:0},500),e.message.update(t)}});e.default={View:o}});
|
||||
define("mvc/form/form-wrapper",["exports","mvc/form/form-view","mvc/ui/ui-misc"],function(e,t,s){"use strict";function i(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(e,"__esModule",{value:!0});var a=i(t),n=i(s),r=Backbone.View.extend({initialize:function(e){this.model=new Backbone.Model(e),this.url=this.model.get("url"),this.redirect=this.model.get("redirect"),this.setElement("<div/>"),this.render()},render:function(){var e=this;$.ajax({url:Galaxy.root+this.url,type:"GET"}).done(function(t){var s=$.extend({},e.model.attributes,t),i=new a.default({title:s.title,message:s.message,status:s.status||"warning",icon:s.icon,initial_errors:!0,errors:s.errors,inputs:s.inputs,buttons:{submit:new n.default.Button({tooltip:s.submit_tooltip,title:s.submit_title||"Save",icon:s.submit_icon||"fa-save",cls:"btn btn-primary ui-clear-float",onclick:function(){e._submit(i)}})}});e.$el.empty().append(i.$el)}).fail(function(t){e.$el.empty().append(new n.default.Message({message:"Failed to load resource "+e.url+".",status:"danger",persistent:!0}).$el)})},_submit:function(e){var t=this;$.ajax({url:Galaxy.root+t.url,data:JSON.stringify(e.data.create()),type:"PUT",contentType:"application/json"}).done(function(s){var i={};s.id?i.id=s.id:i={message:s.message,status:"success",persistent:!1},t.redirect?window.location=Galaxy.root+t.redirect+"?"+$.param(i):(e.data.matchModel(s,function(t,s){e.field_list[s].value(t.value)}),t._showMessage(e,success_message))}).fail(function(s){t._showMessage(e,{message:s.responseJSON.err_msg,status:"danger",persistent:!1})})},_showMessage:function(e,t){e.$el.parents().filter(function(){return-1!=["auto","scroll"].indexOf($(this).css("overflow"))}).first().animate({scrollTop:0},500),e.message.update(t)}});e.default={View:r}});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define("mvc/ui/ui-modal",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=Backbone.View.extend({className:"ui-modal",optionsDefault:{container:"body",title:"ui-modal",cls:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1,closing_callback:null,title_separator:!0},buttonList:{},initialize:function(t){this.options=_.defaults(t||{},this.optionsDefault),$(this.options.container).prepend(this.el),t&&this.render()},show:function(t){if(t&&(this.options=_.defaults(t,this.optionsDefault),this.render()),!this.visible&&(this.visible=!0,this.$el.fadeIn("fast"),this.options.closing_events)){var i=this;$(document).on("keyup.ui-modal",function(t){27==t.keyCode&&i.hide(!0)}),this.$backdrop.on("click",function(){i.hide(!0)})}},hide:function(t){this.visible=!1,this.$el.fadeOut("fast"),this.options.closing_callback&&this.options.closing_callback(t),$(document).off("keyup.ui-modal"),this.$backdrop.off("click")},render:function(){var t=this;if(this.$el.html(this._template()),this.$header=this.$(".modal-header"),this.$dialog=this.$(".modal-dialog"),this.$body=this.$(".modal-body"),this.$footer=this.$(".modal-footer"),this.$backdrop=this.$(".modal-backdrop"),this.$buttons=this.$(".buttons"),"progress"==this.options.body&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"/></div>')),this.$el.removeClass().addClass("modal").addClass(this.options.cls),this.$header.find(".title").html(this.options.title),this.$body.html(this.options.body),this.$buttons.empty(),this.buttonList={},this.options.buttons){var i=0;$.each(this.options.buttons,function(s,o){var e=$("<button/>").attr("id","button-"+i++).text(s).click(o);t.$buttons.append(e).append(" "),t.buttonList[s]=e})}else this.$footer.hide();this.$backdrop[this.options.backdrop&&"addClass"||"removeClass"]("in"),this.$header[!this.options.title_separator&&"addClass"||"removeClass"]("no-separator"),this.$body.removeAttr("style"),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width)},getButton:function(t){return this.buttonList[t]},enableButton:function(t){this.getButton(t).prop("disabled",!1)},disableButton:function(t){this.getButton(t).prop("disabled",!0)},showButton:function(t){this.getButton(t).show()},hideButton:function(t){this.getButton(t).hide()},scrollTop:function(){return this.$body.scrollTop()},_template:function(){return'<div class="modal-backdrop fade"/><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h4 class="title"/></div><div class="modal-body"/><div class="modal-footer"><div class="buttons"/></div></div></div>'}});t.default={View:i}});
|
||||
define("mvc/ui/ui-modal",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var i=t.View=Backbone.View.extend({className:"ui-modal",optionsDefault:{container:"body",title:"ui-modal",cls:"ui-modal",body:"",backdrop:!0,height:null,width:null,closing_events:!1,closing_callback:null,title_separator:!0},buttonList:{},initialize:function(t){this.options=_.defaults(t||{},this.optionsDefault),$(this.options.container).prepend(this.el),t&&this.render()},show:function(t){if(t&&(this.options=_.defaults(t,this.optionsDefault),this.render()),!this.visible&&(this.visible=!0,this.$el.fadeIn("fast"),this.options.closing_events)){var i=this;$(document).on("keyup.ui-modal",function(t){27==t.keyCode&&i.hide(!0)}),this.$backdrop.on("click",function(){i.hide(!0)})}},hide:function(t){this.visible=!1,this.$el.fadeOut("fast"),this.options.closing_callback&&this.options.closing_callback(t),$(document).off("keyup.ui-modal"),this.$backdrop.off("click")},render:function(){var t=this;if(this.$el.html(this._template()),this.$header=this.$(".modal-header"),this.$dialog=this.$(".modal-dialog"),this.$body=this.$(".modal-body"),this.$footer=this.$(".modal-footer"),this.$backdrop=this.$(".modal-backdrop"),this.$buttons=this.$(".buttons"),"progress"==this.options.body&&(this.options.body=$('<div class="progress progress-striped active"><div class="progress-bar progress-bar-info" style="width:100%"/></div>')),this.$el.removeClass().addClass("modal").addClass(this.options.cls),this.$header.find(".title").html(this.options.title),this.$body.html(this.options.body),this.$buttons.empty(),this.buttonList={},this.options.buttons){var i=0;$.each(this.options.buttons,function(s,o){var e=$("<button/>").attr("id","button-"+i++).text(s).click(o);t.$buttons.append(e).append(" "),t.buttonList[s]=e})}else this.$footer.hide();this.$backdrop[this.options.backdrop&&"addClass"||"removeClass"]("in"),this.$header[!this.options.title_separator&&"addClass"||"removeClass"]("no-separator"),this.$body.removeAttr("style"),this.options.height?(this.$body.css("height",this.options.height),this.$body.css("overflow","hidden")):this.$body.css("max-height",$(window).height()/2),this.options.width&&this.$dialog.css("width",this.options.width)},getButton:function(t){return this.buttonList[t]},enableButton:function(t){this.getButton(t).prop("disabled",!1)},disableButton:function(t){this.getButton(t).prop("disabled",!0)},showButton:function(t){this.getButton(t).show()},hideButton:function(t){this.getButton(t).hide()},scrollTop:function(){return this.$body.scrollTop()},_template:function(){return'<div class="modal-backdrop fade"/><div class="modal-dialog"><div class="modal-content"><div class="modal-header"><h4 class="title"/></div><div class="modal-body"/><div class="modal-footer"><div class="buttons"/></div></div></div>'}});t.default={View:i}});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/ui/ui-portlet",["exports","utils/utils","mvc/ui/ui-misc"],function(t,e,i){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0});var s=o(e),n=o(i),l=Backbone.View.extend({visible:!1,initialize:function(t){var e=this;this.model=t&&t.model||new Backbone.Model({id:s.default.uid(),cls:"ui-portlet",title:"",icon:"",buttons:null,body:null,scrollable:!0,nopadding:!1,operations:null,collapsible:!1,collapsible_button:!1,collapsed:!1,onchange_title:null}).set(t),this.setElement(this._template()),this.$body=this.$(".portlet-body"),this.$title_text=this.$(".portlet-title-text"),this.$title_icon=this.$(".portlet-title-icon"),this.$header=this.$(".portlet-header"),this.$content=this.$(".portlet-content"),this.$backdrop=this.$(".portlet-backdrop"),this.$buttons=this.$(".portlet-buttons"),this.$operations=this.$(".portlet-operations"),this.model.get("body")&&this.append(this.model.get("body")),this.collapsible_button=new n.default.ButtonIcon({icon:"fa-eye",tooltip:"Collapse/Expand",cls:"ui-button-icon-plain",onclick:function(){e[e.collapsed?"expand":"collapse"]()}}),this.render()},render:function(){var t=this,e=this.model.attributes;return this.$el.removeClass().addClass(e.cls).attr("id",e.id),this.$header[e.title?"show":"hide"](),this.$title_text.html(e.title),_.each([this.$content,this.$body],function(t){t[e.nopadding?"addClass":"removeClass"]("no-padding")}),e.icon?this.$title_icon.removeClass().addClass("portlet-title-icon fa").addClass(e.icon).show():this.$title_icon.hide(),this.$title_text[e.collapsible?"addClass":"removeClass"]("no-highlight collapsible").off(),e.collapsible&&(this.$title_text.on("click",function(){t[t.collapsed?"expand":"collapse"]()}),e.collapsed?this.collapse():this.expand()),this.$title_text.prop("disabled",!e.onchange_title),e.onchange_title&&this.$title_text.make_text_editable({on_finish:function(t){e.onchange_title(t)}}),e.buttons?(this.$buttons.empty().show(),$.each(this.model.get("buttons"),function(e,i){i.$el.prop("id",e),t.$buttons.append(i.$el)})):this.$buttons.hide(),this.$operations.empty,e.collapsible_button&&this.$operations.append(this.collapsible_button.$el),e.operations&&$.each(e.operations,function(e,i){i.$el.prop("id",e),t.$operations.append(i.$el)}),this},append:function(t){this.$body.append(t)},empty:function(){this.$body.empty()},header:function(){return this.$header},body:function(){return this.$body},show:function(){this.visible=!0,this.$el.fadeIn("fast")},hide:function(){this.visible=!1,this.$el.hide()},enableButton:function(t){this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(t){this.$buttons.find("#"+t).prop("disabled",!0)},hideOperation:function(t){this.$operations.find("#"+t).hide()},showOperation:function(t){this.$operations.find("#"+t).show()},setOperation:function(t,e){this.$operations.find("#"+t).off("click").on("click",e)},title:function(t){return t&&this.$title_text.html(t),this.$title_text.html()},collapse:function(){this.collapsed=!0,this.$content.height("0%"),this.$body.hide(),this.collapsible_button.setIcon("fa-eye-slash")},expand:function(){this.collapsed=!1,this.$content.height("100%"),this.$body.fadeIn("fast"),this.collapsible_button.setIcon("fa-eye")},disable:function(){this.$backdrop.show()},enable:function(){this.$backdrop.hide()},_template:function(){return $("<div/>").append($("<div/>").addClass("portlet-header").append($("<div/>").addClass("portlet-operations")).append($("<div/>").addClass("portlet-title").append($("<i/>").addClass("portlet-title-icon")).append($("<span/>").addClass("portlet-title-text")))).append($("<div/>").addClass("portlet-content").append($("<div/>").addClass("portlet-body")).append($("<div/>").addClass("portlet-buttons"))).append($("<div/>").addClass("portlet-backdrop"))}});t.default={View:l}});
|
||||
define("mvc/ui/ui-portlet",["exports","utils/utils","mvc/ui/ui-misc"],function(t,e,i){"use strict";function o(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0}),t.View=void 0;var s=o(e),n=o(i),l=t.View=Backbone.View.extend({visible:!1,initialize:function(t){var e=this;this.model=t&&t.model||new Backbone.Model({id:s.default.uid(),cls:"ui-portlet",title:"",icon:"",buttons:null,body:null,scrollable:!0,nopadding:!1,operations:null,collapsible:!1,collapsible_button:!1,collapsed:!1,onchange_title:null}).set(t),this.setElement(this._template()),this.$body=this.$(".portlet-body"),this.$title_text=this.$(".portlet-title-text"),this.$title_icon=this.$(".portlet-title-icon"),this.$header=this.$(".portlet-header"),this.$content=this.$(".portlet-content"),this.$backdrop=this.$(".portlet-backdrop"),this.$buttons=this.$(".portlet-buttons"),this.$operations=this.$(".portlet-operations"),this.model.get("body")&&this.append(this.model.get("body")),this.collapsible_button=new n.default.ButtonIcon({icon:"fa-eye",tooltip:"Collapse/Expand",cls:"ui-button-icon-plain",onclick:function(){e[e.collapsed?"expand":"collapse"]()}}),this.render()},render:function(){var t=this,e=this.model.attributes;return this.$el.removeClass().addClass(e.cls).attr("id",e.id),this.$header[e.title?"show":"hide"](),this.$title_text.html(e.title),_.each([this.$content,this.$body],function(t){t[e.nopadding?"addClass":"removeClass"]("no-padding")}),e.icon?this.$title_icon.removeClass().addClass("portlet-title-icon fa").addClass(e.icon).show():this.$title_icon.hide(),this.$title_text[e.collapsible?"addClass":"removeClass"]("no-highlight collapsible").off(),e.collapsible&&(this.$title_text.on("click",function(){t[t.collapsed?"expand":"collapse"]()}),e.collapsed?this.collapse():this.expand()),this.$title_text.prop("disabled",!e.onchange_title),e.onchange_title&&this.$title_text.make_text_editable({on_finish:function(t){e.onchange_title(t)}}),e.buttons?(this.$buttons.empty().show(),$.each(this.model.get("buttons"),function(e,i){i.$el.prop("id",e),t.$buttons.append(i.$el)})):this.$buttons.hide(),this.$operations.empty,e.collapsible_button&&this.$operations.append(this.collapsible_button.$el),e.operations&&$.each(e.operations,function(e,i){i.$el.prop("id",e),t.$operations.append(i.$el)}),this},append:function(t){this.$body.append(t)},empty:function(){this.$body.empty()},header:function(){return this.$header},body:function(){return this.$body},show:function(){this.visible=!0,this.$el.fadeIn("fast")},hide:function(){this.visible=!1,this.$el.hide()},enableButton:function(t){this.$buttons.find("#"+t).prop("disabled",!1)},disableButton:function(t){this.$buttons.find("#"+t).prop("disabled",!0)},hideOperation:function(t){this.$operations.find("#"+t).hide()},showOperation:function(t){this.$operations.find("#"+t).show()},setOperation:function(t,e){this.$operations.find("#"+t).off("click").on("click",e)},title:function(t){return t&&this.$title_text.html(t),this.$title_text.html()},collapse:function(){this.collapsed=!0,this.$content.height("0%"),this.$body.hide(),this.collapsible_button.setIcon("fa-eye-slash")},expand:function(){this.collapsed=!1,this.$content.height("100%"),this.$body.fadeIn("fast"),this.collapsible_button.setIcon("fa-eye")},disable:function(){this.$backdrop.show()},enable:function(){this.$backdrop.hide()},_template:function(){return $("<div/>").append($("<div/>").addClass("portlet-header").append($("<div/>").addClass("portlet-operations")).append($("<div/>").addClass("portlet-title").append($("<i/>").addClass("portlet-title-icon")).append($("<span/>").addClass("portlet-title-text")))).append($("<div/>").addClass("portlet-content").append($("<div/>").addClass("portlet-body")).append($("<div/>").addClass("portlet-buttons"))).append($("<div/>").addClass("portlet-backdrop"))}});t.default={View:l}});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/ui/ui-tabs",["exports","utils/utils"],function(t,e){"use strict";Object.defineProperty(t,"__esModule",{value:!0});!function(t){t&&t.__esModule}(e);var i=Backbone.View.extend({initialize:function(t){this.collection=new Backbone.Collection,this.model=t&&t.model||new Backbone.Model({onchange:null,visible:!0}).set(t),this.setElement($(this._template())),this.$nav=this.$(".tab-navigation"),this.$content=this.$(".tab-content"),this.$el.on("click",function(){$(".tooltip").hide()}),this.render(),this.listenTo(this.model,"change",this.render,this),this.listenTo(this.collection,"add",this._add,this),this.listenTo(this.collection,"remove",this._remove,this),this.listenTo(this.collection,"change",this._change,this),this.listenTo(this.collection,"reset",this._reset,this),this.listenTo(this.collection,"add remove reset",this.render,this)},render:function(){var t=this.model.get("current");(t=this.$("#"+t).length>0?t:this.first())&&(this.$nav.children().removeClass("active"),this.$content.children().removeClass("active"),this.$("#tab-"+t).addClass("active"),this.$("#"+t).addClass("active")),this.$el[this.model.get("visible")?"fadeIn":"fadeOut"]("fast"),this.$nav[this.size()>1?"show":"hide"]()},current:function(){return this.model.get("current")},show:function(t){t&&(this.model.set({current:t,visible:!0}),this.model.get("onchange")&&this.model.get("onchange")(t))},hide:function(){this.model.set("visible",!1)},first:function(){var t=this.collection.first();return t&&t.id},size:function(){return this.collection.length},add:function(t){this.collection.add(t)},del:function(t){this.collection.remove(t)},delAll:function(){this.collection.reset()},showTab:function(t){this.collection.get(t).set("hidden",!1)},hideTab:function(t){this.collection.get(t).set("hidden",!0)},_add:function(t){var e=this,i=t.attributes;this.$content.append($("<div/>").attr("id",i.id).addClass("tab-pane").append(i.$el)),this.$nav.append($(this._template_tab(i)).show().tooltip({title:i.tooltip,placement:"bottom",container:e.$el}).on("click",function(t){t.preventDefault(),e.show(i.id)})),1==this.size()&&this.show(i.id)},_remove:function(t){this.$("#tab-"+t.id).remove(),this.$("#"+t.id).remove()},_reset:function(){this.$nav.empty(),this.$content.empty()},_change:function(t){this.$("#tab-"+t.id)[t.get("hidden")?"hide":"show"]()},_template:function(){return $("<div/>").addClass("ui-tabs tabbable tabs-left").append($("<ul/>").addClass("tab-navigation nav nav-tabs")).append($("<div/>").addClass("tab-content"))},_template_tab:function(t){var e=$("<li/>").addClass("tab-element").attr("id","tab-"+t.id).append($("<a/>").attr("id","tab-title-link-"+t.id)),i=e.find("a");return t.icon&&i.append($("<i/>").addClass("tab-icon fa").addClass(t.icon)),i.append($("<span/>").attr("id","tab-title-text-"+t.id).addClass("tab-title-text").append(t.title)),e}});t.default={View:i}});
|
||||
define("mvc/ui/ui-tabs",["exports"],function(t){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var e=t.View=Backbone.View.extend({initialize:function(t){this.collection=new Backbone.Collection,this.model=t&&t.model||new Backbone.Model({onchange:null,visible:!0}).set(t),this.setElement($(this._template())),this.$nav=this.$(".tab-navigation"),this.$content=this.$(".tab-content"),this.$el.on("click",function(){$(".tooltip").hide()}),this.render(),this.listenTo(this.model,"change",this.render,this),this.listenTo(this.collection,"add",this._add,this),this.listenTo(this.collection,"remove",this._remove,this),this.listenTo(this.collection,"change",this._change,this),this.listenTo(this.collection,"reset",this._reset,this),this.listenTo(this.collection,"add remove reset",this.render,this)},render:function(){var t=this.model.get("current");(t=this.$("#"+t).length>0?t:this.first())&&(this.$nav.children().removeClass("active"),this.$content.children().removeClass("active"),this.$("#tab-"+t).addClass("active"),this.$("#"+t).addClass("active")),this.$el[this.model.get("visible")?"fadeIn":"fadeOut"]("fast"),this.$nav[this.size()>1?"show":"hide"]()},current:function(){return this.model.get("current")},show:function(t){t&&(this.model.set({current:t,visible:!0}),this.model.get("onchange")&&this.model.get("onchange")(t))},hide:function(){this.model.set("visible",!1)},first:function(){var t=this.collection.first();return t&&t.id},size:function(){return this.collection.length},add:function(t){this.collection.add(t)},del:function(t){this.collection.remove(t)},delAll:function(){this.collection.reset()},showTab:function(t){this.collection.get(t).set("hidden",!1)},hideTab:function(t){this.collection.get(t).set("hidden",!0)},_add:function(t){var e=this,i=t.attributes;this.$content.append($("<div/>").attr("id",i.id).addClass("tab-pane").append(i.$el)),this.$nav.append($(this._template_tab(i)).show().tooltip({title:i.tooltip,placement:"bottom",container:e.$el}).on("click",function(t){t.preventDefault(),e.show(i.id)})),1==this.size()&&this.show(i.id)},_remove:function(t){this.$("#tab-"+t.id).remove(),this.$("#"+t.id).remove()},_reset:function(){this.$nav.empty(),this.$content.empty()},_change:function(t){this.$("#tab-"+t.id)[t.get("hidden")?"hide":"show"]()},_template:function(){return $("<div/>").addClass("ui-tabs tabbable tabs-left").append($("<ul/>").addClass("tab-navigation nav nav-tabs")).append($("<div/>").addClass("tab-content"))},_template_tab:function(t){var e=$("<li/>").addClass("tab-element").attr("id","tab-"+t.id).append($("<a/>").attr("id","tab-title-link-"+t.id)),i=e.find("a");return t.icon&&i.append($("<i/>").addClass("tab-icon fa").addClass(t.icon)),i.append($("<span/>").attr("id","tab-title-text-"+t.id).addClass("tab-title-text").append(t.title)),e}});t.default={View:e}});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/ui/ui-thumbnails",["exports","utils/utils","mvc/ui/ui-misc","mvc/ui/ui-tabs"],function(t,i,e,l){"use strict";function s(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0});var n=s(i),a=(s(e),s(l)),u=Backbone.View.extend({events:{"click .ui-thumbnails-item":"_onclick","dblclick .ui-thumbnails-item":"_ondblclick"},initialize:function(t){this.model=t.model||new Backbone.Model(t),this.collection=new Backbone.Collection(this.model.get("collection")),this.tabs=new a.default.View({}),this.setElement(this.tabs.$el.addClass("ui-thumbnails")),this.render(),this.listenTo(this.model,"change",this.render,this),this.listenTo(this.collection,"reset change add remove",this.render,this)},render:function(){this.first=null,this.tabs.delAll(),this._renderDefault(),this._renderList()},_renderDefault:function(){var t=this,i=$("<div/>").addClass("ui-thumbnails-grid");this.collection.each(function(e){if(-1!==e.get("keywords").indexOf("default")){var l=e.get("title");i.append($(t._templateThumbnailItem({id:e.id,title:l.length<20?l:l.substr(0,20)+"...",title_icon:e.get("title_icon"),image_src:e.get("image_src")})).tooltip({title:e.get("description"),placement:"bottom"}))}}),i.children().length>0&&this.tabs.add({id:n.default.uid(),title:t.model.get("title_default"),$el:i})},_renderList:function(){var t=this;if(this.collection.length>0){this.first=this.first||this.collection.first().id;var i=$("<div/>").addClass("ui-thumbnails-grid");this.collection.each(function(e){i.append(t._templateRegularItem(e.attributes))}),this.tabs.add({id:n.default.uid(),title:t.model.get("title_list"),$el:i})}},value:function(t){if(void 0!==t){t="__first"==t?this.first:t;var i=this.$(".ui-thumbnail-current").attr("value");this.$(".ui-thumbnail-current").removeClass("ui-thumbnail-current"),this.$('[value="'+t+'"]').addClass("ui-thumbnail-current");var e=this.$(".ui-thumbnail-current").attr("value"),l=this.model.get("onchange");e!=i&&l&&l(e)}return this.$(".ui-thumbnail-current").attr("value")},_onclick:function(t){this.value($(t.target).closest(".ui-thumbnails-item").attr("value"))},_ondblclick:function(t){this.model.get("ondblclick")&&this.model.get("ondblclick")(this.value())},_templateThumbnailItem:function(t){return'<div class="ui-thumbnails-item ui-thumbnails-item-float" value="'+t.id+'"><img class="ui-thumbnails-image" src="'+t.image_src+'"><div class="ui-thumbnails-title ui-form-info"><span class="fa '+t.title_icon+'"/>'+t.title+"</div><div>"},_templateRegularItem:function(t){return'<div class="ui-thumbnails-item" value="'+t.id+'"><table><tr><td><img class="ui-thumbnails-image" src="'+t.image_src+'"></td><td><div class="ui-thumbnails-description-title ui-form-info">'+t.title+'</div><div class="ui-thumbnails-description-text ui-form-info">'+t.description+"</div></td></tr><div>"}});t.default={View:u}});
|
||||
define("mvc/ui/ui-thumbnails",["exports","utils/utils","mvc/ui/ui-tabs"],function(t,i,e){"use strict";function l(t){return t&&t.__esModule?t:{default:t}}Object.defineProperty(t,"__esModule",{value:!0}),t.View=void 0;var s=l(i),n=l(e),a=t.View=Backbone.View.extend({events:{"click .ui-thumbnails-item":"_onclick","dblclick .ui-thumbnails-item":"_ondblclick"},initialize:function(t){this.model=t.model||new Backbone.Model(t),this.collection=new Backbone.Collection(this.model.get("collection")),this.tabs=new n.default.View({}),this.setElement(this.tabs.$el.addClass("ui-thumbnails")),this.render(),this.listenTo(this.model,"change",this.render,this),this.listenTo(this.collection,"reset change add remove",this.render,this)},render:function(){this.first=null,this.tabs.delAll(),this._renderDefault(),this._renderList()},_renderDefault:function(){var t=this,i=$("<div/>").addClass("ui-thumbnails-grid");this.collection.each(function(e){if(-1!==e.get("keywords").indexOf("default")){var l=e.get("title");i.append($(t._templateThumbnailItem({id:e.id,title:l.length<20?l:l.substr(0,20)+"...",title_icon:e.get("title_icon"),image_src:e.get("image_src")})).tooltip({title:e.get("description"),placement:"bottom"}))}}),i.children().length>0&&this.tabs.add({id:s.default.uid(),title:this.model.get("title_default"),$el:i})},_renderList:function(){var t=this;if(this.collection.length>0){this.first=this.first||this.collection.first().id;var i=$("<div/>").addClass("ui-thumbnails-grid");this.collection.each(function(e){i.append(t._templateRegularItem(e.attributes))}),this.tabs.add({id:s.default.uid(),title:t.model.get("title_list"),$el:i})}},value:function(t){if(void 0!==t){t="__first"==t?this.first:t;var i=this.$(".ui-thumbnail-current").attr("value");this.$(".ui-thumbnail-current").removeClass("ui-thumbnail-current"),this.$('[value="'+t+'"]').addClass("ui-thumbnail-current");var e=this.$(".ui-thumbnail-current").attr("value"),l=this.model.get("onchange");e!=i&&l&&l(e)}return this.$(".ui-thumbnail-current").attr("value")},_onclick:function(t){this.value($(t.target).closest(".ui-thumbnails-item").attr("value"))},_ondblclick:function(){this.model.get("ondblclick")&&this.model.get("ondblclick")(this.value())},_templateThumbnailItem:function(t){return'<div class="ui-thumbnails-item ui-thumbnails-item-float" value="'+t.id+'"><img class="ui-thumbnails-image" src="'+t.image_src+'"><div class="ui-thumbnails-title ui-form-info"><span class="fa '+t.title_icon+'"/>'+t.title+"</div><div>"},_templateRegularItem:function(t){return'<div class="ui-thumbnails-item" value="'+t.id+'"><table><tr><td><img class="ui-thumbnails-image" src="'+t.image_src+'"></td><td><div class="ui-thumbnails-description-title ui-form-info">'+t.title+'</div><div class="ui-thumbnails-description-text ui-form-info">'+t.description+"</div></td></tr><div>"}});t.default={View:a}});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/visualization/visualization-model",[],function(){"use strict";var t=Backbone.Model.extend({defaults:{config:{}},urlRoot:function(){return Galaxy.root+"api/visualizations"},initialize:function(t){_.isObject(t.config)&&_.isObject(this.defaults.config)&&_.defaults(t.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(t,i){if("config"===t){var n=this.get("config");_.isObject(n)&&(i=_.extend(_.clone(n),i))}return Backbone.Model.prototype.set.call(this,t,i),this},toString:function(){var t=this.get("id")||"";return this.get("title")&&(t+=":"+this.get("title")),"Visualization("+t+")"}});Backbone.Collection.extend({model:t,url:function(){return Galaxy.root+"api/visualizations"},initialize:function(t,i){i=i||{}},set:function(t,i){var n=this;t=_.map(t,function(t){var i=n.get(t.id);if(!i)return t;var e=i.toJSON();return _.extend(e,t),e}),Backbone.Collection.prototype.set.call(this,t,i)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}})});
|
||||
define("mvc/visualization/visualization-model",["exports","libs/backbone"],function(t,i){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.VisualizationCollection=t.Visualization=void 0;var n=function(t){if(t&&t.__esModule)return t;var i={};if(null!=t)for(var n in t)Object.prototype.hasOwnProperty.call(t,n)&&(i[n]=t[n]);return i.default=t,i}(i),e=t.Visualization=n.Model.extend({defaults:{config:{}},urlRoot:function(){return Galaxy.root+"api/visualizations"},initialize:function(t){_.isObject(t.config)&&_.isObject(this.defaults.config)&&_.defaults(t.config,this.defaults.config),this._setUpListeners()},_setUpListeners:function(){},set:function(t,i){if("config"===t){var e=this.get("config");_.isObject(e)&&(i=_.extend(_.clone(e),i))}return n.Model.prototype.set.call(this,t,i),this},toString:function(){var t=this.get("id")||"";return this.get("title")&&(t+=":"+this.get("title")),"Visualization("+t+")"}});t.VisualizationCollection=n.Collection.extend({model:e,url:function(){return Galaxy.root+"api/visualizations"},initialize:function(t,i){i=i||{}},set:function(t,i){var e=this;t=_.map(t,function(t){var i=e.get(t.id);if(!i)return t;var n=i.toJSON();return _.extend(n,t),n}),n.Collection.prototype.set.call(this,t,i)},toString:function(){return["VisualizationCollection(",[this.historyId,this.length].join(),")"].join("")}})});
|
||||
@@ -1 +1 @@
|
||||
define("mvc/workflow/workflow-canvas",["exports"],function(t){"use strict";function i(t,i,e){this.app=t,this.cv=i,this.cc=this.cv.find("#canvas-container"),this.overview=e,this.oc=e.find("#overview-canvas"),this.ov=e.find("#overview-viewport"),this.init_drag()}function e(t){this.panel=t}Object.defineProperty(t,"__esModule",{value:!0}),$.extend(i.prototype,{init_drag:function(){var t=this,i=function(i,e){i=Math.min(i,t.cv.width()/2),i=Math.max(i,-t.cc.width()+t.cv.width()/2),e=Math.min(e,t.cv.height()/2),e=Math.max(e,-t.cc.height()+t.cv.height()/2),t.cc.css({left:i,top:e}),t.cv.css({"background-position-x":i,"background-position-y":e}),t.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new e(this)});var o,h;this.cv.bind("dragstart",function(){var i=$(this).offset(),e=t.cc.position();h=e.top-i.top,o=e.left-i.left}).bind("drag",function(t,e){i(e.offsetX+o,e.offsetY+h)}).bind("dragend",function(){t.app.workflow.fit_canvas_to_nodes(),t.draw_overview()}),this.overview.click(function(e){if(t.overview.hasClass("blockaclick"))t.overview.removeClass("blockaclick");else{var o=t.cc.width(),h=t.cc.height(),s=t.oc.width(),c=t.oc.height(),n=e.pageX-t.oc.offset().left-t.ov.width()/2,a=e.pageY-t.oc.offset().top-t.ov.height()/2;i(-n/s*o,-a/c*h),t.app.workflow.fit_canvas_to_nodes(),t.draw_overview()}}),this.ov.bind("drag",function(e,o){var h=t.cc.width(),s=t.cc.height(),c=t.oc.width(),n=t.oc.height(),a=o.offsetX-t.overview.offset().left,f=o.offsetY-t.overview.offset().top;i(-a/c*h,-f/n*s)}).bind("dragend",function(){t.overview.addClass("blockaclick"),t.app.workflow.fit_canvas_to_nodes(),t.draw_overview()}),$("#overview-border").bind("drag",function(i,e){var o=$(this).offsetParent(),h=o.offset(),s=Math.max(o.width()-(e.offsetX-h.left),o.height()-(e.offsetY-h.top));$(this).css({width:s,height:s}),t.draw_overview()}),$("#overview-border div").bind("drag",function(){})},update_viewport_overlay:function(){var t=this.cc,i=this.cv,e=this.oc,o=this.ov,h=t.width(),s=t.height(),c=e.width(),n=e.height(),a=t.position();o.css({left:-a.left/h*c,top:-a.top/s*n,width:i.width()/h*c-2,height:i.height()/s*n-2})},draw_overview:function(){var t,i,e,o,h=$("#overview-canvas"),s=h.parent().parent().width(),c=h.get(0).getContext("2d"),n=$("#canvas-container").width(),a=$("#canvas-container").height(),f=this.cv.width(),r=this.cv.height();n<f&&a<r?(o=(s-(e=n/f*s))/2,i=(s-(t=a/r*s))/2):n<a?(i=0,t=s,o=(s-(e=Math.ceil(t*n/a)))/2):(e=s,o=0,i=(s-(t=Math.ceil(e*a/n)))/2),h.parent().css({left:o,top:i,width:e,height:t}),h.attr("width",e),h.attr("height",t),$.each(this.app.workflow.nodes,function(i,o){c.fillStyle="#D2C099",c.strokeStyle="#D8B365",c.lineWidth=1;var h=$(o.element),s=h.position(),f=s.left/n*e,r=s.top/a*t,v=h.width()/n*e,l=h.height()/a*t;o.errors?(c.fillStyle="#FFCCCC",c.strokeStyle="#AA6666"):void 0!==o.workflow_outputs&&o.workflow_outputs.length>0&&(c.fillStyle="#E8A92D",c.strokeStyle="#E8A92D"),c.fillRect(f,r,v,l),c.strokeRect(f,r,v,l)}),this.update_viewport_overlay()}}),$.extend(e.prototype,{test:function(t,i){clearTimeout(this.timeout);var e=t.pageX,o=t.pageY,h=(b=$(this.panel)).position(),s=b.width(),c=b.height(),n=b.parent(),a=n.width(),f=n.height(),r=n.offset(),v=r.left,l=r.top,d=v+n.width(),w=l+n.height(),p=-(s-a/2),g=-(c-f/2),u=a/2,_=f/2,k=!1;if(e-5<v){if(h.left<u){m=Math.min(23,u-h.left);b.css("left",h.left+m),k=!0}}else if(e+5>d){if(h.left>p){m=Math.min(23,h.left-p);b.css("left",h.left-m),k=!0}}else if(o-5<l){if(h.top<_){m=Math.min(23,_-h.top);b.css("top",h.top+m),k=!0}}else if(o+5>w&&h.top>g){var m=Math.min(23,h.top-p);b.css("top",h.top-m+"px"),k=!0}if(k){i();var b=this;this.timeout=setTimeout(function(){b.test(t,i)},50)}},stop:function(t,i){clearTimeout(this.timeout)}}),t.default=i});
|
||||
define("mvc/workflow/workflow-canvas",["exports"],function(t){"use strict";function e(t,e,i){this.app=t,this.cv=e,this.cc=this.cv.find("#canvas-container"),this.overview=i,this.oc=i.find("#overview-canvas"),this.ov=i.find("#overview-viewport"),this.init_drag(),this.init_copy_paste()}function i(t){this.panel=t}Object.defineProperty(t,"__esModule",{value:!0}),$.extend(e.prototype,{init_drag:function(){var t=this,e=function(e,i){e=Math.min(e,t.cv.width()/2),e=Math.max(e,-t.cc.width()+t.cv.width()/2),i=Math.min(i,t.cv.height()/2),i=Math.max(i,-t.cc.height()+t.cv.height()/2),t.cc.css({left:e,top:i}),t.cv.css({"background-position-x":e,"background-position-y":i}),t.update_viewport_overlay()};this.cc.each(function(){this.scroll_panel=new i(this)});var o,n;this.cv.bind("click",function(){document.activeElement.blur()}).bind("dragstart",function(){var e=$(this).offset(),i=t.cc.position();n=i.top-e.top,o=i.left-e.left}).bind("drag",function(t,i){e(i.offsetX+o,i.offsetY+n)}).bind("dragend",function(){t.app.workflow.fit_canvas_to_nodes(),t.draw_overview()}),this.overview.click(function(i){if(t.overview.hasClass("blockaclick"))t.overview.removeClass("blockaclick");else{var o=t.cc.width(),n=t.cc.height(),a=t.oc.width(),c=t.oc.height(),s=i.pageX-t.oc.offset().left-t.ov.width()/2,h=i.pageY-t.oc.offset().top-t.ov.height()/2;e(-s/a*o,-h/c*n),t.app.workflow.fit_canvas_to_nodes(),t.draw_overview()}}),this.ov.bind("drag",function(i,o){var n=t.cc.width(),a=t.cc.height(),c=t.oc.width(),s=t.oc.height(),h=o.offsetX-t.overview.offset().left,r=o.offsetY-t.overview.offset().top;e(-h/c*n,-r/s*a)}).bind("dragend",function(){t.overview.addClass("blockaclick"),t.app.workflow.fit_canvas_to_nodes(),t.draw_overview()}),$("#overview-border").bind("drag",function(e,i){var o=$(this).offsetParent(),n=o.offset(),a=Math.max(o.width()-(i.offsetX-n.left),o.height()-(i.offsetY-n.top));$(this).css({width:a,height:a}),t.draw_overview()}),$("#overview-border div").bind("drag",function(){})},init_copy_paste:function(){var t=this;document.addEventListener("copy",function(e){""===window.getSelection().toString()&&(t.app.workflow.active_node&&e.clipboardData.setData("application/json",JSON.stringify({nodeId:t.app.workflow.active_node.id})),e.preventDefault())}),document.addEventListener("paste",function(e){if(document.activeElement&&"textarea"!==document.activeElement.type&&"text"!==document.activeElement.type){var i;try{i=JSON.parse(e.clipboardData.getData("application/json")).nodeId}catch(t){}i&&t.app.workflow.nodes.hasOwnProperty(i)&&t.app.workflow.nodes[i].clone(),e.preventDefault()}})},update_viewport_overlay:function(){var t=this.cc,e=this.cv,i=this.oc,o=this.ov,n=t.width(),a=t.height(),c=i.width(),s=i.height(),h=t.position();o.css({left:-h.left/n*c,top:-h.top/a*s,width:e.width()/n*c-2,height:e.height()/a*s-2})},draw_overview:function(){var t,e,i,o,n=$("#overview-canvas"),a=n.parent().parent().width(),c=n.get(0).getContext("2d"),s=$("#canvas-container").width(),h=$("#canvas-container").height(),r=this.cv.width(),f=this.cv.height();s<r&&h<f?(o=(a-(i=s/r*a))/2,e=(a-(t=h/f*a))/2):s<h?(e=0,t=a,o=(a-(i=Math.ceil(t*s/h)))/2):(i=a,o=0,e=(a-(t=Math.ceil(i*h/s)))/2),n.parent().css({left:o,top:e,width:i,height:t}),n.attr("width",i),n.attr("height",t),$.each(this.app.workflow.nodes,function(e,o){c.fillStyle="#D2C099",c.strokeStyle="#D8B365",c.lineWidth=1;var n=$(o.element),a=n.position(),r=a.left/s*i,f=a.top/h*t,d=n.width()/s*i,v=n.height()/h*t;o.errors?(c.fillStyle="#FFCCCC",c.strokeStyle="#AA6666"):void 0!==o.workflow_outputs&&o.workflow_outputs.length>0&&(c.fillStyle="#E8A92D",c.strokeStyle="#E8A92D"),c.fillRect(r,f,d,v),c.strokeRect(r,f,d,v)}),this.update_viewport_overlay()}}),$.extend(i.prototype,{test:function(t,e){var i=this;clearTimeout(this.timeout);var o=t.pageX,n=t.pageY,a=$(this.panel),c=a.position(),s=a.width(),h=a.height(),r=a.parent(),f=r.width(),d=r.height(),v=r.offset(),p=v.left,l=v.top,w=p+r.width(),u=l+r.height(),g=-(s-f/2),_=-(h-d/2),m=f/2,k=d/2,y=!1,b=0;o-5<p?c.left<m&&(b=Math.min(23,m-c.left),a.css("left",c.left+b),y=!0):o+5>w?c.left>g&&(b=Math.min(23,c.left-g),a.css("left",c.left-b),y=!0):n-5<l?c.top<k&&(b=Math.min(23,k-c.top),a.css("top",c.top+b),y=!0):n+5>u&&c.top>_&&(b=Math.min(23,c.top-g),a.css("top",c.top-b+"px"),y=!0),y&&(e(),this.timeout=setTimeout(function(){i.test(t,e)},50))},stop:function(){clearTimeout(this.timeout)}}),t.default=e});
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1 +1 @@
|
||||
define("utils/utils",["exports","utils/localization"],function(t,e){"use strict";function r(t,e){for(var n in t){var i=t[n];if(_.isObject(i)){var a=e(i);a&&(t[n]=a),r(i,e)}}}function n(t){var e={contentType:"application/json",type:t.type||"GET",data:t.data||{},url:t.url};"GET"==e.type||"DELETE"==e.type?($.isEmptyObject(e.data)||(e.url+=-1==e.url.indexOf("?")?"?":"&",e.url+=$.param(e.data,!0)),e.data=null):(e.dataType="json",e.url=e.url,e.data=JSON.stringify(e.data)),$.ajax(e).done(function(e){if("string"==typeof e)try{e=e.replace("Infinity,",'"Infinity",'),e=jQuery.parseJSON(e)}catch(t){console.debug(t)}t.success&&t.success(e)}).fail(function(e){var r=null;try{r=jQuery.parseJSON(e.responseText)}catch(t){r=e.responseText}t.error&&t.error(r,e.status)}).always(function(){t.complete&&t.complete()})}function i(t,e){for(var r=1,n=0;n<e;n++)r*=10;return Math.round(t*r)/r}Object.defineProperty(t,"__esModule",{value:!0});var a=function(t){return t&&t.__esModule?t:{default:t}}(e),s=1024,u=s*s,o=u*s,l=o*s;t.default={cssLoadFile:function(t){$('link[href^="'+t+'"]').length||$('<link href="'+Galaxy.root+t+'" rel="stylesheet">').appendTo("head")},cssGetAttribute:function(t,e){var r=$('<div class="'+t+'"></div>');r.appendTo(":eq(0)");var n=r.css(e);return r.remove(),n},get:function(t){top.__utils__get__=top.__utils__get__||{};var e=JSON.stringify(t);t.cache&&top.__utils__get__[e]?(t.success&&t.success(top.__utils__get__[e]),window.console.debug("utils.js::get() - Fetching from cache ["+t.url+"].")):n({url:t.url,data:t.data,success:function(r){top.__utils__get__[e]=r,t.success&&t.success(r)},error:function(e,r){t.error&&t.error(e,r)}})},merge:function(t,e){return t?_.defaults(t,e):e},iframe:function(t){return'<iframe src="'+t+'" frameborder="0" style="width: 100%; height: 100%;"/>'},bytesToString:function(t,e,r){r=void 0!==r?r:1;var n="";if(t>=l)t/=l,n="TB";else if(t>=o)t/=o,n="GB";else if(t>=u)t/=u,n="MB";else if(t>=s)t/=s,n="KB";else{if(!(t>0))return e?"0 b":"<strong>-</strong>";n="b"}var a="b"==n?t:i(t,r);return e?a+" "+n:"<strong>"+a+"</strong> "+n},uid:function(){return top.__utils__uid__=top.__utils__uid__||0,"uid-"+top.__utils__uid__++},time:function(){var t=new Date,e=(t.getHours()<10?"0":"")+t.getHours(),r=(t.getMinutes()<10?"0":"")+t.getMinutes();return t.getDate()+"/"+(t.getMonth()+1)+"/"+t.getFullYear()+", "+e+":"+r},request:n,sanitize:function(t){return $("<div/>").text(t).html()},textify:function(t){if($.isArray(t)){var e=(t=t.toString().replace(/,/g,", ")).lastIndexOf(", ");return-1!=e&&(t=t.substr(0,e)+" or "+t.substr(e+2)),t}return""},isEmpty:function(t){if(t instanceof Array||(t=[t]),0===t.length)return!0;for(var e in t)if(["__null__","__undefined__",null,void 0].indexOf(t[e])>-1)return!0;return!1},deepeach:r,isJSON:function(t){return/^[\],:{}\s]*$/.test(t.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))},clone:function(t){return JSON.parse(JSON.stringify(t)||null)},linkify:function(t){var e,r,n,i;return r=/(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim,e=t.replace(r,'<a href="$1" target="_blank">$1</a>'),n=/(^|[^\/])(www\.[\S]+(\b|$))/gim,e=e.replace(n,'$1<a href="http://$2" target="_blank">$2</a>'),i=/(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim,e=e.replace(i,'<a href="mailto:$1">$1</a>')},appendScriptStyle:function(t){t.script&&""!==t.script&&$("<script/>",{type:"text/javascript"}).text(t.script).appendTo("head"),t.styles&&""!==t.styles&&$("<style/>",{type:"text/css"}).text(t.styles).appendTo("head")},getQueryString:function(t){return decodeURIComponent(window.location.search.replace(new RegExp("^(?:.*[&\\?]"+encodeURIComponent(t).replace(/[\.\+\*]/g,"\\$&")+"(?:\\=([^&]*))?)?.*$","i"),"$1"))},setWindowTitle:function(t){window.document.title=t?"Galaxy "+(window.Galaxy.config.brand?" | "+window.Galaxy.config.brand:"")+" | "+(0,a.default)(t):"Galaxy "+(window.Galaxy.config.brand?" | "+window.Galaxy.config.brand:"")}}});
|
||||
define("utils/utils",["exports","utils/localization"],function(e,t){"use strict";function r(e){return'<iframe src="'+e+'" frameborder="0" style="width: 100%; height: 100%;"/>'}function n(e,t){for(var r in e){var i=e[r];if(_.isObject(i)){var a=t(i);a&&(e[r]=a),n(i,t)}}}function i(e){var t,r,n,i;return r=/(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim,t=e.replace(r,'<a href="$1" target="_blank">$1</a>'),n=/(^|[^\/])(www\.[\S]+(\b|$))/gim,t=t.replace(n,'$1<a href="http://$2" target="_blank">$2</a>'),i=/(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim,t=t.replace(i,'<a href="mailto:$1">$1</a>')}function a(e){return JSON.parse(JSON.stringify(e)||null)}function s(e){return/^[\],:{}\s]*$/.test(e.replace(/\\["\\\/bfnrtu]/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,"]").replace(/(?:^|:|,)(?:\s*\[)+/g,""))}function u(e){return $("<div/>").text(e).html()}function o(e){if(e instanceof Array||(e=[e]),0===e.length)return!0;for(var t in e)if(["__null__","__undefined__",null,void 0].indexOf(e[t])>-1)return!0;return!1}function l(e){if($.isArray(e)){var t=(e=e.toString().replace(/,/g,", ")).lastIndexOf(", ");return-1!=t&&(e=e.substr(0,t)+" or "+e.substr(t+2)),e}return""}function c(e){top.__utils__get__=top.__utils__get__||{};var t=JSON.stringify(e);e.cache&&top.__utils__get__[t]?(e.success&&e.success(top.__utils__get__[t]),window.console.debug("utils.js::get() - Fetching from cache ["+e.url+"].")):f({url:e.url,data:e.data,success:function(r){top.__utils__get__[t]=r,e.success&&e.success(r)},error:function(t,r){e.error&&e.error(t,r)}})}function f(e){var t={contentType:"application/json",type:e.type||"GET",data:e.data||{},url:e.url};"GET"==t.type||"DELETE"==t.type?($.isEmptyObject(t.data)||(t.url+=-1==t.url.indexOf("?")?"?":"&",t.url+=$.param(t.data,!0)),t.data=null):(t.dataType="json",t.url=t.url,t.data=JSON.stringify(t.data)),$.ajax(t).done(function(t){if("string"==typeof t)try{t=t.replace("Infinity,",'"Infinity",'),t=jQuery.parseJSON(t)}catch(e){console.debug(e)}e.success&&e.success(t)}).fail(function(t){var r=null;try{r=jQuery.parseJSON(t.responseText)}catch(e){r=t.responseText}e.error&&e.error(r,t.status)}).always(function(){e.complete&&e.complete()})}function d(e,t){var r=$('<div class="'+e+'"></div>');r.appendTo(":eq(0)");var n=r.css(t);return r.remove(),n}function p(e){$('link[href^="'+e+'"]').length||$('<link href="'+Galaxy.root+e+'" rel="stylesheet">').appendTo("head")}function g(e,t){return e?_.defaults(e,t):t}function y(e,t){for(var r=1,n=0;n<t;n++)r*=10;return Math.round(e*r)/r}function h(e,t,r){r=void 0!==r?r:1;var n="";if(e>=j)e/=j,n="TB";else if(e>=G)e/=G,n="GB";else if(e>=O)e/=O,n="MB";else if(e>=T)e/=T,n="KB";else{if(!(e>0))return t?"0 b":"<strong>-</strong>";n="b"}var i="b"==n?e:y(e,r);return t?i+" "+n:"<strong>"+i+"</strong> "+n}function m(){return top.__utils__uid__=top.__utils__uid__||0,"uid-"+top.__utils__uid__++}function b(){var e=new Date,t=(e.getHours()<10?"0":"")+e.getHours(),r=(e.getMinutes()<10?"0":"")+e.getMinutes();return e.getDate()+"/"+(e.getMonth()+1)+"/"+e.getFullYear()+", "+t+":"+r}function v(e){e.script&&""!==e.script&&$("<script/>",{type:"text/javascript"}).text(e.script).appendTo("head"),e.styles&&""!==e.styles&&$("<style/>",{type:"text/css"}).text(e.styles).appendTo("head")}function w(e){return decodeURIComponent(window.location.search.replace(new RegExp("^(?:.*[&\\?]"+encodeURIComponent(e).replace(/[\.\+\*]/g,"\\$&")+"(?:\\=([^&]*))?)?.*$","i"),"$1"))}function x(e){window.document.title=e?"Galaxy "+(window.Galaxy.config.brand?" | "+window.Galaxy.config.brand:"")+" | "+(0,S.default)(e):"Galaxy "+(window.Galaxy.config.brand?" | "+window.Galaxy.config.brand:"")}Object.defineProperty(e,"__esModule",{value:!0}),e.iframe=r,e.deepeach=n,e.linkify=i,e.clone=a,e.isJSON=s,e.sanitize=u,e.isEmpty=o,e.textify=l,e.get=c,e.request=f,e.cssGetAttribute=d,e.cssLoadFile=p,e.merge=g,e.roundToDecimalPlaces=y,e.bytesToString=h,e.uid=m,e.time=b,e.appendScriptStyle=v,e.getQueryString=w,e.setWindowTitle=x;var S=function(e){return e&&e.__esModule?e:{default:e}}(t),T=1024,O=T*T,G=O*T,j=G*T;e.default={cssLoadFile:p,cssGetAttribute:d,get:c,merge:g,iframe:r,bytesToString:h,uid:m,time:b,request:f,sanitize:u,textify:l,isEmpty:o,deepeach:n,isJSON:s,clone:a,linkify:i,appendScriptStyle:v,getQueryString:w,setWindowTitle:x}});
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
<%def name="javascripts()">
|
||||
${parent.javascripts()}
|
||||
${h.js("bundled/masthead.bundled")}
|
||||
${h.js("bundled/extended.bundled")}
|
||||
</%def>
|
||||
|
||||
<%def name="late_javascripts()">
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
}
|
||||
// TODO: ?? move above to base_panels.mako?
|
||||
$( function() {
|
||||
window.masthead(${h.dumps(masthead_config)});
|
||||
window.bundleEntries.masthead(${h.dumps(masthead_config)});
|
||||
});
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
@@ -72,15 +72,11 @@
|
||||
${h.js(
|
||||
## TODO: remove when all libs are required directly in modules
|
||||
'bundled/libs.bundled',
|
||||
'bundled/masthead.bundled',
|
||||
'bundled/extended.bundled',
|
||||
'libs/d3',
|
||||
'libs/require',
|
||||
)}
|
||||
|
||||
%if self.galaxy_config.get('bundle', None):
|
||||
${h.js('bundled/%s.bundled' % self.galaxy_config.get('bundle'))}
|
||||
%endif
|
||||
|
||||
<script type="text/javascript">
|
||||
// configure require
|
||||
// due to our using both script tags and require, we need to access the same jq in both for plugin retention
|
||||
@@ -127,10 +123,10 @@
|
||||
// load any app configured
|
||||
define( 'app', function(){
|
||||
var jscript = galaxy_config.app.jscript;
|
||||
if( galaxy_config.app.jscript && window[galaxy_config.app.jscript]){
|
||||
if( galaxy_config.app.jscript && window.bundleEntries[galaxy_config.app.jscript]){
|
||||
$( function(){
|
||||
// load galaxy module application
|
||||
window[galaxy_config.app.jscript]();
|
||||
window.bundleEntries[galaxy_config.app.jscript]();
|
||||
});
|
||||
} else {
|
||||
console.error("'galaxy_config.app.jscript' missing.");
|
||||
|
||||
@@ -44,12 +44,12 @@
|
||||
"libs/jquery/jquery.form",
|
||||
"libs/jquery/jstorage",
|
||||
"libs/jquery/jquery.autocomplete",
|
||||
"bundled/workflow.bundled"
|
||||
"bundled/extended.bundled"
|
||||
)}
|
||||
|
||||
<script type='text/javascript'>
|
||||
$( function() {
|
||||
workflowApp(${h.dumps(self.editor_config)});
|
||||
window.bundleEntries.workflow(${h.dumps(self.editor_config)});
|
||||
});
|
||||
</script>
|
||||
</%def>
|
||||
|
||||
@@ -36,11 +36,6 @@ else:
|
||||
assert sys.version_info[:2] >= (2, 7)
|
||||
|
||||
|
||||
def stop_err(msg, ret=1):
|
||||
sys.stderr.write(msg)
|
||||
sys.exit(ret)
|
||||
|
||||
|
||||
def file_err(msg, dataset, json_file):
|
||||
json_file.write(dumps(dict(type='dataset',
|
||||
ext='data',
|
||||
@@ -249,22 +244,18 @@ def add_file(dataset, registry, json_file, output_path):
|
||||
dataset.name = uncompressed_name
|
||||
data_type = 'zip'
|
||||
if not data_type:
|
||||
# TODO refactor this logic. check_binary isn't guaranteed to be
|
||||
# correct since it only looks at whether the first 100 chars are
|
||||
# printable or not. If someone specifies a known unsniffable
|
||||
# binary datatype and check_binary fails, the file gets mangled.
|
||||
if check_binary(dataset.path) or Binary.is_ext_unsniffable(dataset.file_type):
|
||||
if check_binary(dataset.path) or registry.is_extension_unsniffable_binary(dataset.file_type):
|
||||
# We have a binary dataset, but it is not Bam, Sff or Pdf
|
||||
data_type = 'binary'
|
||||
# binary_ok = False
|
||||
parts = dataset.name.split(".")
|
||||
if len(parts) > 1:
|
||||
ext = parts[-1].strip().lower()
|
||||
if check_content and not Binary.is_ext_unsniffable(ext):
|
||||
is_ext_unsniffable_binary = registry.is_extension_unsniffable_binary(ext)
|
||||
if check_content and not is_ext_unsniffable_binary:
|
||||
file_err('The uploaded binary file contains inappropriate content', dataset, json_file)
|
||||
return
|
||||
elif Binary.is_ext_unsniffable(ext) and dataset.file_type != ext:
|
||||
err_msg = "You must manually set the 'File Format' to '%s' when uploading %s files." % (ext.capitalize(), ext)
|
||||
elif is_ext_unsniffable_binary and dataset.file_type != ext:
|
||||
err_msg = "You must manually set the 'File Format' to '%s' when uploading %s files." % (ext, ext)
|
||||
file_err(err_msg, dataset, json_file)
|
||||
return
|
||||
if not data_type:
|
||||
|
||||
Reference in New Issue
Block a user