<commit_before>/* filesView Plugin
 * Depends:
 *	ui.core.js
 * 	ui.view.js
 *

 Author 
 <NAME> (<EMAIL>) 

 License
 Copyright (c) 2010 Massachusetts Institute of Technology.
 MIT License (cf. MIT-LICENSE.txt or http://www.opensource.org/licenses/mit-license.php)
*/

(function($) {
    var V_OBJ = $.extend({},$.ui.view.prototype,{
	    _create: function() {
		$.ui.view.prototype._create.call(this);
		var self = this;
		self._model		= null;
		self._id_ensemble	= null;
		self._id_folder		= null;
		self._admin		= self.options.admin;
		self._me		= $.concierge.get_component("get_userinfo")();
		self._menu_items	= $();
		self._menu_items_reg	= $("<ul id='contextmenu_filesview' class='contextMenu'/>");
		self._menu_items_admin	= $("<ul id='contextmenu_filesview' class='contextMenu'><li class='rename'><a href='#rename'>Rename</a></li><li class='move'><a href='#move'>Move</a></li><li class='update'><a href='#update'>Update</a></li><li class='assignment'><a href='#assignment'>Edit Assignment</a></li><li class='delete separator'><a href='#delete'>Delete</a></li></ul>");
		self._scrollTimerID =  null;
		//self._firstrender = true;
		self._defaultopen = null;

		
		self.element.addClass("filesView");
		$(document).on("click", "button[action=add_file]", function(){
			$.concierge.get_component("add_file_menu")({id_ensemble: self._id_ensemble, id_folder:  self._id_folder});
		    });
		$(document).on("click","button[action=add_folder]", function(){
			$.concierge.get_component("add_folder_menu")({id_ensemble: self._id_ensemble, id_folder:  self._id_folder});
		    });
		$(document).on("click","button[action=invite_users]", function(){
			$.concierge.get_component("invite_users_menu")({id_ensemble: self._id_ensemble});
		    });
	
		$.mods.declare({
			filesView1: {js: [], css: ["/content/modules/dev/ui.filesview.css"]}, 
			    contextmenu: {js:["/content/modules/contextmenu/jquery.contextMenu.js"] , css: ["/content/modules/contextmenu/jquery.contextMenu.css"]}});
		$.mods.ready("filesView1", function(){});
		$.mods.ready("contextmenu", function(){});
		
		
	    },
	    _defaultHandler: function(evt){
		switch (evt.type){
		case "folder": 
		this._id_ensemble	= this._model.o.folder[evt.value].id_ensemble;
		this._id_folder		= evt.value;
		break;
		case "ensemble": 
		this._id_ensemble	= evt.value==0 ? null : evt.value;
		this._id_folder		= null;
		break;
		case "home": 
		this._id_ensemble	= null;
		this._id_folder		= null;
		break;
		/*
		case "rate_reply": 
		$("#filesView-pending-list li[comment_id="+evt.value.comment_id+"] button").attr("disabled", "disabled");
		break;
		*/
		}		
		this._render();
	    },
	    _filelens: function(f){
		var self=this;
		var ckey = $.concierge.get_component("get_userinfo")().ckey;
		var opts = this._admin ? "<td><a href='javascript:void(0)' class='optionmenu'>Actions</a></td>" : "" ;
		var assignment_info = f.assignment ? ("Yes - due "+f.due.substring(4,0)+"-"+f.due.substring(7,5)+"-"+f.due.substring(10,8)+" at "+f.due.substring(13,11)+":"+f.due.substring(16,14)) :"<span>No</span>";
		var download = "";
		if (self._admin || self._model.o.ensemble[f.id_ensemble].allow_download ){
		    download = "<td><a target='_blank' href='"+this.options.img_server+"/pdf/repository/"+f.ID+"?ckey="+ckey+"'>original</a></td>";
		}
		var f_stats =  self._model.o.file_stats[f.ID];
		var stats = f_stats ? "<td><a title='You wrote  "+f_stats.mine+" comments on this file.' class='collagelink' target='_blank' href='/collage?q=auth&amp;id_source="+f.ID+"'><span class='collagelink-caption'> me </span><div class='collagelink-number'> "+f_stats.mine+"</div></a> <a title=\"There are "+(f_stats.total-f_stats.seen)+" comments you haven't seen on this file.\" class='collagelink' target='_blank' href='/collage?q=auth_admin&amp;id_source="+f.ID+"&amp;unread=1'><span class='collagelink-caption'> unread </span><div class='collagelink-number'>"+(f_stats.total-f_stats.seen)+"</div></a> <a  title='There are "+f_stats.total+" comments on this file.' class='collagelink' target='_blank' href='/collage?q=auth_admin&amp;id_source="+f.ID+"'><span class='collagelink-caption'> all </span><div class='collagelink-number'> "+f_stats.total+"</div></a> </td>":"<td/>";
		//link to annotated PDF:  <a target='_blank' href='"+this.options.img_server+"/pdf/annotated/"+f.ID+"?ckey="+ckey+"'>annotated</a>
		return $("<tr class='filesview_row' id_item='"+f.ID+"'><td class='filesview_ftitle'><div class='nbicon pdficon'/><a class='aftericon' target='_blank' href='/f/"+f.ID+"'>"+$.E(f.title)+"</a></td><td>"+assignment_info+"</td>"+download+stats+opts+"</tr>");

	    }, 
	    _folderlens: function(f){
		return $("<tr class='filesview_row' id_item='"+f.ID+"'><td class='filesview_ftitle'><div class='nbicon foldericon'/><a class='aftericon'  href='javascript:$.concierge.trigger({type:\"folder\", value:"+f.ID+"})'>"+$.E(f.name)+"</a></td></tr>");
	    }, 
	    _draw_pending: function(){
		var self = this;
		var m = self._model;
		var $list = $("#filesView-pending-list", self.element).empty();
		var f_question_sort = function(o1,o2){
		    return o2.id-o1.id;
		}
		var id_ensemble = self._id_ensemble;
		var  query_params = {};
		var viewall_url = "/collage?q=pending";
		if (id_ensemble != null){
		    query_params["ensemble_id"] = id_ensemble;
		    viewall_url+="&amp;id_ensemble="+id_ensemble; 
		}
		$("#filesView-allpending-link").attr("href", viewall_url);
		
		var questions	= m.get("question", {user_id: self._me.id}).intersect(m.get("location", query_params).items, "location_id").sort(f_question_sort);
		if (questions.length){
		    $("#filesView-pending-header-total").text(questions.length);
		    $("#filesView-pending-header-plural").text($.pluralize(questions.length));
		}
		else{
		    //  $("#filesView-panel-pending").hide();
		}
		var i,l,cs, c,q,s, body, reply_link,  ensemble_info, when, lens, lens_comment, comments, buttons, rating;
		for (i in questions){
		    q = questions[i];
		    l = m.o.location[q.location_id];
		    cs = m.get("comment", {location_id: l.id}).items;
		    comments = "";
		    s = m.o.file[l.source_id];
		    ensemble_info = id_ensemble == null ? ("<span class='filesView-item-ensembleinfo'>"+$.E(m.o.ensemble[l.ensemble_id].name)+"</span>") : "";
		    for (var cid in cs){
			c = cs[cid];
			if (!((q.comment_id == null && c.parent_id == null) || q.comment_id == c.id)){
			    //only display real answers, not the original comment
			    body = $.E(c.body).replace(/\n/g, " ");
			    reply_link = "/r/"+c.id;   
			    when = "<span class='filesView-when'>"+$.concierge.get_component("pretty_print_timedelta")({t: c.ctime})+"</span>";
			    rating = m.get("replyrating", {comment_id: c.id});
			    buttons =  rating.length() ? "<span class='reply-rated-as'>Reply rated as <button disabled='disabled'>"+self._RATING_LABELS[rating.first().status]+"</button></span>" : "<button onclick='$.concierge.trigger({type:\"rate_reply\", value:{status: 3, comment_id:"+ c.id +", threadmark_id: " + q.id + "}})'>"+self._RATING_LABELS[3]+"</button> <button onclick='$.concierge.trigger({type:\"rate_reply\", value:{status: 2, comment_id:"+ c.id +", threadmark_id: " + q.id + "}})'  >"+self._RATING_LABELS[2]+"</button> <button onclick='$.concierge.trigger({type:\"rate_reply\", value:{status: 1, comment_id:"+ c.id +", threadmark_id: " + q.id + "}})'  >"+self._RATING_LABELS[1]+"</button>";
			    lens_comment = "<li comment_id='"+c.id+"'><div class='filesView-floatright'>"+buttons+"<a style='margin-left: 20px' href='"+reply_link+"'><button>Reply</button></a> </div><span class='filesView-reply-body'>"+body+"</span>"+when+"</li>";
			    comments+="<ul>"+lens_comment+"</ul>";
			}
		    }
		    var c_orig = m.get("basecomment", {location_id: q.location_id}).first();
		    lens = self.img_snippet(i,l,c_orig);
		    lens.prepend(comments);
		    $list.append(lens);
		}
		return questions.length;
	    }, 
	    _draw_questions: function(){
		var self = this;
		var m = self._model;
		var $list = $("#filesView-question-list", self.element).empty();
		var f_location_sort = function(o1,o2){
		    return m.get("question",{location_id: o2.id}).length() - m.get("question",{location_id: o1.id}).length();
		}
		var id_ensemble = self._id_ensemble;
		var  query_params = {};
		var viewall_url = "/collage?q=questions";
		if (id_ensemble != null){
		    query_params["ensemble_id"] = id_ensemble;
		    viewall_url+="&amp;id_ensemble="+id_ensemble; 
		}
		$("#filesView-allquestions-link").attr("href", viewall_url);
		var locs = m.get("location", query_params).intersect(m.get("question").exclude({user_id: self._me.id}).values("location_id")).sort(f_location_sort);
		if (locs.length){
		    $("#filesView-question-header-total").text(locs.length);
		    $("#filesView-question-header-plural").text($.pluralize(locs.length));
		}
		else{
		    $("#filesView-panel-question").hide();
		}
		var i,l,c,q;
		for (i in locs){
		    l = locs[i];
		    c = m.get("comment", {location_id: l.id, parent_id: null}).first();
		    q = m.get("question", {location_id: l.id});
		    $list.append(self.img_snippet(i,l,c,q));	    
		}
		return locs.length;
	    },
	    img_snippet: function(i, l, c, q){	    	
		var self = this;
		var id_ensemble = self._id_ensemble;
		var m = self._model;
		var s =  m.o.file[l.source_id];
		var scalefactor, doc, inner,  inner_top, sel, link, numvotes;
		var body, comment_link, reply_link, ensemble_info, parity, lens;
		body = $.E(c.body).replace(/\n/g, " ");
		comment_link = "/c/"+c.id;
		reply_link = q==undefined ? "" : "<a target='_blank' href='/r/"+c.id+"'><button>Reply</button></a>";
		ensemble_info = id_ensemble == null ? ("<span class='filesView-item-ensembleinfo'>"+$.E(m.o.ensemble[l.ensemble_id].name)+"</span>") : "";
		parity = (!(i % 2)) ? " class='filesView-item-odd' ":" class='filesView-item-even' ";

		scalefactor = 0.6334;
		//scalefactor = 0.4798
		inner_top = Math.min(0, 50-l.y*scalefactor);	    
		sel = "<div class='snippet-selection' id_item='"+l.id+"' style='top: "+l.y*scalefactor+"px; left: "+l.x*scalefactor+"px; width: "+l.w*scalefactor+"px; height: "+l.h*scalefactor+"px'/>";
		    
		inner = "<div class='snippet-innermaterial' style='top: "+inner_top+"px'><div class='snippet-selections'>"+sel+"</div><img class='snippet-material' page='"+(Number(i)+1)+"' src2='"+self.options.img_server+"/pdf/cache2/288/33/"+l.source_id+"?ckey="+self._me.ckey+"&amp;page="+l.page+"'/></div>";
		link =" <a target='_blank' href='"+comment_link+"'>"+ $.E(m.o.ensemble[l.ensemble_id].name+" - "+s.title +" (p.  "+l.page+")") +"</a>";
		numvotes = q==undefined ? "": "<div class='nbicon questionicon-hicontrast'/><span class='filesView-question-numvotes'>"+q.length()+"</span>";
		doc = "<div class='snippet-material' page='"+(i+1)+"'><div class='snippet-pagenumber pagenumbertop'>"+link+numvotes+reply_link+"  </div>"+inner+"</div>";
		lens = $("<div "+parity+">"+doc+"<div class='filesView-question-body'><ul><li>"+body+"</li></ul></div> </div>");
		$("div.snippet-innermaterial", lens).draggable();
		return lens;
	    },
	    _draw_frame: function(){
		var self = this;
		var header	= self._admin ? "<div class='filesView-header'><div class='nbicon blueadminicon'/><span id='adminconsole-label'>Admin Console</span><button action='add_file'>Add file</button> <button action='add_folder'>New folder</button> <button action='invite_users'>Invite Users</button> <a id='see_users' target='_blank'>Users</a> <a id='group_props' target='_blank'>Properties</a>  <a id='spreadsheet' target='_blank'>Spreadsheet</a></div>" : "";
		var opts	= self._admin ? "<th>Actions</th>" : "";

		var filesView_pending =  "<h3  id='filesView-pending-header'><a href='#'>You have <span id='filesView-pending-header-total'>0</span> feedback request<span id='filesView-pending-header-plural'/>.</a></h3><div id='filesView-panel-pending' class='filesView-panel'><div id='filesView-pending-list'/></div>";
		var filesView_question = "<h3 id='filesView-question-header'><a href='#'>Your classmates have <span id='filesView-question-header-total'>0</span> pending question<span id='filesView-question-header-plural'/>. Can you help them ? <!--<a id='filesView-allquestions-link'>View all</a>--></a></h3><div id='filesView-panel-question'  class='filesView-panel'><div id='filesView-question-list'/></div>";

		var filesView_files = (self._id_ensemble == null) ?  "<!--<div  id='filesView-panel-recentfiles' class='filesView-panel'>Recent Files...</div>-->" : "<h3 id='filesView-files-header'><a href='#'>Contents of <span id='filesView-files-header-name'/></a></h3><div id='filesView-panel-files' class='filesView-panel'> <table class='tablesorter'><thead><tr><th>Name</th><th>Assignment</th><th id='th_download'>Download PDF</th><th>Stats</th>"+opts+"</tr></thead><tbody id='filesView-file-list'/></table></div>";
		self.element.html(header+ "<div id='filesView-accordion'>"+  filesView_files + filesView_pending + filesView_question +"</div>");


		var contextmenu_items = self._admin ? "<ul id='contextmenu_filesview' class='contextMenu'><li class='rename'><a href='#rename'>Rename</a></li><li class='move'><a href='#move'>Move</a></li><li class='update'><a href='#update'>Update</a></li><li class='assignment'><a href='#assignment'>Edit Assignment</a></li><li class='delete separator'><a href='#delete'>Delete</a></li></ul>" : "";
		self._menu_items.remove();
		self._menu_items = self._admin ? self._menu_items_admin : self._menu_items_reg;
		$("body").append(self._menu_items);
	    },
	    _draw_files : function(){
		var self=this;
		var id_ensemble = self._id_ensemble;		
		var id_folder = self._id_folder;
		var model = self._model; 
		self._admin = id_ensemble == null ? false : model.o.ensemble[id_ensemble].admin;
		
		if (id_ensemble == null){
		    // TODO: put drawing code here.
		}
		else{
		    var $tbody = $("#filesView-file-list", self.element);
		    //remove download header for users is not in admin mode and download isn't allowed. 
		    if (self._admin==false && model.o.ensemble[id_ensemble].allow_download==false){
			$("#th_download").remove();
		    }
		    //first files: 
		    //		    var elts = (id_folder==null) ? model.get("file", {id_ensemble: id_ensemble, id_folder: null}) :  model.get("file", {id_folder: id_folder});
		    var elts = model.get("file", {id_ensemble: id_ensemble, id_folder: id_folder});
		    var name = (id_folder==null) ?  model.o.ensemble[id_ensemble].name : model.o.folder[id_folder].name;
		    $("#filesView-files-header-name").text($.E(name));
		    var items = elts.items;
		    for (var i in items){
			$tbody.append(self._filelens(items[i]));
		    }
		    //now folders: 
		    elts =  model.get("folder", {id_ensemble: id_ensemble, id_parent: id_folder});
		    items = elts.items;
		    for (var i in items){
			$tbody.append(self._folderlens(items[i]));
		    }
		    if ($tbody.children().length==0){
			$tbody.append("<tr><td><div class='nofiles'>No files or folders</div></td></tr>");
		    }
		    $("table.tablesorter", self.element).trigger("update"); 
		    //.trigger("sorton", this.options.sort_list);
		    var f_context = function(action, el, pos){		    
			switch (action){
			case "open": 
			$.concierge.get_component("file_open")({id: el.attr("id_item")});
			//console.debug("open", el);
			break;
			default: 
			$.concierge.get_component(action+"_file_menu")({id: el.attr("id_item")});
			break;
			}
		    };
		    var f_leftcontext = function(action, el, pos){
			f_context(action, el.parent().parent(), pos);
		    }
		    $("tr.filesview_row", self.element).contextMenu({menu: "contextmenu_filesview"}, f_context);
		    $("a.optionmenu", self.element).contextMenu({menu:"contextmenu_filesview", leftButton:true }, f_leftcontext);
		    /*
		      $e_info = $("div.filesView-ensemble").empty();
		      if (id_folder==null && self._admin){ 
		      var e = model.o.ensemble[id_ensemble];
		      $e_info.append("Allow staffonly ? ") //SACHA CONTINUE HERE
		      }
		    */
		
		    $("#group_props").attr("href", "/properties/ensemble/"+self._id_ensemble);
		    $("#see_users").attr("href", "/properties/ensemble_users/"+self._id_ensemble);
		    $("#spreadsheet").attr("href", "/spreadsheet?id_ensemble="+self._id_ensemble);
		}
	    }, 
	    _render: function(){		
		var self=this;
		self._draw_frame();
		var open_candidate =  "#filesView-files-header";
		open_candidate = "#filesView-files-header";
		if (self._draw_questions()){
		    open_candidate = "#filesView-question-header"; 
		}		
		if (self._draw_pending()){
		    open_candidate = "#filesView-pending-header";
		}
		if (self._defaultopen == null){
		    self._defaultopen = open_candidate;
		}
		self._draw_files();
		$("#filesView-accordion").accordion({
			autoHeight: false, 
			    collapsible: true,
			    change: function(event, ui){
			    //simulate scroll event to display img if not there already. 
			    self.element.scroll();
			    self._defaultopen = "#" + ui.newHeader.attr("id");
			}, 
			    active: self._defaultopen
			    });

		// there might be quite a few questions: don't get all images at once
		var scroll_timeout = 300;
		var scroll_handler = function(evt){
		    var $this = $(this);
		    var timerID = self._scrollTimerID;
		    if (timerID != null){
			window.clearTimeout(timerID);
			self._scrollTimerID =  null;
		    }
		    timerID = window.setTimeout(function(){
			    var panel_top = $this.offset().top;
			    var H = $this.height();
			    $("img[src2]:visible", $this).each(function(i){
				    var $elt = $(this);
				    var $div = $elt.closest("div.snippet-material");
				    var delta_top = $div.offset().top - panel_top;
				    if ((delta_top+$div.height() > 0) && (delta_top < H)){
					$elt.attr("src", $elt.attr("src2"));
					this.removeAttribute("src2");
				    }
				});
			}, scroll_timeout);
		    self._scrollTimerID =  timerID;   
		};
		self.element.scroll(scroll_handler).scroll();	
		/*
		$("#filesView-panel-question").scroll(scroll_handler).scroll();	       

		window.setTimeout(function(){ //so that both can be initialized. 
			$("#filesView-panel-pending").scroll(scroll_handler).scroll();	     
		    }, scroll_timeout+200);
		*/

	    }, 
	    set_model: function(model){
		var self=this;
		self._model = model;
		model.register($.ui.view.prototype.get_adapter.call(this),  {file: null, folder: null, file_stats: null, replyrating: null, question: null}); //TODO: put stg here so that we update
		$.mods.declare({tablesorter: {js: ["/content/modules/tablesorter/jquery.tablesorter.min.js"], css: ["/content/modules/tablesorter/style.css"]}});
		$.mods.ready("tablesorter", function(){$("table.tablesorter", self.element).tablesorter({headers: {2:{sorter: false}, 3:{sorter:false}, 4:{sorter:false}}, textExtraction: function(node) { 
				    var $n = $(node);
				    if ($n.hasClass("filesview_ftitle")){
					return node.childNodes[1].innerHTML; 
				    }
				    else{
					return node.innerHTML;
				    }
				}  });});

	    },
	    update: function(action, payload, items_fieldname){
		if (action == "add" || action == "remove"){
		    this._render();
		    /*
		    if ("replyrating" in payload){
			this._draw_pending();
		    }
		    else{
			this._render();
		    }
		    */
		}
		//		console.debug("model update !", action, payload, items_fieldname);
	    }, 
	    _RATING_LABELS: {1: "<div class='nbicon refuseicon'/>Dismiss", 
			     2: "<div class='nbicon checkicon'/>Accept", 
			     3: "<div class='nbicon thankscheckicon'/> Thanks, this <i>really</i> helped !"
	    }
	});
			 
    $.widget("ui.filesView",V_OBJ );
    $.ui.filesView.prototype.options = {
	img_server: "http://localhost", 
	sort_list: [[0,0]], 
	listens: {
	    folder:null, 
	    ensemble: null, 
	    home: null,
	}, 
	admin: false, 
    };
})(jQuery);
<commit_msg>allowing admin to download annotated PDF<commit_after>/* filesView Plugin
 * Depends:
 *	ui.core.js
 * 	ui.view.js
 *

 Author 
 <NAME> (<EMAIL>) 

 License
 Copyright (c) 2010 Massachusetts Institute of Technology.
 MIT License (cf. MIT-LICENSE.txt or http://www.opensource.org/licenses/mit-license.php)
*/

(function($) {
    var V_OBJ = $.extend({},$.ui.view.prototype,{
	    _create: function() {
		$.ui.view.prototype._create.call(this);
		var self = this;
		self._model		= null;
		self._id_ensemble	= null;
		self._id_folder		= null;
		self._admin		= self.options.admin;
		self._me		= $.concierge.get_component("get_userinfo")();
		self._menu_items	= $();
		self._menu_items_reg	= $("<ul id='contextmenu_filesview' class='contextMenu'/>");
		self._menu_items_admin	= $("<ul id='contextmenu_filesview' class='contextMenu'><li class='rename'><a href='#rename'>Rename</a></li><li class='move'><a href='#move'>Move</a></li><li class='update'><a href='#update'>Update</a></li><li class='assignment'><a href='#assignment'>Edit Assignment</a></li><li class='delete separator'><a href='#delete'>Delete</a></li></ul>");
		self._scrollTimerID =  null;
		//self._firstrender = true;
		self._defaultopen = null;

		
		self.element.addClass("filesView");
		$(document).on("click", "button[action=add_file]", function(){
			$.concierge.get_component("add_file_menu")({id_ensemble: self._id_ensemble, id_folder:  self._id_folder});
		    });
		$(document).on("click","button[action=add_folder]", function(){
			$.concierge.get_component("add_folder_menu")({id_ensemble: self._id_ensemble, id_folder:  self._id_folder});
		    });
		$(document).on("click","button[action=invite_users]", function(){
			$.concierge.get_component("invite_users_menu")({id_ensemble: self._id_ensemble});
		    });
	
		$.mods.declare({
			filesView1: {js: [], css: ["/content/modules/dev/ui.filesview.css"]}, 
			    contextmenu: {js:["/content/modules/contextmenu/jquery.contextMenu.js"] , css: ["/content/modules/contextmenu/jquery.contextMenu.css"]}});
		$.mods.ready("filesView1", function(){});
		$.mods.ready("contextmenu", function(){});
		
		
	    },
	    _defaultHandler: function(evt){
		switch (evt.type){
		case "folder": 
		this._id_ensemble	= this._model.o.folder[evt.value].id_ensemble;
		this._id_folder		= evt.value;
		break;
		case "ensemble": 
		this._id_ensemble	= evt.value==0 ? null : evt.value;
		this._id_folder		= null;
		break;
		case "home": 
		this._id_ensemble	= null;
		this._id_folder		= null;
		break;
		/*
		case "rate_reply": 
		$("#filesView-pending-list li[comment_id="+evt.value.comment_id+"] button").attr("disabled", "disabled");
		break;
		*/
		}		
		this._render();
	    },
	    _filelens: function(f){
		var self=this;
		var ckey = $.concierge.get_component("get_userinfo")().ckey;
		var opts = this._admin ? "<td><a href='javascript:void(0)' class='optionmenu'>Actions</a></td>" : "" ;
		var assignment_info = f.assignment ? ("Yes - due "+f.due.substring(4,0)+"-"+f.due.substring(7,5)+"-"+f.due.substring(10,8)+" at "+f.due.substring(13,11)+":"+f.due.substring(16,14)) :"<span>No</span>";
		var download = "";
		if (self._admin || self._model.o.ensemble[f.id_ensemble].allow_download ){
		    download = "<a target='_blank' href='"+this.options.img_server+"/pdf/repository/"+f.ID+"?ckey="+ckey+"'>original</a>";
		
		    //for now only admin can download annotated PDF:
		    if (self._admin){
			download += " <a target='_blank' href='"+this.options.img_server+"/pdf/annotated/"+f.ID+"?ckey="+ckey+"'>annotated</a>";
		    }
		    download = "<td>"+download+"</td>";
		}
		var f_stats =  self._model.o.file_stats[f.ID];
		var stats = f_stats ? "<td><a title='You wrote  "+f_stats.mine+" comments on this file.' class='collagelink' target='_blank' href='/collage?q=auth&amp;id_source="+f.ID+"'><span class='collagelink-caption'> me </span><div class='collagelink-number'> "+f_stats.mine+"</div></a> <a title=\"There are "+(f_stats.total-f_stats.seen)+" comments you haven't seen on this file.\" class='collagelink' target='_blank' href='/collage?q=auth_admin&amp;id_source="+f.ID+"&amp;unread=1'><span class='collagelink-caption'> unread </span><div class='collagelink-number'>"+(f_stats.total-f_stats.seen)+"</div></a> <a  title='There are "+f_stats.total+" comments on this file.' class='collagelink' target='_blank' href='/collage?q=auth_admin&amp;id_source="+f.ID+"'><span class='collagelink-caption'> all </span><div class='collagelink-number'> "+f_stats.total+"</div></a> </td>":"<td/>";
		return $("<tr class='filesview_row' id_item='"+f.ID+"'><td class='filesview_ftitle'><div class='nbicon pdficon'/><a class='aftericon' target='_blank' href='/f/"+f.ID+"'>"+$.E(f.title)+"</a></td><td>"+assignment_info+"</td>"+download+stats+opts+"</tr>");

	    }, 
	    _folderlens: function(f){
		return $("<tr class='filesview_row' id_item='"+f.ID+"'><td class='filesview_ftitle'><div class='nbicon foldericon'/><a class='aftericon'  href='javascript:$.concierge.trigger({type:\"folder\", value:"+f.ID+"})'>"+$.E(f.name)+"</a></td></tr>");
	    }, 
	    _draw_pending: function(){
		var self = this;
		var m = self._model;
		var $list = $("#filesView-pending-list", self.element).empty();
		var f_question_sort = function(o1,o2){
		    return o2.id-o1.id;
		}
		var id_ensemble = self._id_ensemble;
		var  query_params = {};
		var viewall_url = "/collage?q=pending";
		if (id_ensemble != null){
		    query_params["ensemble_id"] = id_ensemble;
		    viewall_url+="&amp;id_ensemble="+id_ensemble; 
		}
		$("#filesView-allpending-link").attr("href", viewall_url);
		
		var questions	= m.get("question", {user_id: self._me.id}).intersect(m.get("location", query_params).items, "location_id").sort(f_question_sort);
		if (questions.length){
		    $("#filesView-pending-header-total").text(questions.length);
		    $("#filesView-pending-header-plural").text($.pluralize(questions.length));
		}
		else{
		    //  $("#filesView-panel-pending").hide();
		}
		var i,l,cs, c,q,s, body, reply_link,  ensemble_info, when, lens, lens_comment, comments, buttons, rating;
		for (i in questions){
		    q = questions[i];
		    l = m.o.location[q.location_id];
		    cs = m.get("comment", {location_id: l.id}).items;
		    comments = "";
		    s = m.o.file[l.source_id];
		    ensemble_info = id_ensemble == null ? ("<span class='filesView-item-ensembleinfo'>"+$.E(m.o.ensemble[l.ensemble_id].name)+"</span>") : "";
		    for (var cid in cs){
			c = cs[cid];
			if (!((q.comment_id == null && c.parent_id == null) || q.comment_id == c.id)){
			    //only display real answers, not the original comment
			    body = $.E(c.body).replace(/\n/g, " ");
			    reply_link = "/r/"+c.id;   
			    when = "<span class='filesView-when'>"+$.concierge.get_component("pretty_print_timedelta")({t: c.ctime})+"</span>";
			    rating = m.get("replyrating", {comment_id: c.id});
			    buttons =  rating.length() ? "<span class='reply-rated-as'>Reply rated as <button disabled='disabled'>"+self._RATING_LABELS[rating.first().status]+"</button></span>" : "<button onclick='$.concierge.trigger({type:\"rate_reply\", value:{status: 3, comment_id:"+ c.id +", threadmark_id: " + q.id + "}})'>"+self._RATING_LABELS[3]+"</button> <button onclick='$.concierge.trigger({type:\"rate_reply\", value:{status: 2, comment_id:"+ c.id +", threadmark_id: " + q.id + "}})'  >"+self._RATING_LABELS[2]+"</button> <button onclick='$.concierge.trigger({type:\"rate_reply\", value:{status: 1, comment_id:"+ c.id +", threadmark_id: " + q.id + "}})'  >"+self._RATING_LABELS[1]+"</button>";
			    lens_comment = "<li comment_id='"+c.id+"'><div class='filesView-floatright'>"+buttons+"<a style='margin-left: 20px' href='"+reply_link+"'><button>Reply</button></a> </div><span class='filesView-reply-body'>"+body+"</span>"+when+"</li>";
			    comments+="<ul>"+lens_comment+"</ul>";
			}
		    }
		    var c_orig = m.get("basecomment", {location_id: q.location_id}).first();
		    lens = self.img_snippet(i,l,c_orig);
		    lens.prepend(comments);
		    $list.append(lens);
		}
		return questions.length;
	    }, 
	    _draw_questions: function(){
		var self = this;
		var m = self._model;
		var $list = $("#filesView-question-list", self.element).empty();
		var f_location_sort = function(o1,o2){
		    return m.get("question",{location_id: o2.id}).length() - m.get("question",{location_id: o1.id}).length();
		}
		var id_ensemble = self._id_ensemble;
		var  query_params = {};
		var viewall_url = "/collage?q=questions";
		if (id_ensemble != null){
		    query_params["ensemble_id"] = id_ensemble;
		    viewall_url+="&amp;id_ensemble="+id_ensemble; 
		}
		$("#filesView-allquestions-link").attr("href", viewall_url);
		var locs = m.get("location", query_params).intersect(m.get("question").exclude({user_id: self._me.id}).values("location_id")).sort(f_location_sort);
		if (locs.length){
		    $("#filesView-question-header-total").text(locs.length);
		    $("#filesView-question-header-plural").text($.pluralize(locs.length));
		}
		else{
		    $("#filesView-panel-question").hide();
		}
		var i,l,c,q;
		for (i in locs){
		    l = locs[i];
		    c = m.get("comment", {location_id: l.id, parent_id: null}).first();
		    q = m.get("question", {location_id: l.id});
		    $list.append(self.img_snippet(i,l,c,q));	    
		}
		return locs.length;
	    },
	    img_snippet: function(i, l, c, q){	    	
		var self = this;
		var id_ensemble = self._id_ensemble;
		var m = self._model;
		var s =  m.o.file[l.source_id];
		var scalefactor, doc, inner,  inner_top, sel, link, numvotes;
		var body, comment_link, reply_link, ensemble_info, parity, lens;
		body = $.E(c.body).replace(/\n/g, " ");
		comment_link = "/c/"+c.id;
		reply_link = q==undefined ? "" : "<a target='_blank' href='/r/"+c.id+"'><button>Reply</button></a>";
		ensemble_info = id_ensemble == null ? ("<span class='filesView-item-ensembleinfo'>"+$.E(m.o.ensemble[l.ensemble_id].name)+"</span>") : "";
		parity = (!(i % 2)) ? " class='filesView-item-odd' ":" class='filesView-item-even' ";

		scalefactor = 0.6334;
		//scalefactor = 0.4798
		inner_top = Math.min(0, 50-l.y*scalefactor);	    
		sel = "<div class='snippet-selection' id_item='"+l.id+"' style='top: "+l.y*scalefactor+"px; left: "+l.x*scalefactor+"px; width: "+l.w*scalefactor+"px; height: "+l.h*scalefactor+"px'/>";
		    
		inner = "<div class='snippet-innermaterial' style='top: "+inner_top+"px'><div class='snippet-selections'>"+sel+"</div><img class='snippet-material' page='"+(Number(i)+1)+"' src2='"+self.options.img_server+"/pdf/cache2/288/33/"+l.source_id+"?ckey="+self._me.ckey+"&amp;page="+l.page+"'/></div>";
		link =" <a target='_blank' href='"+comment_link+"'>"+ $.E(m.o.ensemble[l.ensemble_id].name+" - "+s.title +" (p.  "+l.page+")") +"</a>";
		numvotes = q==undefined ? "": "<div class='nbicon questionicon-hicontrast'/><span class='filesView-question-numvotes'>"+q.length()+"</span>";
		doc = "<div class='snippet-material' page='"+(i+1)+"'><div class='snippet-pagenumber pagenumbertop'>"+link+numvotes+reply_link+"  </div>"+inner+"</div>";
		lens = $("<div "+parity+">"+doc+"<div class='filesView-question-body'><ul><li>"+body+"</li></ul></div> </div>");
		$("div.snippet-innermaterial", lens).draggable();
		return lens;
	    },
	    _draw_frame: function(){
		var self = this;
		var header	= self._admin ? "<div class='filesView-header'><div class='nbicon blueadminicon'/><span id='adminconsole-label'>Admin Console</span><button action='add_file'>Add file</button> <button action='add_folder'>New folder</button> <button action='invite_users'>Invite Users</button> <a id='see_users' target='_blank'>Users</a> <a id='group_props' target='_blank'>Properties</a>  <a id='spreadsheet' target='_blank'>Spreadsheet</a></div>" : "";
		var opts	= self._admin ? "<th>Actions</th>" : "";

		var filesView_pending =  "<h3  id='filesView-pending-header'><a href='#'>You have <span id='filesView-pending-header-total'>0</span> feedback request<span id='filesView-pending-header-plural'/>.</a></h3><div id='filesView-panel-pending' class='filesView-panel'><div id='filesView-pending-list'/></div>";
		var filesView_question = "<h3 id='filesView-question-header'><a href='#'>Your classmates have <span id='filesView-question-header-total'>0</span> pending question<span id='filesView-question-header-plural'/>. Can you help them ? <!--<a id='filesView-allquestions-link'>View all</a>--></a></h3><div id='filesView-panel-question'  class='filesView-panel'><div id='filesView-question-list'/></div>";

		var filesView_files = (self._id_ensemble == null) ?  "<!--<div  id='filesView-panel-recentfiles' class='filesView-panel'>Recent Files...</div>-->" : "<h3 id='filesView-files-header'><a href='#'>Contents of <span id='filesView-files-header-name'/></a></h3><div id='filesView-panel-files' class='filesView-panel'> <table class='tablesorter'><thead><tr><th>Name</th><th>Assignment</th><th id='th_download'>Download PDF</th><th>Stats</th>"+opts+"</tr></thead><tbody id='filesView-file-list'/></table></div>";
		self.element.html(header+ "<div id='filesView-accordion'>"+  filesView_files + filesView_pending + filesView_question +"</div>");


		var contextmenu_items = self._admin ? "<ul id='contextmenu_filesview' class='contextMenu'><li class='rename'><a href='#rename'>Rename</a></li><li class='move'><a href='#move'>Move</a></li><li class='update'><a href='#update'>Update</a></li><li class='assignment'><a href='#assignment'>Edit Assignment</a></li><li class='delete separator'><a href='#delete'>Delete</a></li></ul>" : "";
		self._menu_items.remove();
		self._menu_items = self._admin ? self._menu_items_admin : self._menu_items_reg;
		$("body").append(self._menu_items);
	    },
	    _draw_files : function(){
		var self=this;
		var id_ensemble = self._id_ensemble;		
		var id_folder = self._id_folder;
		var model = self._model; 
		self._admin = id_ensemble == null ? false : model.o.ensemble[id_ensemble].admin;
		
		if (id_ensemble == null){
		    // TODO: put drawing code here.
		}
		else{
		    var $tbody = $("#filesView-file-list", self.element);
		    //remove download header for users is not in admin mode and download isn't allowed. 
		    if (self._admin==false && model.o.ensemble[id_ensemble].allow_download==false){
			$("#th_download").remove();
		    }
		    //first files: 
		    //		    var elts = (id_folder==null) ? model.get("file", {id_ensemble: id_ensemble, id_folder: null}) :  model.get("file", {id_folder: id_folder});
		    var elts = model.get("file", {id_ensemble: id_ensemble, id_folder: id_folder});
		    var name = (id_folder==null) ?  model.o.ensemble[id_ensemble].name : model.o.folder[id_folder].name;
		    $("#filesView-files-header-name").text($.E(name));
		    var items = elts.items;
		    for (var i in items){
			$tbody.append(self._filelens(items[i]));
		    }
		    //now folders: 
		    elts =  model.get("folder", {id_ensemble: id_ensemble, id_parent: id_folder});
		    items = elts.items;
		    for (var i in items){
			$tbody.append(self._folderlens(items[i]));
		    }
		    if ($tbody.children().length==0){
			$tbody.append("<tr><td><div class='nofiles'>No files or folders</div></td></tr>");
		    }
		    $("table.tablesorter", self.element).trigger("update"); 
		    //.trigger("sorton", this.options.sort_list);
		    var f_context = function(action, el, pos){		    
			switch (action){
			case "open": 
			$.concierge.get_component("file_open")({id: el.attr("id_item")});
			//console.debug("open", el);
			break;
			default: 
			$.concierge.get_component(action+"_file_menu")({id: el.attr("id_item")});
			break;
			}
		    };
		    var f_leftcontext = function(action, el, pos){
			f_context(action, el.parent().parent(), pos);
		    }
		    $("tr.filesview_row", self.element).contextMenu({menu: "contextmenu_filesview"}, f_context);
		    $("a.optionmenu", self.element).contextMenu({menu:"contextmenu_filesview", leftButton:true }, f_leftcontext);
		    /*
		      $e_info = $("div.filesView-ensemble").empty();
		      if (id_folder==null && self._admin){ 
		      var e = model.o.ensemble[id_ensemble];
		      $e_info.append("Allow staffonly ? ") //SACHA CONTINUE HERE
		      }
		    */
		
		    $("#group_props").attr("href", "/properties/ensemble/"+self._id_ensemble);
		    $("#see_users").attr("href", "/properties/ensemble_users/"+self._id_ensemble);
		    $("#spreadsheet").attr("href", "/spreadsheet?id_ensemble="+self._id_ensemble);
		}
	    }, 
	    _render: function(){		
		var self=this;
		self._draw_frame();
		var open_candidate =  "#filesView-files-header";
		open_candidate = "#filesView-files-header";
		if (self._draw_questions()){
		    open_candidate = "#filesView-question-header"; 
		}		
		if (self._draw_pending()){
		    open_candidate = "#filesView-pending-header";
		}
		if (self._defaultopen == null){
		    self._defaultopen = open_candidate;
		}
		self._draw_files();
		$("#filesView-accordion").accordion({
			autoHeight: false, 
			    collapsible: true,
			    change: function(event, ui){
			    //simulate scroll event to display img if not there already. 
			    self.element.scroll();
			    self._defaultopen = "#" + ui.newHeader.attr("id");
			}, 
			    active: self._defaultopen
			    });

		// there might be quite a few questions: don't get all images at once
		var scroll_timeout = 300;
		var scroll_handler = function(evt){
		    var $this = $(this);
		    var timerID = self._scrollTimerID;
		    if (timerID != null){
			window.clearTimeout(timerID);
			self._scrollTimerID =  null;
		    }
		    timerID = window.setTimeout(function(){
			    var panel_top = $this.offset().top;
			    var H = $this.height();
			    $("img[src2]:visible", $this).each(function(i){
				    var $elt = $(this);
				    var $div = $elt.closest("div.snippet-material");
				    var delta_top = $div.offset().top - panel_top;
				    if ((delta_top+$div.height() > 0) && (delta_top < H)){
					$elt.attr("src", $elt.attr("src2"));
					this.removeAttribute("src2");
				    }
				});
			}, scroll_timeout);
		    self._scrollTimerID =  timerID;   
		};
		self.element.scroll(scroll_handler).scroll();	
		/*
		$("#filesView-panel-question").scroll(scroll_handler).scroll();	       

		window.setTimeout(function(){ //so that both can be initialized. 
			$("#filesView-panel-pending").scroll(scroll_handler).scroll();	     
		    }, scroll_timeout+200);
		*/

	    }, 
	    set_model: function(model){
		var self=this;
		self._model = model;
		model.register($.ui.view.prototype.get_adapter.call(this),  {file: null, folder: null, file_stats: null, replyrating: null, question: null}); //TODO: put stg here so that we update
		$.mods.declare({tablesorter: {js: ["/content/modules/tablesorter/jquery.tablesorter.min.js"], css: ["/content/modules/tablesorter/style.css"]}});
		$.mods.ready("tablesorter", function(){$("table.tablesorter", self.element).tablesorter({headers: {2:{sorter: false}, 3:{sorter:false}, 4:{sorter:false}}, textExtraction: function(node) { 
				    var $n = $(node);
				    if ($n.hasClass("filesview_ftitle")){
					return node.childNodes[1].innerHTML; 
				    }
				    else{
					return node.innerHTML;
				    }
				}  });});

	    },
	    update: function(action, payload, items_fieldname){
		if (action == "add" || action == "remove"){
		    this._render();
		    /*
		    if ("replyrating" in payload){
			this._draw_pending();
		    }
		    else{
			this._render();
		    }
		    */
		}
		//		console.debug("model update !", action, payload, items_fieldname);
	    }, 
	    _RATING_LABELS: {1: "<div class='nbicon refuseicon'/>Dismiss", 
			     2: "<div class='nbicon checkicon'/>Accept", 
			     3: "<div class='nbicon thankscheckicon'/> Thanks, this <i>really</i> helped !"
	    }
	});
			 
    $.widget("ui.filesView",V_OBJ );
    $.ui.filesView.prototype.options = {
	img_server: "http://localhost", 
	sort_list: [[0,0]], 
	listens: {
	    folder:null, 
	    ensemble: null, 
	    home: null,
	}, 
	admin: false, 
    };
})(jQuery);

{'fraction_non_alphanumeric': 0.2088583716894288, 'fraction_numerical': 0.004577579919012048, 'mean_word_length': 4.173715029277814, 'pattern_counts': {'":': 18, '<': 467, '<?xml version=': 0, '>': 467, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 25, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7571700', 'n_tokens_mistral': 15477, 'n_tokens_neox': 14109, 'n_words': 2232}