define(['jquery', 'underscore', 'backbone',
'models/PackageModel',
'views/DownloadButtonView',
'text!templates/downloadContents.html'],
function($, _, Backbone, Package, DownloadButtonView, Template) {
'use strict';
var PackageTable = Backbone.View.extend({
template: _.template(Template),
type: "PackageTable",
tagName : "div",
className : "download-contents",
events: {
"click .expand-control" : "expand",
"click .collapse-control" : "collapse"
},
initialize: function(options){
if((options === undefined) || (!options)) var options = {};
this.packageId = options.packageId || null;
this.memberId = options.memberId || null;
this.attributes = options.attributes || null;
this.className += options.className || "";
this.currentlyViewing = options.currentlyViewing || null;
this.numVisible = options.numVisible || 4;
this.parentView = options.parentView || null;
this.title = options.title || "";
this.nested = (typeof options.nested === "undefined")? false : options.nested;
//Set up the Package model
if((typeof options.model === "undefined") || !options.model){
this.model = new Package();
this.model.set("memberId", this.memberId);
this.model.set("packageId", this.packageId);
}
if(!(typeof options.metricsModel == "undefined")){
this.metricsModel = options.metricsModel;
}
//Get the members
if(this.packageId) this.model.getMembers();
else if(this.memberId) this.model.getMembersByMemberID(this.memberId);
this.onMetadataView = (this.parentView && this.parentView.type == "Metadata");
this.hasEntityDetails = (this.onMetadataView && (this.model.get("members") && this.model.get("members").length < 150))? this.parentView.hasEntityDetails() : false;
this.listenTo(this.model, "changeAll", this.render);
},
/*
* Creates a table of package/download contents that this metadata doc is a part of
*/
render: function(){
var view = this,
members = this.model.get("members");
//If the model isn't complete, we may be still waiting on a response from the index so don't render anything yet
if(!this.model.complete) return false;
//Start the HTML for the rows
var tbody = $(document.createElement("tbody"));
//Filter out the packages from the member list
members = _.filter(members, function(m){ return(m.type != "Package") });
//Filter the members in order of preferred appearance
members = this.sort(members);
this.sortedMembers = members;
var metadata = this.model.getMetadata();
//Count the number of rows in this table
var numRows = members.length;
//Cut down the members list to only those that will be visible
members = members.slice(0, this.numVisible);
this.rowsComplete = false;
//Create the HTML for each row
_.each(members, function(solrResult){
//Append the row element
$(tbody).append(view.getMemberRow(solrResult));
});
var bodyRows = $(tbody).find("tr");
this.numHidden = numRows - this.numVisible;
//Draw the footer which will have an expandable/collapsable control
if(this.numHidden > 0){
var tfoot = $(document.createElement("tfoot")),
tfootRow = $(document.createElement("tr")),
tfootCell = $(document.createElement("th")).attr("colspan", "100%"),
item = (this.numHidden == 1)? "item" : "items",
expandLink = $(document.createElement("a")).addClass("expand-control control").text("Show " + this.numHidden + " more " + item + " in this data set"),
expandIcon = $(document.createElement("i")).addClass("icon icon-caret-right icon-on-left"),
collapseLink = $(document.createElement("a")).addClass("collapse-control control").text("Show less").css("display", "none"),
collapseIcon = $(document.createElement("i")).addClass("icon icon-caret-up icon-on-left");
$(tfoot).append(tfootRow);
$(tfootRow).append(tfootCell);
$(tfootCell).append(expandLink, collapseLink);
$(expandLink).prepend(expandIcon);
$(collapseLink).prepend(collapseIcon);
}
if(bodyRows.length == 0){
tbody.html("
This is an empty dataset. |
");
}
if(!this.title && metadata){
this.title = 'Files in this dataset';
if(this.model.get("id"))
this.title += ' Package: ' + this.model.get("id") + '';
this.title += '';
}
else if(!this.title && !metadata){
this.title = "Files in this dataset";
}
this.$el.html(this.template({
title : this.title || "Files in this dataset",
metadata : this.nested ? metadata : null,
colspan : bodyRows.first().find("td").length,
packageId : this.model.get("id"),
nested : this.nested
}));
//Insert the Download All button
if(this.model.getURL() && this.model.get("id")){
var downloadBtn = new DownloadButtonView({ model: this.model });
downloadBtn.render();
this.$(".download-container").append(downloadBtn.el);
}
//Add the table body and footer
this.$("thead").after(tbody);
if(typeof tfoot !== "undefined") this.$(tbody).after(tfoot);
return this;
},
sort: function(models){
//Default to the package model members as the models to sort
if(!models){
var models = this.model.get("members");
//If this model doesn't have members, return an empty array or a falsey value
if(!models) return models;
}
// One == already sorted!
if(models.length == 1) return models;
//If there are too many models to sort (takes too much time) then just get the metadata to display first
else if(models.length > 150){
var view = this;
//Find the metadata doc we are currently viewing
var currentMetadata = _.find(models, function(m){ return (m.get("id") == view.currentlyViewing) });
//Add it to the front
if(currentMetadata){
models = _.without(models, currentMetadata);
models.unshift(currentMetadata);
}
//Return the newly sorted array
return models;
}
var view = this,
metadataView = this.onMetadataView? this.parentView : null;
//** If this is not a nested package AND the parent view is the metadata view, then sort by order of appearance in the metadata **/
if(!this.nested && (metadataView && !_.findWhere(metadataView.subviews, {type: "MetadataIndex"}))){
if(metadataView.hasEntityDetails()){
//If we are currently viewing a metadata document, find it
if(this.currentlyViewing)
var currentMetadata = _.find(models, function(m){ return (m.get("id") == view.currentlyViewing) });
//For each model, find its position on the Metadata View page
var numNotFound = 0;
_.each(models, function(model){
if(currentMetadata == model) return;
var container = view.parentView.findEntityDetailsContainer(model);
if(container) model.offsetTop = $(container)[0].offsetTop;
else{
model.offsetTop = window.outerHeight;
numNotFound++;
}
});
//Continue only if we found the entity details section for at least one model, if not, sort by the default method later
if(numNotFound < models.length-1){ //Minus 1 since we don't count the metadata
//Sort the models by this position
models = _.sortBy(models, "offsetTop");
//Move the metadata model that we are currently viewing in the Metadata view to the top
if(currentMetadata){
models = _.without(models, currentMetadata);
models.unshift(currentMetadata);
}
//Flatten the array in case we have nesting
models = _.flatten(models);
//Return the sorted array
return models;
}
}
}
//** For tables with no accompanying metadata (nested or not on the Metadata View), default to sorting by group then alpha by name**/
//Split the members of this package into groups based on their format type (metaata, data, image, code, etc)
var groupedModels = _.groupBy(models, function(m){
if(!m.get("type") || (typeof m.get("type") == "undefined"))
return "data";
return m.get("type");
}),
sortedModels = [];
var rowOrder = ["metadata", "image", "PDF", "program", "data", "annotation"];
for(var i=0; i/view/" + encodeURIComponent(id))
.addClass("preview")
.attr("data-id", id)
.text("More info");
$(moreInfoCell).append(moreInfo);
}
$(tr).append(moreInfoCell);
//Format id cell
var fileTypeCell = $(document.createElement("td")).addClass("formatId wrap-contents");
$(fileTypeCell).html(memberModel.getFormat());
$(tr).append(fileTypeCell);
//File size cell
var sizeCell = $(document.createElement("td")).addClass("size");
var size = memberModel.bytesToSize();
$(sizeCell).text(size);
$(tr).append(sizeCell);
if( MetacatUI.appModel.get("displayDatasetMetrics") ){
// Retreiving the Package Metrics Counts from the Metrics Model
// Adding a Metric Cell for the corresponding DataONE object in the table
var readsCell = $(document.createElement("td"))
.addClass("metrics-count downloads")
.attr("data-id", id);
$(tr).append(readsCell);
if( !memberModel.hideMetrics() ){
// If the model has already been fethced.
if (this.metricsModel.get("views") !== null) {
readsCell.append(this.getMemberRowMetrics(id, formatType));
}
else {
// Update the metrics later on
// If the fetch() is still in progress.
this.listenTo(this.metricsModel, "sync", function(){
var readsCell = this.$('.metrics-count.downloads[data-id="' + id + '"]');
readsCell.text(this.getMemberRowMetrics(id, formatType));
});
}
}
}
//Download button cell
var downloadBtnCell = $(document.createElement("td")).addClass("download-btn btn-container");
var downloadButton = new DownloadButtonView({ model: memberModel });
downloadButton.render();
$(downloadBtnCell).append(downloadButton.el);
$(tr).append(downloadBtnCell);
if(collapsable)
tr.addClass("collapse");
if(hidden)
tr.css("display", "none");
return tr;
},
// Member row metrics for the package table
// Retrieving information from the Metrics Model's result details
getMemberRowMetrics: function(id, formatType) {
if(typeof this.metricsModel !== "undefined"){
var metricsResultDetails = this.metricsModel.get("resultDetails");
if( typeof metricsResultDetails !== "undefined" && metricsResultDetails ){
var metricsPackageDetails = metricsResultDetails["metrics_package_counts"];
var objectLevelMetrics = metricsPackageDetails[id];
if(typeof objectLevelMetrics !== "undefined") {
if(formatType == "METADATA") {
var reads = objectLevelMetrics["viewCount"];
}
else {
var reads = objectLevelMetrics["downloadCount"];
}
}
else{
var reads = 0;
}
}
else{
var reads = 0;
}
}
if((typeof reads !== "undefined") && reads){
// giving labels
if(formatType == "METADATA" && reads == 1)
reads += " view";
else if(formatType == "METADATA")
reads += " views";
else if(reads == 1)
reads += " download";
else
reads += " downloads";
}
else {
// returning an empty string if the metrics are 0
reads = "";
}
return reads;
},
expand: function(e){
//Don't do anything...
e.preventDefault();
var view = this;
//If this is a nested dataset, we need to actually draw the remaining rows
if(!this.rowsComplete){
var tbody = this.$("tbody");
//Create the HTML for each row
var members = this.sortedMembers.slice(this.numVisible);
_.each(members, function(solrResult){
//Append the row element
$(tbody).append(view.getMemberRow(solrResult, { collapsable: true }));
});
//Make the view as complete so we don't do this again
this.rowsComplete = true;
}
this.$("tr.collapse").fadeIn();
this.$(".expand-control").fadeOut(function(){
view.$(".collapse-control").fadeIn("fast");
view.$(".tooltip-this").tooltip();
});
},
collapse: function(e){
//Don't do anything...
e.preventDefault();
var view = this;
this.$("tr.collapse").fadeOut();
this.$(".collapse-control").fadeOut(function(){
view.$(".expand-control").fadeIn();
});
},
checkForPrivateMembers: function(){
try{
var packageModel = this.model,
packageCollection = this.dataPackageCollection;
if( !packageModel || !packageCollection ){
return;
}
//Get the number of package members found in Solr and parsed from the RDF XML
var numMembersFromSolr = packageModel.get("members").length,
numMembersFromRDF = packageCollection.length;
//If there are more package members in the RDF XML tthan found in SOlr, we
// can assume that those objects are private.
if( numMembersFromRDF > numMembersFromSolr ){
var downloadButtons = this.$(".btn.download");
for( var i=0; i -1 ||
downloadURL.indexOf( encodeURIComponent(packageModel.get("id"))) > -1 ){
//Disable this download button
$(btn).attr("disabled", "disabled")
.addClass("disabled")
.attr("href", "")
.tooltip({
trigger: "hover",
placement: "top",
delay: 500,
title: "This dataset may contain private data, so each data file should be downloaded individually."
});
i = downloadButtons.length;
}
}
}
}
catch(e){
console.error(e);
}
}
/*showDownloadProgress: function(e){
e.preventDefault();
var button = $(e.target);
button.addClass("in-progress");
button.html("Downloading... ");
return true;
}*/
});
return PackageTable;
});