371 lines
13 KiB
JavaScript
371 lines
13 KiB
JavaScript
/**
|
|
* Updates the Hanging Protocol Select2 Input
|
|
*/
|
|
function updateProtocolSelect() {
|
|
// Loop through the available HangingProtocols
|
|
// to create an array with the protocols that includes
|
|
// a property labelled 'text', so that Select2 has something
|
|
// to display
|
|
var protocols = HangingProtocols.find().map(function(protocol) {
|
|
protocol.text = protocol.name;
|
|
return protocol;
|
|
});
|
|
|
|
// Select the Protocol select DOM element
|
|
var protocolSelect = $('#protocolSelect');
|
|
|
|
// Empty the element using Select2 for rerendering
|
|
protocolSelect.select2().empty();
|
|
|
|
// Initialize the select element with Select2 using the
|
|
// array of protocols
|
|
protocolSelect.select2({
|
|
data: protocols
|
|
});
|
|
|
|
// Update the ProtocolSelector to display the current active Protocol
|
|
protocolSelect.select2().val(ProtocolEngine.protocol.id).trigger('change');
|
|
}
|
|
|
|
Template.protocolEditor.onRendered(function() {
|
|
this.timeAgoInterval = Meteor.setInterval(function() {
|
|
// Run this every minute
|
|
Session.set('timeAgoVariable', new Date());
|
|
}, 60000);
|
|
|
|
// Subscribe to the Hanging Protocols Collection
|
|
this.subscribe('hangingprotocols', function() {
|
|
// Update the Protocol select box when the Collection is ready
|
|
updateProtocolSelect();
|
|
});
|
|
});
|
|
|
|
Template.protocolEditor.onDestroyed(function() {
|
|
Meteor.clearInterval(this.timeAgoInterval);
|
|
});
|
|
|
|
Template.protocolEditor.helpers({
|
|
/**
|
|
* Reactively updates the active Protocol
|
|
*
|
|
* @returns {*} The currently active Protocol Model
|
|
*/
|
|
activeProtocol: function() {
|
|
// Whenever the Layout Manager is updated, trigger this helper
|
|
Session.get('LayoutManagerUpdated');
|
|
|
|
// If no ProtocolEngine, protocol, or stage is defined, stop here
|
|
if (!ProtocolEngine ||
|
|
!ProtocolEngine.protocol ||
|
|
ProtocolEngine.stage === undefined) {
|
|
return;
|
|
}
|
|
|
|
// Update the Protocol Select box
|
|
updateProtocolSelect();
|
|
|
|
// Find the protocol in the database
|
|
var protocolInDatabase = HangingProtocols.findOne({
|
|
id: ProtocolEngine.protocol.id
|
|
});
|
|
|
|
// Give the current Protocol an _id property from the Database
|
|
if (protocolInDatabase) {
|
|
ProtocolEngine.protocol._id = protocolInDatabase._id;
|
|
}
|
|
|
|
// Make sure that the number of referenced priors is correct
|
|
ProtocolEngine.protocol.updateNumberOfPriorsReferenced();
|
|
|
|
// Otherwise, return the active Hanging Protocol
|
|
return ProtocolEngine.protocol;
|
|
},
|
|
/**
|
|
* Reactively updates the active Protocol Stage
|
|
*
|
|
* @returns {*} The current Protocol's active Stage model
|
|
*/
|
|
activeStage: function() {
|
|
// Whenever the Layout Manager is updated, trigger this helper
|
|
Session.get('LayoutManagerUpdated');
|
|
|
|
// If no ProtocolEngine, protocol, or stage is defined, stop here
|
|
if (!ProtocolEngine ||
|
|
!ProtocolEngine.protocol ||
|
|
ProtocolEngine.stage === undefined) {
|
|
return;
|
|
}
|
|
|
|
// Retrieve the Stage Model for the current Protocol's active Stage
|
|
var stage = ProtocolEngine.getCurrentStageModel();
|
|
if (!stage) {
|
|
return;
|
|
}
|
|
|
|
// Update active Stage's layout template and properties based on the displayed
|
|
// layout properties. This is used to update the Stage Model when the user modifies
|
|
// the layout in the viewer
|
|
stage.viewportStructure.layoutTemplateName = layoutManager.layoutTemplateName;
|
|
stage.viewportStructure.properties = layoutManager.layoutProps;
|
|
|
|
// If there is a discrepancy between the Stage's number of viewports and the
|
|
// the number of required viewports given the properties above, rectify it
|
|
// by removing or adding Viewports to the stage
|
|
//
|
|
// First, calculate the difference, if any exists
|
|
var difference = stage.viewportStructure.getNumViewports() - stage.viewports.length;
|
|
|
|
if (difference < 0) {
|
|
// Make the viewport difference into a positive value
|
|
var absDifference = Math.abs(difference);
|
|
|
|
// If there are more Viewports defined than necessary, remove the extraneous Viewports
|
|
var position = stage.viewports.length - absDifference;
|
|
|
|
// Splice extra viewports from the Stage's viewports array
|
|
stage.viewports.splice(position, absDifference);
|
|
} else if (difference > 0) {
|
|
// If there are less Viewports defined than necessary, add viewports until we reach the
|
|
// required amount
|
|
|
|
// Count up until the difference in number of Viewports
|
|
for (var i = 0; i < difference; i++) {
|
|
// Instantiate a new Viewport Model
|
|
var viewport = new HP.Viewport();
|
|
|
|
// Add new Viewports to the Stage's viewports array
|
|
stage.viewports.push(viewport);
|
|
}
|
|
}
|
|
|
|
// Return the current Stage model for the active Protocol
|
|
return ProtocolEngine.getCurrentStageModel();
|
|
},
|
|
activeViewportUndefined: function() {
|
|
return (Session.get('activeViewport') === undefined);
|
|
}
|
|
});
|
|
|
|
Template.protocolEditor.events({
|
|
/**
|
|
* Creates a new Hanging Protocol and displays it in the Viewer
|
|
*/
|
|
'click #newProtocol': function() {
|
|
// Clone the default Protocol
|
|
var protocol = HP.defaultProtocol.createClone();
|
|
|
|
// Change the Protocol name to state that it is New, and give it a timestamp
|
|
protocol.name = 'New (created ' + moment().format('h:mm:ss a') + ')';
|
|
|
|
// Change the Protocol ID from the default value
|
|
protocol.id = uuid.new();
|
|
|
|
// Insert the Protocol into the HangingProtocols Collection
|
|
HangingProtocols.insert(protocol);
|
|
|
|
// Activate the new Protocol using the ProtocolEngine
|
|
ProtocolEngine.setHangingProtocol(protocol);
|
|
|
|
// Update the protocol selector to display the new Protocols
|
|
updateProtocolSelect();
|
|
},
|
|
/**
|
|
* Rename the current Protocol
|
|
*/
|
|
'click #renameProtocol': function() {
|
|
var selectedProtocol = this;
|
|
if (selectedProtocol.locked) {
|
|
return;
|
|
}
|
|
|
|
// Define some details for the text entry dialog
|
|
var title = 'Rename Protocol';
|
|
var instructions = 'Enter a new name';
|
|
var currentValue = selectedProtocol.name;
|
|
|
|
// Open the text entry dialog with the details above
|
|
// and fire the callback function when finished.
|
|
openTextEntryDialog(title, instructions, currentValue, function(value) {
|
|
// Update the name with the entered text
|
|
HangingProtocols.update(selectedProtocol._id, {
|
|
$set: {
|
|
name: value
|
|
}
|
|
});
|
|
|
|
selectedProtocol.name = value;
|
|
});
|
|
},
|
|
/**
|
|
* Triggers a custom event when for the HTML5 File input when files are selected
|
|
*
|
|
* @param event The Change event for the input
|
|
*/
|
|
'change .btn-file :file': function(event) {
|
|
// http://www.abeautifulsite.net/whipping-file-inputs-into-shape-with-bootstrap-3/
|
|
|
|
// Find the Input in the DOM
|
|
var input = $(event.currentTarget);
|
|
|
|
// Get the number of selected files
|
|
var numFiles = input.get(0).files ? input.get(0).files.length : 1;
|
|
|
|
// Get the label of the file
|
|
var label = input.val().replace(/\\/g, '/').replace(/.*\//, '');
|
|
|
|
// Trigger our custom event with the number of files and label
|
|
input.trigger('fileselect', [numFiles, label]);
|
|
},
|
|
/**
|
|
* Imports files selected by the user into the Hanging Protocols Collection
|
|
*
|
|
* @param event The custom fileselect event
|
|
*/
|
|
'fileselect .btn-file :file': function(event) {
|
|
// Retreieve the FileList
|
|
var files = event.target.files;
|
|
|
|
// Create an HTML5 File Reader
|
|
var reader = new FileReader();
|
|
|
|
reader.onload = function() {
|
|
var text = reader.result;
|
|
|
|
// POST the file to our protocol-import Route
|
|
// for it to be parsed and included in the
|
|
// HangingProtocols Collection
|
|
$.post('/protocol-import', {
|
|
protocol: text
|
|
}, function(resp, text, xhr) {
|
|
if (xhr.status !== 200) {
|
|
// If the server returns an error during importing, alert the user
|
|
|
|
// TODO: Use a custom dialog box, rather than "alert"
|
|
alert('Protocol import failed.');
|
|
}
|
|
});
|
|
};
|
|
|
|
// Instruct the FileReader to read the (first) selected file
|
|
// TODO: Update to allow batch uploads?
|
|
reader.readAsText(files[0], 'utf-8');
|
|
},
|
|
/**
|
|
* Set the Hanging Protocol when the select box is changed
|
|
*
|
|
* @param event The select2:select event
|
|
*/
|
|
'select2:select #protocolSelect': function(event) {
|
|
// Retrieve the protocolId
|
|
var protocolId = event.params.data.id;
|
|
|
|
// Retrieve the Protocol from the HangingProtocols Collection
|
|
var selectedProtocol = HangingProtocols.findOne({
|
|
id: protocolId
|
|
});
|
|
|
|
// If it doesn't exist, stop here
|
|
if (!selectedProtocol) {
|
|
return;
|
|
}
|
|
|
|
// Set the current Hanging Protocol to the user-specified Protocol
|
|
ProtocolEngine.setHangingProtocol(selectedProtocol);
|
|
},
|
|
/**
|
|
* Allow the Protocols / Stage navigation tabs to toggle the
|
|
* 'active' class when clicked
|
|
*/
|
|
'click .navigationButtons a': function() {
|
|
$(this).addClass('active').siblings().removeClass('active');
|
|
},
|
|
/**
|
|
* Update the HangingProtocols Collection with the latest changes to the current Protocol
|
|
*/
|
|
'click #saveProtocol': function() {
|
|
var selectedProtocol = this;
|
|
if (selectedProtocol.locked) {
|
|
return;
|
|
}
|
|
|
|
// Store the ID for the update call
|
|
var id = selectedProtocol._id;
|
|
|
|
// Remove the MongoDB _id property so that we can
|
|
// simplify the $set value
|
|
delete selectedProtocol._id;
|
|
|
|
// Update the Protocol's modifiedDate and modifiedBy User details
|
|
selectedProtocol.protocolWasModified();
|
|
|
|
// Update the current Protocol in the database with the latest changes
|
|
HangingProtocols.update(id, {
|
|
$set: selectedProtocol
|
|
});
|
|
},
|
|
/**
|
|
* Save the current Protocol as a new document in the HangingProtocols Collection
|
|
*/
|
|
'click #saveAsProtocol': function() {
|
|
var selectedProtocol = this;
|
|
|
|
// Define some details for the text entry dialog
|
|
var title = 'Save Protocol As';
|
|
var instructions = 'Enter a new name';
|
|
var currentValue = selectedProtocol.name;
|
|
|
|
// Open the text entry dialog with the details above
|
|
// and fire the callback function when finished.
|
|
openTextEntryDialog(title, instructions, currentValue, function(value) {
|
|
// Erase the MongoDB _id
|
|
delete selectedProtocol._id;
|
|
|
|
// Create a new ID for the protocol
|
|
selectedProtocol.id = uuid.new();
|
|
|
|
// Update the name with the entered text
|
|
selectedProtocol.name = value;
|
|
|
|
// Update the Protocol's modifiedDate and modifiedBy User details
|
|
selectedProtocol.protocolWasModified();
|
|
|
|
// Insert the new Protocol
|
|
HangingProtocols.insert(selectedProtocol);
|
|
});
|
|
},
|
|
/**
|
|
* Export the currently selected Protocol as a JSON file
|
|
*/
|
|
'click #exportJSON': function() {
|
|
// Tell the User's Browser to download the JSON file by routing a hidden iframe to our
|
|
// protocol-export Route. This prevents the tab from changing its current content.
|
|
var selectedProtocol = this;
|
|
document.getElementById('download_iframe').src = '/protocol-export/' + selectedProtocol.id;
|
|
},
|
|
/**
|
|
* Delete the currently selected Protocol
|
|
*/
|
|
'click #deleteProtocol': function() {
|
|
var selectedProtocol = this;
|
|
if (selectedProtocol.locked) {
|
|
return;
|
|
}
|
|
|
|
var options = {
|
|
title: 'Delete Protocol',
|
|
text: 'Are you sure you would like to remove this Protocol? This cannot be reversed.'
|
|
};
|
|
|
|
showConfirmDialog(function() {
|
|
// Send a call to remove the Protocol from the HangingProtocols Collection on the server
|
|
Meteor.call('removeHangingProtocol', selectedProtocol._id);
|
|
|
|
// Reset the ProtocolEngine to the next best match
|
|
ProtocolEngine.reset();
|
|
|
|
// Update the protocol selector
|
|
updateProtocolSelect();
|
|
}, options);
|
|
}
|
|
});
|