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); } //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; // Grab all of our URLs var queryServiceUrl = appModel.get('queryServiceUrl'); var packageServiceUrl = appModel.get('packageServiceUrl'); //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"; } //Draw and insert the HTML table this.$el.html(this.template({ readsEnabled : this.readsEnabled, 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.get("id")); 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