Merge branch 'dev' into remove_formbuilder

This commit is contained in:
guerler
2017-12-05 16:39:45 -05:00
90 changed files with 2534 additions and 2001 deletions
@@ -1,7 +0,0 @@
import AdminToolshed from "admin.toolshed";
export function App(options) {
new AdminToolshed.GalaxyApp(options);
}
window.adminToolshedApp = App;
+50
View File
@@ -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;
-7
View File
@@ -1,7 +0,0 @@
import GalaxyLibrary from "galaxy.library";
export function App(options) {
new GalaxyLibrary.GalaxyApp(options);
}
window.libraryApp = App;
-16
View File
@@ -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;
-13
View File
@@ -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;
-7
View File
@@ -1,7 +0,0 @@
import WorkflowView from "mvc/workflow/workflow-view";
export default function workflowApp(options) {
new WorkflowView(options);
}
window.workflowApp = workflowApp;
+15 -10
View File
@@ -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;
},
+13 -5
View File
@@ -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 */
+12 -6
View File
@@ -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>"
+22 -7
View File
@@ -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 -1
View File
@@ -1,4 +1,4 @@
var View = Backbone.View.extend({
export var View = Backbone.View.extend({
className: "ui-modal",
// defaults
+2 -1
View File
@@ -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 -3
View File
@@ -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) ||
+11 -9
View File
@@ -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")
+21 -21
View File
@@ -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
+3
View File
@@ -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": {
+1 -5
View File
@@ -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
View File
@@ -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"
+1 -1
View File
@@ -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"
})
]
};
+2 -21
View File
@@ -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"
-3
View File
@@ -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"
+4
View File
@@ -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
+1 -2
View File
@@ -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,
+3 -3
View File
@@ -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
+11 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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("&nbsp;"),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("&nbsp;"),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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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}});
+1 -1
View File
@@ -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>
+3 -7
View File
@@ -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>
+5 -14
View File
@@ -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: