<commit_before>/* --------------- JQUERY --------------- */
var shelfConfig = {
			active: false,
			collapsible: true,
			autoHeight: false,
			animated: "swing",
			heightStyle: "content"
	};
var shelfSectionConfig = {
			active: false,
			collapsible: true,
			autoHeight: false,
			animated: "swing"
	};

var currentShelfNumber = 0;
var currentShelfSectionNumber = 0;
var shelves = [];

var $parentAccordion;
var $accordionTemplate;

var $addSection;
var $addShelf;

$(document).ready(function () {

	$parentAccordion = $("#parentAccordion");
	$parentAccordion.accordion(shelfConfig);
	$accordionTemplate = $(".accordion").children();

	$addSection = $("#addSection");
	$addShelf = $("#addShelf");

	$addSection.hide();

	// Add Shelf Button
	$addShelf.on("click", function (e) {
		e.preventDefault();

		// Create a shelf and append it to the parent accordion
		addShelfToArray( shelves );
		var $shelfElement = generateAccordion( currentShelfNumber, "shelf" );
		$parentAccordion.append($shelfElement);
		$parentAccordion.accordion("refresh");

		// Apply name to shelf
		var header = "#ui-accordion-parentAccordion-header-" + currentShelfNumber;
		var shelfDisplayNumber = currentShelfNumber + 1;
		$(header).text("Shelf " + shelfDisplayNumber);

		// Create an accordion element to hold shelf attributes
		var $attributesElement = generateAccordion(currentShelfNumber + 1, "section");
		var panel = "#ui-accordion-parentAccordion-panel-" + currentShelfNumber;
		$(panel).append($attributesElement);
		$(panel).accordion("refresh");

		// Apply content to shelf attribute accordion element
		var $attributesContent = generateAccordionContent(currentShelfNumber, "shelf", shelves);
		var attrHeader = "#ui-accordion-ui-accordion-parentAccordion-panel-" + currentShelfNumber + "-header-0";
		$(attrHeader).text("Shelf attributes");
		var attrContent = "#ui-accordion-ui-accordion-parentAccordion-panel-" + currentShelfNumber + "-panel-0";
		$(attrContent).append($attributesContent);

		addEditable( shelves, "shelf" );
		drawShelves( shelves, scale );

		manageSectionButton();
		currentShelfNumber++;
	});

	// Add section button
	$addSection.on("click", function (e) {
			e.preventDefault();

			var activeShelfNumber = $parentAccordion.accordion("option", "active");
			shelves[activeShelfNumber].sections.push( new sections() );
			var newSectionNumber = shelves[activeShelfNumber].sections.length;

			// Create a section and append it to a shelf
			var $shelfSectionElement = generateAccordion(activeShelfNumber + 1, "section");
			var panel = "#ui-accordion-parentAccordion-panel-" + activeShelfNumber;
			$(panel).append($shelfSectionElement);
			$(panel).accordion("refresh");

			// Apply a name to the section
			var innerHeader = "#ui-accordion-ui-accordion-parentAccordion-panel-" + activeShelfNumber + "-header-" + newSectionNumber;
			$(innerHeader).text("Section " + newSectionNumber);

			// Apply content to the section
			var $contents = generateAccordionContent( activeShelfNumber, "section", shelves );
			var innerPanel = "#ui-accordion-ui-accordion-parentAccordion-panel-" + activeShelfNumber + "-panel-" + newSectionNumber;
			$(innerPanel).append($contents);

			addEditable( shelves, "section" );
			drawSections( activeShelfNumber, shelves, scale );
	});

});

function addEditable( shelves, type ) {
	if( type == "shelf" ){

		$(".notes").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			shelves[shelfIndex].notes = value;
			return value;
		});

		$(".uuid").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			shelves[shelfIndex].rpUUID = value;
			return value;
		});

	} else {

		$(".id").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].displayID = value;
			return value;
		});

		$(".color").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].displayColor = value;
			return value;
		});

		$(".motion").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].pirURL = value;
			return value;
		});

		$(".stock").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].pintURL = value;
			return value;
		});

	}
}

function shelf() {
	this.shelfName;
	this.notes;
	this.rpUUID;
	this.sections = [];
	return;
}

function sections() {
	this.sectionName = "Default Section name";
	this.displayId;
	this.displayColor;
	this.pirURL;
	this.pintURL;
	return;
}

function getAccordionTemplate() {
		 return $accordionTemplate.clone();
}

function generateAccordion( number, accordionType ) {
		var $accordion = getAccordionTemplate();
		var $accordionWithEvents = attachAccordionEvents( $accordion, accordionType );
		return $accordionWithEvents;
}

function generateAccordionContent( shelfIndex, accordionType, shelvesArray ) {
		var $accordionContent = $(document.createElement("ul"));
		if ( accordionType == "shelf" ) {
			$accordionContent.append($("
").append("Notes: <span class=\"input notes\"" + shelvesArray[shelfIndex].notes + ""));
			$accordionContent.append($("
").append("RasPi UUID: <span class=\"input uuid\"" + shelvesArray[shelfIndex].rpUUID + ""));
		}else {
			var sectionIndex = shelvesArray[shelfIndex].sections.length - 1;
			$accordionContent.append($("
").append("ID: <span class=\"input id\"" + shelvesArray[shelfIndex].sections[sectionIndex].displayId + ""));
			$accordionContent.append($("
").append("Color: <span class=\"input color\"" + shelvesArray[shelfIndex].sections[sectionIndex].displayColor + ""));
			$accordionContent.append($("
").append("Motion sensor: <span class=\"input motion\"" + shelvesArray[shelfIndex].sections[sectionIndex].pirURL + ""));
			$accordionContent.append($("
").append("Stock sensor: <span class=\"input stock\"" + shelvesArray[shelfIndex].sections[sectionIndex].pintURL + ""));
		}

		return $accordionContent;
}

function attachAccordionEvents( $accordionElement, accordionType ) {
		if (accordionType == "shelf") {
				$accordionElement.accordion(shelfConfig);
		} else {
				$accordionElement.accordion(shelfSectionConfig);
		}

		return $accordionElement;
}

// change
function manageSectionButton() {
		if ( $parentAccordion.children().length > 0 ) {
				$addSection.show();
		} else {
				$addSection.hide();
		}
}

function addShelfToArray( shelvesArray ) {
	shelvesArray.push( new shelf );
	return;
}

/* --------------- D3 --------------- */
var svg;
// look at viewbox example here: http://jsfiddle.net/NKRPe/60/
var w = 808;
var h = w*2/3;
var strokePadding = 1;
var domainSize = 1;

/* Scale needs its domain to size the current of shelves + blank aisles, so update
the scale domain anytime a shelf is added */
var scale = d3.scale.linear()
	.domain([0,1])
	.rangeRound([0,w]);

$(document).ready( function() {
	svg = d3.select('#d3').append("svg")
		.attr("width", w)
		.attr("height", h);
});

function drawShelves(shelves, scale){
	domainSize++;
	scale.domain([0,domainSize])
	// Move exisiting shelves and sections
	svg.transition().selectAll(".shelf")
			.duration(500)
			.attr("x", function(d,i) {
				return scale(i+1);
			});
	for(var i=0; i<shelves.length; i++){
		var selector = ".s" + i;
		svg.transition().selectAll(selector)
		.duration(500)
		.attr("x", function() {
			return scale(i+1) + 5;
		});
	}

	// Add the newest shelf
	svg.selectAll(".shelf").data(shelves).enter().append("rect")
		.attr("x", w+100) // initialize out of frame, then slide in
		.attr("y", strokePadding)
		.attr("rx", 5)
		.attr("ry", 5)
		.attr("width", 50)
		.attr("height", 500)
		.attr("fill", "#E1EFF5")
		.attr("stroke",  "#2E6E9E")
		.attr("stroke-width", strokePadding)
		.attr("class", "shelf")
		.transition()
		.duration(500)
		.attr("x", function(d,i) {
			return scale(i+1);
		});
}

function drawSections(shelfIndex, shelves, scale){

	var selector = ".s" + shelfIndex;

	var sectionScale = d3.scale.linear()
		.domain([0, shelves[shelfIndex].sections.length])
		.range([0,495]);

	svg.transition().selectAll(selector)
		.duration(500)
		.attr("y", function(d,i) {
			return sectionScale(i) + 5;
		})
		.attr("height", function(d,i) {
			return 495/shelves[shelfIndex].sections.length - 5;
		});

	// Add new sections
	svg.selectAll(selector).data(shelves[shelfIndex].sections).enter().append("rect")
		.attr("x", function() {
			return scale(shelfIndex+1) + 5;
		})
		.attr("y", function(d,i) {
			return sectionScale(i) + 5;
		})
		.attr("width", 40) // probably need to change the sizes
		.attr("height", function(d,i) {
			return 495/shelves[shelfIndex].sections.length - 5;
		})
		.attr("rx", 5)
		.attr("ry", 5)
		.attr("fill", "#2E6E9E")
		.attr("class", "section s" + shelfIndex)
		.attr("opacity", 0)
		// Open accordion associated with this element when clicked
		.on("click", function(d, i) {
			$parentAccordion.accordion('option', 'active', shelfIndex);
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active", i + 1);
		})
		.transition()
		.attr("opacity", 1)
		.duration(500);
}<commit_msg>Changed cursor to pointer when you hover over a selectable section<commit_after>/* --------------- JQUERY --------------- */
var shelfConfig = {
			active: false,
			collapsible: true,
			autoHeight: false,
			animated: "swing",
			heightStyle: "content"
	};
var shelfSectionConfig = {
			active: false,
			collapsible: true,
			autoHeight: false,
			animated: "swing"
	};

var currentShelfNumber = 0;
var currentShelfSectionNumber = 0;
var shelves = [];

var $parentAccordion;
var $accordionTemplate;

var $addSection;
var $addShelf;

$(document).ready(function () {

	$parentAccordion = $("#parentAccordion");
	$parentAccordion.accordion(shelfConfig);
	$accordionTemplate = $(".accordion").children();

	$addSection = $("#addSection");
	$addShelf = $("#addShelf");

	$addSection.hide();

	// Add Shelf Button
	$addShelf.on("click", function (e) {
		e.preventDefault();

		// Create a shelf and append it to the parent accordion
		addShelfToArray( shelves );
		var $shelfElement = generateAccordion( currentShelfNumber, "shelf" );
		$parentAccordion.append($shelfElement);
		$parentAccordion.accordion("refresh");

		// Apply name to shelf
		var header = "#ui-accordion-parentAccordion-header-" + currentShelfNumber;
		var shelfDisplayNumber = currentShelfNumber + 1;
		$(header).text("Shelf " + shelfDisplayNumber);

		// Create an accordion element to hold shelf attributes
		var $attributesElement = generateAccordion(currentShelfNumber + 1, "section");
		var panel = "#ui-accordion-parentAccordion-panel-" + currentShelfNumber;
		$(panel).append($attributesElement);
		$(panel).accordion("refresh");

		// Apply content to shelf attribute accordion element
		var $attributesContent = generateAccordionContent(currentShelfNumber, "shelf", shelves);
		var attrHeader = "#ui-accordion-ui-accordion-parentAccordion-panel-" + currentShelfNumber + "-header-0";
		$(attrHeader).text("Shelf attributes");
		var attrContent = "#ui-accordion-ui-accordion-parentAccordion-panel-" + currentShelfNumber + "-panel-0";
		$(attrContent).append($attributesContent);

		addEditable( shelves, "shelf" );
		drawShelves( shelves, scale );

		manageSectionButton();
		currentShelfNumber++;
	});

	// Add section button
	$addSection.on("click", function (e) {
			e.preventDefault();

			var activeShelfNumber = $parentAccordion.accordion("option", "active");
			shelves[activeShelfNumber].sections.push( new sections() );
			var newSectionNumber = shelves[activeShelfNumber].sections.length;

			// Create a section and append it to a shelf
			var $shelfSectionElement = generateAccordion(activeShelfNumber + 1, "section");
			var panel = "#ui-accordion-parentAccordion-panel-" + activeShelfNumber;
			$(panel).append($shelfSectionElement);
			$(panel).accordion("refresh");

			// Apply a name to the section
			var innerHeader = "#ui-accordion-ui-accordion-parentAccordion-panel-" + activeShelfNumber + "-header-" + newSectionNumber;
			$(innerHeader).text("Section " + newSectionNumber);

			// Apply content to the section
			var $contents = generateAccordionContent( activeShelfNumber, "section", shelves );
			var innerPanel = "#ui-accordion-ui-accordion-parentAccordion-panel-" + activeShelfNumber + "-panel-" + newSectionNumber;
			$(innerPanel).append($contents);

			addEditable( shelves, "section" );
			drawSections( activeShelfNumber, shelves, scale );
	});

});

function addEditable( shelves, type ) {
	if( type == "shelf" ){

		$(".notes").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			shelves[shelfIndex].notes = value;
			return value;
		});

		$(".uuid").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			shelves[shelfIndex].rpUUID = value;
			return value;
		});

	} else {

		$(".id").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].displayID = value;
			return value;
		});

		$(".color").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].displayColor = value;
			return value;
		});

		$(".motion").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].pirURL = value;
			return value;
		});

		$(".stock").editable( function(value, settings) {
			var shelfIndex = $parentAccordion.accordion("option", "active");
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active");
			shelves[shelfIndex].sections[sectionIndex - 1].pintURL = value;
			return value;
		});

	}
}

function shelf() {
	this.shelfName;
	this.notes;
	this.rpUUID;
	this.sections = [];
	return;
}

function sections() {
	this.sectionName = "Default Section name";
	this.displayId;
	this.displayColor;
	this.pirURL;
	this.pintURL;
	return;
}

function getAccordionTemplate() {
		 return $accordionTemplate.clone();
}

function generateAccordion( number, accordionType ) {
		var $accordion = getAccordionTemplate();
		var $accordionWithEvents = attachAccordionEvents( $accordion, accordionType );
		return $accordionWithEvents;
}

function generateAccordionContent( shelfIndex, accordionType, shelvesArray ) {
		var $accordionContent = $(document.createElement("ul"));
		if ( accordionType == "shelf" ) {
			$accordionContent.append($("
").append("Notes: <span class=\"input notes\"" + shelvesArray[shelfIndex].notes + ""));
			$accordionContent.append($("
").append("RasPi UUID: <span class=\"input uuid\"" + shelvesArray[shelfIndex].rpUUID + ""));
		}else {
			var sectionIndex = shelvesArray[shelfIndex].sections.length - 1;
			$accordionContent.append($("
").append("ID: <span class=\"input id\"" + shelvesArray[shelfIndex].sections[sectionIndex].displayId + ""));
			$accordionContent.append($("
").append("Color: <span class=\"input color\"" + shelvesArray[shelfIndex].sections[sectionIndex].displayColor + ""));
			$accordionContent.append($("
").append("Motion sensor: <span class=\"input motion\"" + shelvesArray[shelfIndex].sections[sectionIndex].pirURL + ""));
			$accordionContent.append($("
").append("Stock sensor: <span class=\"input stock\"" + shelvesArray[shelfIndex].sections[sectionIndex].pintURL + ""));
		}

		return $accordionContent;
}

function attachAccordionEvents( $accordionElement, accordionType ) {
		if (accordionType == "shelf") {
				$accordionElement.accordion(shelfConfig);
		} else {
				$accordionElement.accordion(shelfSectionConfig);
		}

		return $accordionElement;
}

// change
function manageSectionButton() {
		if ( $parentAccordion.children().length > 0 ) {
				$addSection.show();
		} else {
				$addSection.hide();
		}
}

function addShelfToArray( shelvesArray ) {
	shelvesArray.push( new shelf );
	return;
}

/* --------------- D3 --------------- */
var svg;
// look at viewbox example here: http://jsfiddle.net/NKRPe/60/
var w = 808;
var h = w*2/3;
var strokePadding = 1;
var domainSize = 1;

/* Scale needs its domain to size the current of shelves + blank aisles, so update
the scale domain anytime a shelf is added */
var scale = d3.scale.linear()
	.domain([0,1])
	.rangeRound([0,w]);

$(document).ready( function() {
	svg = d3.select('#d3').append("svg")
		.attr("width", w)
		.attr("height", h);
});

function drawShelves(shelves, scale){
	domainSize++;
	scale.domain([0,domainSize])
	// Move exisiting shelves and sections
	svg.transition().selectAll(".shelf")
			.duration(500)
			.attr("x", function(d,i) {
				return scale(i+1);
			});
	for(var i=0; i<shelves.length; i++){
		var selector = ".s" + i;
		svg.transition().selectAll(selector)
		.duration(500)
		.attr("x", function() {
			return scale(i+1) + 5;
		});
	}

	// Add the newest shelf
	svg.selectAll(".shelf").data(shelves).enter().append("rect")
		.attr("x", w+100) // initialize out of frame, then slide in
		.attr("y", strokePadding)
		.attr("rx", 5)
		.attr("ry", 5)
		.attr("width", 50)
		.attr("height", 500)
		.attr("fill", "#E1EFF5")
		.attr("stroke",  "#2E6E9E")
		.attr("stroke-width", strokePadding)
		.attr("class", "shelf")
		.transition()
		.duration(500)
		.attr("x", function(d,i) {
			return scale(i+1);
		});
}

function drawSections(shelfIndex, shelves, scale){

	var selector = ".s" + shelfIndex;

	var sectionScale = d3.scale.linear()
		.domain([0, shelves[shelfIndex].sections.length])
		.range([0,495]);

	svg.transition().selectAll(selector)
		.duration(500)
		.attr("y", function(d,i) {
			return sectionScale(i) + 5;
		})
		.attr("height", function(d,i) {
			return 495/shelves[shelfIndex].sections.length - 5;
		});

	// Add new sections
	svg.selectAll(selector).data(shelves[shelfIndex].sections).enter().append("rect")
		.attr("x", function() {
			return scale(shelfIndex+1) + 5;
		})
		.attr("y", function(d,i) {
			return sectionScale(i) + 5;
		})
		.attr("width", 40) // probably need to change the sizes
		.attr("height", function(d,i) {
			return 495/shelves[shelfIndex].sections.length - 5;
		})
		.attr("rx", 5)
		.attr("ry", 5)
		.attr("fill", "#2E6E9E")
		.attr("class", "section s" + shelfIndex)
		.attr("opacity", 0)
		// Open accordion associated with this element when clicked
		.attr("cursor", "pointer")
		.on("click", function(d, i) {
			$parentAccordion.accordion('option', 'active', shelfIndex);
			var panel = "#ui-accordion-parentAccordion-panel-" + shelfIndex;
			var sectionIndex = $(panel).accordion("option", "active", i + 1);
		})
		.transition()
		.attr("opacity", 1)
		.duration(500);
}<|endoftext|>


<commit_before>/*global define*/
define([
	'jQuery-2.1.4.min',
	'underscore_1.3.3',
	'backbone_0.9.2',
  'bootstrap-table',
  '../model/FrontEndWidgetModel.js',
  'text!../../../js/app/templates/frontEndWidget.html'
], function ($, _, Backbone, BootstrapTable, FrontEndWidgetModel, FrontEndWidgetTemplate) {
	'use strict';

	var FrontEndWidgetView = Backbone.View.extend({

		tagName:  'div',

    el: '#frontEndWidgetView',

		template: _.template(FrontEndWidgetTemplate),

		// The DOM events specific to an item.
		events: {
      'click #addHTMLBtn': 'addHTML',
      'click #addImgRowBtn': 'addImgRow',
      'click #addWidget': 'addWidget',
      'change #widgetTitle': 'updateWidget',
      'change #widgetDesc': 'updateWidget',
      'change .widgetText': 'updateWidget'
		},

		initialize: function () {
      this.targetWidget = -1; //Index that points to the currently loaded Widget.

		},

    render: function () {
      //debugger;

      this.$el.html(this.template);

      this.populateTable();

			return this;
		},

    //This function is called by render. It's purpose is to initialize and populate the bootstrap
    //table with data from the Front End Widgets Collection.
    populateTable: function() {
      //debugger;

      //Catch corner case of empty DB
      if((global.frontEndWidgetCollection.models.length == 1) &&
         (global.frontEndWidgetCollection.models[0].get('_id') == "") &&
         (global.frontEndWidgetCollection.models[0].get('title') == "") )
          return;

      //Initialize the table.
      this.$el.find('#widgetTable').bootstrapTable({
        sortName: 'entry',
        sortOrder: 'desc',
        showExport: false,
        columns: [{
          field: 'entry',
          title: 'Entry',
          sortable: true
        }, {
          field: 'title',
          title: 'Title',
          sortable: true
        }, {
          field: 'desc',
          title: 'Description',
          sortable: true
        }, {
          field: 'GUID',
          title: 'GUID',
          sortable: true
        }, {
          field: 'delete',
          title: 'Delete',
          sortable: false
        }
        ],
      });

      //Loop through the Keep Out coordinates.
      var tableData = [];
      for(var i=0; i < global.frontEndWidgetCollection.length; i++) {
        var item = global.frontEndWidgetCollection.models[i];
        var obj = new Object();

        obj.entry = i;
        obj.title = ''+item.get('title')+'';
        obj.desc = item.get('desc');
        obj.GUID = item.get('_id');
        obj.delete = '<button type="button" class="btn btn-danger btn-xs"></button>';

        tableData.push(obj);
      }
      this.$el.find('#widgetTable').bootstrapTable('load', tableData);
      this.$el.find('.fixed-table-loading').hide();

    },

    loadWidget: function(index) {
      //debugger;

      var item = global.frontEndWidgetCollection.models[index];

      this.targetWidget = index;

      //this.$el.find('#widgetEditor').slideDown(); //Show the widget editor
      this.$el.find('#widgetEditor').show(); //Show the widget editor
      this.$el.find('hr').slideDown(); //Show any hr separators

      this.$el.find('#widgetTitle').val(item.get('title'));
      this.$el.find('#widgetDesc').val(item.get('desc'));

      var htmlArray = item.get('contentArray');
      var imgArray = item.get('imgUrlArray');

      //BEGIN POPULATION OF HTML ARRAY
      if((htmlArray.length == 0) || (htmlArray.length == undefined)) {
        //Do nothing. Leave the default HTML the way it is.
        debugger;

        //On second though, do not need to do the below:
        //Add click handler to delete button above the HTML entry box.
        //this.$el.find('#widgetHTML').find('.scaffold').find('button').click([-1], this.deleteHtml);
      } else {

        for(var i=0; i < htmlArray.length; i++) {
          var tmpEntry = this.$el.find('#widgetHTML').find('.scaffold').clone(); //Clone the scaffolding
          var contentSelector = 'content'+i;

          tmpEntry.removeClass('scaffold'); //Remove the scaffold class
          tmpEntry.addClass(contentSelector);
          tmpEntry.find('button').click([i],this.deleteHtml); //Assign a click handler to the delete button
          tmpEntry.find('textarea').val(htmlArray[i]); //Populate the text box
          this.$el.find('#widgetHTML').append(tmpEntry);
        }

        //Remove the scaffolding element
        //this.$el.find('#widgetHTML').find('.scaffold').remove();
        //Hide the scaffolding element
        this.$el.find('#widgetHTML').find('.scaffold').hide();
      }
      //END POPULATION OF HTML ARRAY

      //BEGIN POPULATION OF IMAGE ARRAY
      if((imgArray.length == 0) || (imgArray.length == undefined)) {
        //Do nothing. Leave the default image layout the way it is.
        debugger;
      } else {

        //Initialize
        var colIndex = 0;
        var tmpRow = this.$el.find('#widgetImages').find('.scaffold').clone();
        tmpRow.removeClass('scaffold');

        //Loop through all the images
        for(var i=0; i < imgArray.length; i++) {
          var imgSelector = '.img'+colIndex;

          var thisImg = tmpRow.find(imgSelector);
          thisImg.find('button').click([i], this.deleteImg); //Assign a click handler to the delete button.
          thisImg.find('img').attr('onclick', ''); //Remove the default click handler.
          thisImg.find('img').click([i], this.swapImg); //Assign a click handler to the image to swap out the image with a new one.
          thisImg.find('img').attr('src', imgArray[i]); //Swap out the image with the one assigned to the widget.

          //Manage the column index
          colIndex++;
          if(colIndex > 2) {
            colIndex = 0;

            this.$el.find('#widgetImages').prepend(tmpRow);
            var tmpRow = this.$el.find('#widgetImages').find('scaffold').clone();
            //tmpRow.find('.label').remove(); //Remove the label.
            tmpRow.removeClass('scaffold');
          }
        }

        this.$el.find('#widgetImages').find('.scaffold').remove();
        this.$el.find('#widgetImages').prepend(tmpRow);
      }
      //END POPULATION OF IMAGE ARRAY
    },

    //This function is called when the user clicks on the delete button assigned to an HTML array
    //element. It's purpose is to remove the array entry from the model.
    deleteHtml: function(event) {
      debugger;

      //If index is a click event object, then retrieve the data passed in.
      //if(typeof(index) == "object")
      //  index = index.data[0];

      //-1 means there is no entry created yet, just clear the textarea.
      //if(index == -1) {
      //  this.$el.find('.widgetText').val(''); //Clear text area
      //}

      //Get the contentArray from the model.
      var thisModel = global.frontEndWidgetCollection.models[global.frontEndWidgetView.targetWidget];
      var contentArray = thisModel.get('contentArray');

      //Create a handle for the parent

      var textDiv = $(event.target).parent();
      //Fixes bug where user clicks on fa icon instead of button.
      var textDivClass = textDiv.attr('class');
      if(textDivClass.indexOf('btn') != -1)
        textDiv = textDiv.parent();

      var isContent0 = (textDiv.attr('class').indexOf('content0') != -1);

      if(isContent0) {
        textDiv.find('textarea').val(''); //Clear the text area

        var contentArrayNotEmpty = ((contentArray[0] != "") && (contentArray[0] != undefined))

        //Delete contentArray element 0 if it exists
        if(contentArrayNotEmpty) {
          contentArray.splice(0,1);
          thisModel.set('contentArray', contentArray);

          thisModel.refreshWidget = true;
          thisModel.save();
        }
      } else {

        //Find out what contentArray element this text box is associated with
        var classIndex = textDiv.attr('class').indexOf('content');
        var contentClass = textDiv.attr('class').slice(classIndex);
        var contentIndex = Number(contentClass.slice(7));

        //Delete that element from the contentArray (if it exists)
        contentArray.splice(contentIndex,1);
        thisModel.set('contentArray', contentArray);
        //thisModel.save();

        //Remove the text area
        //$(event.target).parent().remove();
        //textDiv.remove();

        //Rerender the UI
        thisModel.refreshWidget = true;
        thisModel.save();
      }

    },

    //This function is called when the user clicks on the delete button assigned to the image.
    //It's purpose is to remove the image from the current front end widget.
    deleteImg: function(index) {
      debugger;

      //If index is a click event object, then retrieve the data passed in.
      if(typeof(index) == "object")
        index = index.data[0];
    },

    swapImg: function(index) {
      debugger;

      //If index is a click event object, then retrieve the data passed in.
      if(typeof(index) == "object")
        index = index.data[0];

      if(index == -1) {
        console.log('Empty image was clicked');
      } else {
        console.log('Existing image was clicked');
      }
    },

    //This function is called when a user clicks on the delete button for a widget.
    deleteWidget: function(index) {
      debugger;

      var thisModel = global.frontEndWidgetCollection.models[index];

      $.get('/api/frontendwidget/'+thisModel.id+'/remove', '', function(data) {
        debugger;

        global.frontEndWidgetCollection.refreshView = true;
        global.frontEndWidgetCollection.fetch();
      });
    },

    //This function is called when the user clicks on the 'Add HTML' button.
    //This function adds a new textarea element to the DOM for additional content.
    addHTML: function() {
      debugger;

      var targetModel = global.frontEndWidgetCollection.models[global.frontEndWidgetView.targetWidget];
      var contentArray = targetModel.get('contentArray');
      var contentIndex = contentArray.length;

      var tmpEntry = this.$el.find('#widgetHTML').find('.scaffold').clone(); //Clone the scaffolding
      tmpEntry.removeClass('scaffold'); //Remove the scaffold class
      tmpEntry.find('button').click([contentIndex],this.deleteHtml); //Assign a click handler to the delete button
      this.$el.find('#widgetHTML').append(tmpEntry);
      tmpEntry.show();
    },

    //This function is called when the suer clicks on the 'Add Image Row' button.
    addImgRow: function() {
      debugger;
    },

    //This function is called when the user clicks on the 'Add Widget' button.
    addWidget: function() {
      debugger;

      var newWidget = new FrontEndWidgetModel({title: 'new widget'});
      $.post('/api/frontendwidget/create', newWidget.attributes, function(data) {
        debugger;

        global.frontEndWidgetCollection.refreshView = true;
        global.frontEndWidgetCollection.fetch();
      });

      this.render();
    },

    //This function gets called anytime any of the input fields are changed.
    //The purpose is to save data in an event-driven way and then sync those changes with the server.
    updateWidget: function(event) {
      var thisModel = global.frontEndWidgetCollection.models[this.targetWidget];

      thisModel.set('title', this.$el.find('#widgetTitle').val());
      thisModel.set('desc', this.$el.find('#widgetDesc').val());

      //var widgetTextElems = this.$el.find('.widgetText');
      //for(var i=0; i < widgetTextElems.length; i++) {
      //  debugger;
      //}

      //$(event.target)

      debugger;
      // BEGIN SAVING CONTENT ARRAY
      var contentArray = thisModel.get('contentArray');

      var widgetTextElems = this.$el.find('.widgetText');
      var widgetTextDivs = widgetTextElems.parent();
      for(var i=0; i < widgetTextDivs.length; i++) {
        var thisElem = $(widgetTextDivs[i]);
        var thisClass = thisElem.attr('class');

        //Skip the scaffold element
        if(thisElem.hasClass('scaffold'))
          continue;

        //Get the contentArray index this textarray element represents
        var classIndex = $(widgetTextDivs[i]).attr('class').indexOf('content');
        var contentClass = $(widgetTextDivs[i]).attr('class').slice(classIndex);
        var contentIndex = Number(contentClass.slice(7));

        var content = thisElem.find('textarea').val();

        if(contentIndex >= contentArray.length) {
          contentArray.push(content);
        } else {
          contentArray[contentIndex] = content;
        }

      }

      //var tmpArray = thisModel.get('contentArray');
      //tmpArray.push(widgetTextElems);
      thisModel.set('contentArray', contentArray);

      thisModel.save();
      // END SAVING CONTENT ARRAY

    }

	});

  //debugger;
	return FrontEndWidgetView;
});<commit_msg>Developing data passing and button control code in Front End Widgets view.<commit_after>/*global define*/
define([
	'jQuery-2.1.4.min',
	'underscore_1.3.3',
	'backbone_0.9.2',
  'bootstrap-table',
  '../model/FrontEndWidgetModel.js',
  'text!../../../js/app/templates/frontEndWidget.html'
], function ($, _, Backbone, BootstrapTable, FrontEndWidgetModel, FrontEndWidgetTemplate) {
	'use strict';

	var FrontEndWidgetView = Backbone.View.extend({

		tagName:  'div',

    el: '#frontEndWidgetView',

		template: _.template(FrontEndWidgetTemplate),

		// The DOM events specific to an item.
		events: {
      'click #addHTMLBtn': 'addHTML',
      'click #addImgRowBtn': 'addImgRow',
      'click #addWidget': 'addWidget',
      'change #widgetTitle': 'updateWidget',
      'change #widgetDesc': 'updateWidget',
      'change .widgetText': 'updateWidget'
		},

		initialize: function () {
      this.targetWidget = -1; //Index that points to the currently loaded Widget.

		},

    render: function () {
      //debugger;

      this.$el.html(this.template);

      this.populateTable();

			return this;
		},

    //This function is called by render. It's purpose is to initialize and populate the bootstrap
    //table with data from the Front End Widgets Collection.
    populateTable: function() {
      //debugger;

      //Catch corner case of empty DB
      if((global.frontEndWidgetCollection.models.length == 1) &&
         (global.frontEndWidgetCollection.models[0].get('_id') == "") &&
         (global.frontEndWidgetCollection.models[0].get('title') == "") )
          return;

      //Initialize the table.
      this.$el.find('#widgetTable').bootstrapTable({
        sortName: 'entry',
        sortOrder: 'desc',
        showExport: false,
        columns: [{
          field: 'entry',
          title: 'Entry',
          sortable: true
        }, {
          field: 'title',
          title: 'Title',
          sortable: true
        }, {
          field: 'desc',
          title: 'Description',
          sortable: true
        }, {
          field: 'GUID',
          title: 'GUID',
          sortable: true
        }, {
          field: 'delete',
          title: 'Delete',
          sortable: false
        }
        ],
      });

      //Loop through the Keep Out coordinates.
      var tableData = [];
      for(var i=0; i < global.frontEndWidgetCollection.length; i++) {
        var item = global.frontEndWidgetCollection.models[i];
        var obj = new Object();

        obj.entry = i;
        obj.title = ''+item.get('title')+'';
        obj.desc = item.get('desc');
        obj.GUID = item.get('_id');
        obj.delete = '<button type="button" class="btn btn-danger btn-xs"></button>';

        tableData.push(obj);
      }
      this.$el.find('#widgetTable').bootstrapTable('load', tableData);
      this.$el.find('.fixed-table-loading').hide();

    },

    loadWidget: function(index) {
      //debugger;

      var item = global.frontEndWidgetCollection.models[index];

      this.targetWidget = index;

      //this.$el.find('#widgetEditor').slideDown(); //Show the widget editor
      this.$el.find('#widgetEditor').show(); //Show the widget editor
      this.$el.find('hr').slideDown(); //Show any hr separators

      this.$el.find('#widgetTitle').val(item.get('title'));
      this.$el.find('#widgetDesc').val(item.get('desc'));

      var htmlArray = item.get('contentArray');
      var imgArray = item.get('imgUrlArray');

      //BEGIN POPULATION OF HTML ARRAY
      if((htmlArray.length == 0) || (htmlArray.length == undefined)) {
        //Do nothing. Leave the default HTML the way it is.
        debugger;

        //On second though, do not need to do the below:
        //Add click handler to delete button above the HTML entry box.
        //this.$el.find('#widgetHTML').find('.scaffold').find('button').click([-1], this.deleteHtml);
      } else {

        for(var i=0; i < htmlArray.length; i++) {
          var tmpEntry = this.$el.find('#widgetHTML').find('.scaffold').clone(); //Clone the scaffolding
          var contentSelector = 'content'+i;

          tmpEntry.removeClass('scaffold'); //Remove the scaffold class
          tmpEntry.addClass(contentSelector);
          tmpEntry.find('button').click([i],this.deleteHtml); //Assign a click handler to the delete button
          tmpEntry.find('textarea').val(htmlArray[i]); //Populate the text box
          this.$el.find('#widgetHTML').append(tmpEntry);
        }

        //Remove the scaffolding element
        //this.$el.find('#widgetHTML').find('.scaffold').remove();
        //Hide the scaffolding element
        this.$el.find('#widgetHTML').find('.scaffold').hide();
      }
      //END POPULATION OF HTML ARRAY

      //BEGIN POPULATION OF IMAGE ARRAY
      if((imgArray.length == 0) || (imgArray.length == undefined)) {
        //Do nothing. Leave the default image layout the way it is.
        debugger;
      } else {

        //Initialize
        var colIndex = 0;
        var tmpRow = this.$el.find('#widgetImages').find('.scaffold').clone();
        tmpRow.removeClass('scaffold');

        //Loop through all the images
        for(var i=0; i < imgArray.length; i++) {
          var imgSelector = '.img'+colIndex;

          var thisImg = tmpRow.find(imgSelector);
          thisImg.find('button').click([i], this.deleteImg); //Assign a click handler to the delete button.
          thisImg.find('img').attr('onclick', ''); //Remove the default click handler.
          thisImg.find('img').click([i], this.swapImg); //Assign a click handler to the image to swap out the image with a new one.
          thisImg.find('img').attr('src', imgArray[i]); //Swap out the image with the one assigned to the widget.

          //Manage the column index
          colIndex++;
          if(colIndex > 2) {
            colIndex = 0;

            this.$el.find('#widgetImages').prepend(tmpRow);
            var tmpRow = this.$el.find('#widgetImages').find('scaffold').clone();
            //tmpRow.find('.label').remove(); //Remove the label.
            tmpRow.removeClass('scaffold');
          }
        }

        this.$el.find('#widgetImages').find('.scaffold').remove();
        this.$el.find('#widgetImages').prepend(tmpRow);
      }
      //END POPULATION OF IMAGE ARRAY
    },

    //This function is called when the user clicks on the delete button assigned to an HTML array
    //element. It's purpose is to remove the array entry from the model.
    deleteHtml: function(event) {
      debugger;

      //If index is a click event object, then retrieve the data passed in.
      //if(typeof(index) == "object")
      //  index = index.data[0];

      //-1 means there is no entry created yet, just clear the textarea.
      //if(index == -1) {
      //  this.$el.find('.widgetText').val(''); //Clear text area
      //}

      //Get the contentArray from the model.
      var thisModel = global.frontEndWidgetCollection.models[global.frontEndWidgetView.targetWidget];
      var contentArray = thisModel.get('contentArray');

      //Create a handle for the parent

      var textDiv = $(event.target).parent();
      //Fixes bug where user clicks on fa icon instead of button.
      var textDivClass = textDiv.attr('class');
      if(textDivClass.indexOf('btn') != -1)
        textDiv = textDiv.parent();

      var isContent0 = (textDiv.attr('class').indexOf('content0') != -1);

      if(isContent0) {
        textDiv.find('textarea').val(''); //Clear the text area

        var contentArrayNotEmpty = ((contentArray[0] != "") && (contentArray[0] != undefined))

        //Delete contentArray element 0 if it exists
        if(contentArrayNotEmpty) {
          contentArray.splice(0,1);
          thisModel.set('contentArray', contentArray);

          thisModel.refreshWidget = true;
          thisModel.save();
        }
      } else {

        //Find out what contentArray element this text box is associated with
        var classIndex = textDiv.attr('class').indexOf('content');
        var contentClass = textDiv.attr('class').slice(classIndex);
        var contentIndex = Number(contentClass.slice(7));

        //Delete that element from the contentArray (if it exists)
        contentArray.splice(contentIndex,1);
        thisModel.set('contentArray', contentArray);
        //thisModel.save();

        //Remove the text area
        //$(event.target).parent().remove();
        //textDiv.remove();

        //Rerender the UI
        thisModel.refreshWidget = true;
        thisModel.save();
      }

    },

    //This function is called when the user clicks on the delete button assigned to the image.
    //It's purpose is to remove the image from the current front end widget.
    deleteImg: function(index) {
      debugger;

      //If index is a click event object, then retrieve the data passed in.
      if(typeof(index) == "object")
        index = index.data[0];
    },

    swapImg: function(index) {
      debugger;

      //If index is a click event object, then retrieve the data passed in.
      if(typeof(index) == "object")
        index = index.data[0];

      if(index == -1) {
        console.log('Empty image was clicked');
      } else {
        console.log('Existing image was clicked');
      }
    },

    //This function is called when a user clicks on the delete button for a widget.
    deleteWidget: function(index) {
      debugger;

      var thisModel = global.frontEndWidgetCollection.models[index];

      $.get('/api/frontendwidget/'+thisModel.id+'/remove', '', function(data) {
        debugger;

        global.frontEndWidgetCollection.refreshView = true;
        global.frontEndWidgetCollection.fetch();
      });
    },

    //This function is called when the user clicks on the 'Add HTML' button.
    //This function adds a new textarea element to the DOM for additional content.
    addHTML: function() {
      debugger;

      var targetModel = global.frontEndWidgetCollection.models[global.frontEndWidgetView.targetWidget];
      var contentArray = targetModel.get('contentArray');
      var contentIndex = contentArray.length;

      var tmpEntry = this.$el.find('#widgetHTML').find('.scaffold').clone(); //Clone the scaffolding
      tmpEntry.removeClass('scaffold'); //Remove the scaffold class
      tmpEntry.find('button').click([contentIndex],this.deleteHtml); //Assign a click handler to the delete button
      this.$el.find('#widgetHTML').append(tmpEntry);
      tmpEntry.show();
    },

    //This function is called when the suer clicks on the 'Add Image Row' button.
    addImgRow: function() {
      debugger;
    },

    //This function is called when the user clicks on the 'Add Widget' button.
    addWidget: function() {
      debugger;

      var newWidget = new FrontEndWidgetModel({title: 'new widget'});
      $.post('/api/frontendwidget/create', newWidget.attributes, function(data) {
        debugger;

        global.frontEndWidgetCollection.refreshView = true;
        global.frontEndWidgetCollection.fetch();
      });

      this.render();
    },

    //This function gets called anytime any of the input fields are changed.
    //The purpose is to save data in an event-driven way and then sync those changes with the server.
    updateWidget: function(event) {
      var thisModel = global.frontEndWidgetCollection.models[this.targetWidget];

      thisModel.set('title', this.$el.find('#widgetTitle').val());
      thisModel.set('desc', this.$el.find('#widgetDesc').val());

      //var widgetTextElems = this.$el.find('.widgetText');
      //for(var i=0; i < widgetTextElems.length; i++) {
      //  debugger;
      //}

      //$(event.target)

      debugger;
      // BEGIN SAVING CONTENT ARRAY
      var contentArray = thisModel.get('contentArray');

      var widgetTextElems = this.$el.find('.widgetText');
      var widgetTextDivs = widgetTextElems.parent();
      for(var i=0; i < widgetTextDivs.length; i++) {
        var thisElem = $(widgetTextDivs[i]);
        var thisClass = thisElem.attr('class');

        //Skip the scaffold element
        if(thisElem.hasClass('scaffold'))
          continue;

        //Get the contentArray index this textarray element represents
        var classIndex = $(widgetTextDivs[i]).attr('class').indexOf('content');
        var contentClass = $(widgetTextDivs[i]).attr('class').slice(classIndex);
        var contentIndex = Number(contentClass.slice(7));

        var content = thisElem.find('textarea').val();

        if(contentIndex >= contentArray.length) {
          contentArray.push(content);
        } else {
          contentArray[contentIndex] = content;
        }

      }

      //var tmpArray = thisModel.get('contentArray');
      //tmpArray.push(widgetTextElems);
      thisModel.set('contentArray', contentArray);

      thisModel.refreshWidget = true;
      thisModel.save();
      // END SAVING CONTENT ARRAY

    }

	});

  //debugger;
	return FrontEndWidgetView;
});<|endoftext|>


<commit_before>$('nav.tabs a').on('click', function() { // selects nav element w/ class `tabs` and adds event listener
  // if($(this).hasClass('active'));
  //   $(this).removeClass('active');

  if($(this).hasClass(''));
    $(this).addClass('active');

  // $("").removeClass('active');
  //   $(this).removeClass('active');
  // $('a').removeClass('active');
});

// $('.active').on('click', function() {
//   $(this).removeClass('active');
// });
<commit_msg>adds and removes class 'active' but only on first click<commit_after>$('nav.tabs a').on('click', function() { // selects nav element w/ class `tabs` and adds event listener
  if(!$(this).hasClass('active')) // if this does not have class `active`...
    $(this).addClass('active'); // ...add class `active`
      $('nav.tabs a.active').on('click', function() {
        // if($(this).hasClass('active'))
          $(this).removeClass('active');
      });
});
<|endoftext|>


<commit_before>// @source https://github.com/NyaaPantsu/nyaa/tree/dev/public/js
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
var TorrentsMod = {
  // Variables that can be modified to change the dom interactions
  show_hide_button: "show_actions",
  btn_class_action: "cb_action",
  btn_class_submit: "cb_submit",
  progress_bar_id: "progress_modtool",
  status_input_name: "status_id",
  owner_input_name: "owner_id",
  category_input_name: "category_id",
  delete_btn: "delete",
  lock_delete_btn: "lock_delete",
  edit_btn: "edit",
  refreshTimeout: 3000,
  // Internal variables used for processing the request
  selected: [],
  queued: [],
  unique_id:1,
  error_count:0,
  progress_count: 0,
  progress_max: 0,
  pause: false,
  enabled: false,

  // Init method
  Create: function() {
    var sh_btn = document.getElementById(TorrentsMod.show_hide_button);
    var btn_actions = document.getElementsByClassName(this.btn_class_action)
    var btn_submit = document.getElementsByClassName(this.btn_class_submit)
    btn_submit[0].disabled = true;
    for (var i=0; i < btn_actions.length; i++) {
      btn_actions[i].disabled = true;
      switch (btn_actions[i].id) {
        case this.delete_btn:
        btn_actions[i].addEventListener("click", this.Delete)
        break;
        case this.lock_delete_btn:
        btn_actions[i].addEventListener("click", this.LockDelete)
        break;
        case this.edit_btn:
        btn_actions[i].addEventListener("click", this.Edit)
        break;
        default:
        break;
      }
    }
    for (var i=0; i < this.checkboxes.length; i++) {
      checkbox = this.checkboxes[i];
      checkbox.addEventListener("change", this.checkboxEventHandler)
    }
    sh_btn.addEventListener("click", function(e) {
      var divActions = this.nextElementSibling;
      if (divActions.style.display == "inline") {
        TorrentsMod.enabled = false;
      } else {
        TorrentsMod.enabled = true;
      }
      divActions.style.display = (TorrentsMod.enabled) ? "inline" : "none";
      var td_cbs = document.getElementsByClassName("tr-cb")
      for (var i=0; i < td_cbs.length; i++) {
        td_cb = td_cbs[i];
        td_cb.style.display = (TorrentsMod.enabled) ? "table-cell" : "none";
      }
      var toggleText = this.dataset.toggleText;
      this.dataset.toggleText = this.innerText;
      this.innerText = toggleText;
    });
  },
  // generate a unique id for a query
  getId: function(){
    return this.unique_id++;
  },

  // UI Methods
  selectAll: function(bool) {
    var l = TorrentsMod.checkboxes.length;
    for (var i = 0; i < l; i++) {
      TorrentsMod.checkboxes[i].checked = bool;
      TorrentsMod.checkboxEventHandlerFunc(TorrentsMod.checkboxes[i]);
    }
  },
  disableBtnActions: function() {
    var btn_actions = document.getElementsByClassName(this.btn_class_action)
    for (var i=0; i < btn_actions.length; i++) {
      btn_actions[i].disabled = true;
    }
  },
  enableBtnActions: function() {
    var btn_actions = document.getElementsByClassName(this.btn_class_action)
    for (var i=0; i < btn_actions.length; i++) {
      btn_actions[i].disabled = false;
    }
  },
  enableBtnSubmit: function() {
    var btn_submit = document.getElementsByClassName(this.btn_class_submit)
    btn_submit[0].disabled = false;
  },
  enableApplyChangesBtn: function() {
    var btn_apply_changes = document.getElementById("confirm_changes");
    btn_apply_changes.disabled=false;
  },
  disableBtnSubmit: function() {
    var btn_submit = document.getElementsByClassName(this.btn_class_submit)
    btn_submit[0].disabled = true;
  },
  disableApplyChangesBtn: function() {
    var btn_apply_changes = document.getElementById("confirm_changes");
    btn_apply_changes.disabled=true;
  },
  removeDivFromList: function(i) {
    var queueAction = this.queued[i];
    var parentDiv = document.getElementById(queueAction.unique_id).parentNode;
    parentDiv.removeChild(document.getElementById(queueAction.unique_id));
  },
  removeFromParent: function(el) {
    var parentDiv = el.parentNode;
    parentDiv.removeChild(el);
  },
  generatingModal: function() {
    listLength = this.queued.length;
    var div = {"edit": "", "delete": ""};
    for (var i=0; i < listLength; i++) {
      var listHTML = "";
      for(key in this.queued[i].selection) {
        var selection = this.queued[i].selection[key];
        selection.key = i;
        listHTML += Templates.Render("torrents."+this.queued[i].action+".item", selection);
      }
      this.queued[i].list = listHTML;
      this.queued[i].key = i;
      div[this.queued[i].action] += Templates.Render("torrents."+this.queued[i].action+".block", this.queued[i]);
    }
    this.progress_count = 0;
    this.progress_max = listLength;
    document.querySelector(".modal .edit_changes").innerHTML = div["edit"];
    document.querySelector(".modal .delete_changes").innerHTML = div["delete"];
  },
  toggleList: function(el) {
    el.parentNode.nextSibling.style.display = (el.parentNode.nextSibling.style.display != "block") ? "block" : "none"
  },
  addToLog: function(type, msg) {
    var logDiv = document.querySelector(".modal .logs_mess");
    if (logDiv.style.display == "none") logDiv.style.display = "block"
    logDiv.innerHTML += Templates.Render("torrents.logs."+type, msg);
  },
  updateProgressBar: function() {
    document.querySelector("#"+this.progress_bar_id).style.display = "block";
    var progress_green = document.querySelector("#"+this.progress_bar_id+" .progress-green");
    var perc = this.progress_count/this.progress_max*100;
    progress_green.style.width=perc+"%";
    progress_green.innerText = this.progress_count+"/"+this.progress_max;
  },
  resetModal: function() {
    var logDiv = document.querySelector(".modal .logs_mess");
    logDiv.style.display = "none";
    document.querySelector("#"+this.progress_bar_id).style.display = "none";
    logDiv.innerHTML = "";
    document.querySelector(".modal .edit_changes").innerHTML = "";
    document.querySelector(".modal .delete_changes").innerHTML = "";
    this.enableApplyChangesBtn();
  },
  statusToClassName: function(status) {
    var className = ["", "normal", "remake", "trusted", "aplus", ""]
    return className[status];
  },

  // Selection Management Methods
  addToSelection: function (torrent) {
    this.selected[torrent.id] = torrent;
  },
  removeFromSelection: function(torrent) {
    delete this.selected[torrent.id];
    for (t in this.selected) {
      return
    }
    this.selected = [];
  },

  // Query Queue Management Methods
  AddToQueue: function(QueueAction) {
    QueueAction.unique_id = this.getId(); // used for DOM interaction
    this.queued.push(QueueAction);
    this.enableBtnSubmit()
  },
  RemoveFromQueueAfterItems: function(i) {
    for (t in this.queued[i].selection) {
      this.RemoveItemFromQueue(i, t);
    }
  },
  RemoveFromQueue: function(i) {
    this.progress_max = (this.progress_max - 1 >= 0) ? this.progress_max-1 : 0;
    this.RemoveFromQueueAction(i)
    return false;
  },
  RemoveFromQueueAction: function(i) {
    this.removeFromParent(document.getElementById("list_"+this.queued[i].unique_id));
    this.queued.splice(i, 1);
    if (this.queued.length == 0) {
      this.disableBtnSubmit();
      if (this.progress_max>0) {
        this.disableApplyChangesBtn();
      } else {
        Modal.CloseActive();
      }
    }
  },
  formatSelectionToQuery: function(selection) {
    var format = "";
    for (s in selection) {
      format += "&torrent_id="+selection[s].id
    }
    return (format != "") ? format.substr(1) : ""
  },
  RemoveItemFromQueue: function(i, id) {
    this.removeFromParent(document.getElementById("list_item_"+id));
    delete this.queued[i].selection[id];
    document.getElementById("torrent_cb_"+id).checked=false;
    document.getElementById("torrent_"+id).style.display="";
    var test = 0;
    for (t in this.queued[i].selection) {
      test++
      break;
    }
    if (test == 0) this.RemoveFromQueue(i);
    return false;
  },
  newQueryAttempt: function(queryUrl, queryPost, callback) {
    Query.Post(queryUrl, queryPost, function (response) {
      if ((response.length == 0)||(!response.ok)) { // Query has failed
        var errorMsg = response.errors.join("
");
        TorrentsMod.addToLog("error", errorMsg);
        TorrentsMod.error_count++;
        if (TorrentsMod.error_count < 2) {
          TorrentsMod.addToLog("success", T.r("try_new_attempt"));
          TorrentsMod.newQueryAttempt(queryUrl, queryPost, callback)
        } else {
          TorrentsMod.addToLog("error", T.r("query_is_broken", queryUrl, queryPost));
          if (callback != undefined) {
            TorrentsMod.addToLog("error", "Passing to the next query...");
            callback(response) // So we can query only one item
          }
        }
      } else {
        var succesMsg = (response.infos != null) ? response.infos.join("
") : T.r("query_executed_success");
        TorrentsMod.addToLog("success", succesMsg)
        if (callback != undefined) callback(response) // So we can query only one item
      }
    });
  },
  QueryQueue: function(i, callback) {
    if (this.queued.length > 0) {
      var QueueAction = this.queued[i]; // we clone it so we can delete it safely
      this.RemoveFromQueueAction(i);
      var queryPost = "";
      var queryUrl = "/mod/api/torrents";
      QueueAction.queryPost = TorrentsMod.formatSelectionToQuery(QueueAction.selection)
      if (QueueAction.action == "delete") {
        queryPost="action="+QueueAction.action;
        queryPost+="&withreport="+QueueAction.withReport;
        queryPost += "&status="+((QueueAction.status != undefined) ? QueueAction.status : "");
        queryPost += "&"+QueueAction.queryPost; // we add torrent id
      } else if (QueueAction.action == "edit") {
        queryPost="action=multiple";
        queryPost += "&status="+QueueAction.status;
        queryPost += "&owner="+QueueAction.owner;
        queryPost += "&category="+QueueAction.category;
        queryPost += "&"+QueueAction.queryPost; // we add torrent id
      }
      TorrentsMod.newQueryAttempt(queryUrl, queryPost, callback)
    } else {
      TorrentsMod.addToLog("success", T.r("all_operations_done"))
      if (TorrentsMod.refreshTimeout > 0) {
        TorrentsMod.addToLog("success", T.r("refreshing_in", TorrentsMod.refreshTimeout/1000))
        setTimeout(function(){
          window.location.reload()
        }, TorrentsMod.refreshTimeout);
      }
    }
  },
  QueryLoop: function() {
    if (TorrentsMod.progress_count <= TorrentsMod.progress_max) {
      TorrentsMod.updateProgressBar()
      TorrentsMod.progress_count++;
      if (TorrentsMod.progress_count > TorrentsMod.progress_max) TorrentsMod.progress_count = TorrentsMod.progress_max;
      TorrentsMod.QueryQueue(0, TorrentsMod.QueryLoop);
    }
  },

  // Event Handlers
  checkboxEventHandler: function(e) {
    var el = e.target;
    TorrentsMod.checkboxEventHandlerFunc(el);
  },
  checkboxEventHandlerFunc: function(el) {
    var name = el.dataset.name;
    var id = el.value;
    if (el.checked) TorrentsMod.addToSelection({name:name, id:id});
    else TorrentsMod.removeFromSelection({name:name, id:id});
    if (TorrentsMod.selected.length > 0) TorrentsMod.enableBtnActions();
    else TorrentsMod.disableBtnActions();
  },

  // Action Methods
  DeleteHandler: function(locked) {
    var withReport = confirm(T.r("delete_reports_with_torrents"))
    var selection = TorrentsMod.selected;
    if (locked)
    TorrentsMod.AddToQueue({ action: "delete",
    withReport: withReport,
    selection: selection,
    queryPost: "",
    infos: T.r("with_lock")+ ((withReport) ? T.r("and_reports") : ""),
    status: "5" });
    else TorrentsMod.AddToQueue({
      action: "delete",
      withReport: withReport,
      selection: selection,
      infos: (withReport) ? T.r("with_reports") : "",
      queryPost: ""});
      for (i in selection) document.getElementById("torrent_"+i).style.display="none";
      TorrentsMod.selected = []
      TorrentsMod.disableBtnActions();
    },
    Delete: function(e) {
      TorrentsMod.DeleteHandler(false);
      e.preventDefault();
    },
    LockDelete: function(e) {
      TorrentsMod.DeleteHandler(true);
      e.preventDefault();
    },
    Edit: function(e) {
      var selection = TorrentsMod.selected;
      var status = document.querySelector(".modtools *[name='"+TorrentsMod.status_input_name+"']").value;
      var owner_id = document.querySelector(".modtools *[name='"+TorrentsMod.owner_input_name+"']").value;
      var category = document.querySelector(".modtools *[name='"+TorrentsMod.category_input_name+"']").value;
      var infos = "";
      infos += (status != "") ? T.r("status_js", status) : "";
      infos += (owner_id != "") ? T.r("owner_id_js", owner_id) : "";
      infos += (category != "") ? T.r("category_js", category) : "";
      TorrentsMod.AddToQueue({
        action: "edit",
        selection: selection,
        queryPost: "", // We don't format now, we wait until the query is sent
        infos: (infos != "" ) ? T.r("with_st", infos) : T.r("no_changes"),
        status: status,
        category: category,
        owner: owner_id });
        if (status != "") {
          for (i in selection) document.getElementById("torrent_"+i).className="torrent-info "+TorrentsMod.statusToClassName(status);
        }
        TorrentsMod.selected = []
        TorrentsMod.disableBtnActions();
        e.preventDefault();
      },
      ApplyChanges: function() {
        this.pause = false;
        this.QueryLoop();
      }
    };

    // Load torrentMods when DOM is ready
    document.addEventListener("DOMContentLoaded", function() {
      TorrentsMod.checkboxes =  document.querySelectorAll("input[name='torrent_id']");
      TorrentsMod.Create();
    });
    // @license-end
<commit_msg>Fixing translation in modtools<commit_after>// @source https://github.com/NyaaPantsu/nyaa/tree/dev/public/js
// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat
var TorrentsMod = {
  // Variables that can be modified to change the dom interactions
  show_hide_button: "show_actions",
  btn_class_action: "cb_action",
  btn_class_submit: "cb_submit",
  progress_bar_id: "progress_modtool",
  status_input_name: "status_id",
  owner_input_name: "owner_id",
  category_input_name: "category_id",
  delete_btn: "delete",
  lock_delete_btn: "lock_delete",
  edit_btn: "edit",
  refreshTimeout: 3000,
  // Internal variables used for processing the request
  selected: [],
  queued: [],
  unique_id:1,
  error_count:0,
  progress_count: 0,
  progress_max: 0,
  pause: false,
  enabled: false,

  // Init method
  Create: function() {
    var sh_btn = document.getElementById(TorrentsMod.show_hide_button);
    var btn_actions = document.getElementsByClassName(this.btn_class_action)
    var btn_submit = document.getElementsByClassName(this.btn_class_submit)
    btn_submit[0].disabled = true;
    for (var i=0; i < btn_actions.length; i++) {
      btn_actions[i].disabled = true;
      switch (btn_actions[i].id) {
      case this.delete_btn:
        btn_actions[i].addEventListener("click", this.Delete)
        break;
      case this.lock_delete_btn:
        btn_actions[i].addEventListener("click", this.LockDelete)
        break;
      case this.edit_btn:
        btn_actions[i].addEventListener("click", this.Edit)
        break;
      default:
        break;
      }
    }
    for (var i=0; i < this.checkboxes.length; i++) {
      var checkbox = this.checkboxes[i];
      checkbox.addEventListener("change", this.checkboxEventHandler)
    }
    sh_btn.addEventListener("click", function(e) {
      var divActions = this.nextElementSibling;
      if (divActions.style.display == "inline") {
        TorrentsMod.enabled = false;
      } else {
        TorrentsMod.enabled = true;
      }
      divActions.style.display = (TorrentsMod.enabled) ? "inline" : "none";
      var td_cbs = document.getElementsByClassName("tr-cb")
      for (var i=0; i < td_cbs.length; i++) {
        td_cb = td_cbs[i];
        td_cb.style.display = (TorrentsMod.enabled) ? "table-cell" : "none";
      }
      var toggleText = this.dataset.toggleText;
      this.dataset.toggleText = this.innerText;
      this.innerText = toggleText;
    });
  },
  // generate a unique id for a query
  getId: function(){
    return this.unique_id++;
  },

  // UI Methods
  selectAll: function(bool) {
    var l = TorrentsMod.checkboxes.length;
    for (var i = 0; i < l; i++) {
      TorrentsMod.checkboxes[i].checked = bool;
      TorrentsMod.checkboxEventHandlerFunc(TorrentsMod.checkboxes[i]);
    }
  },
  disableBtnActions: function() {
    var btn_actions = document.getElementsByClassName(this.btn_class_action)
    for (var i=0; i < btn_actions.length; i++) {
      btn_actions[i].disabled = true;
    }
  },
  enableBtnActions: function() {
    var btn_actions = document.getElementsByClassName(this.btn_class_action)
    for (var i=0; i < btn_actions.length; i++) {
      btn_actions[i].disabled = false;
    }
  },
  enableBtnSubmit: function() {
    var btn_submit = document.getElementsByClassName(this.btn_class_submit)
    btn_submit[0].disabled = false;
  },
  enableApplyChangesBtn: function() {
    var btn_apply_changes = document.getElementById("confirm_changes");
    btn_apply_changes.disabled=false;
  },
  disableBtnSubmit: function() {
    var btn_submit = document.getElementsByClassName(this.btn_class_submit)
    btn_submit[0].disabled = true;
  },
  disableApplyChangesBtn: function() {
    var btn_apply_changes = document.getElementById("confirm_changes");
    btn_apply_changes.disabled=true;
  },
  removeDivFromList: function(i) {
    var queueAction = this.queued[i];
    var parentDiv = document.getElementById(queueAction.unique_id).parentNode;
    parentDiv.removeChild(document.getElementById(queueAction.unique_id));
  },
  removeFromParent: function(el) {
    var parentDiv = el.parentNode;
    parentDiv.removeChild(el);
  },
  generatingModal: function() {
    var listLength = this.queued.length;
    var div = {"edit": "", "delete": ""};
    for (var i=0; i < listLength; i++) {
      var listHTML = "";
      for(key in this.queued[i].selection) {
        var selection = this.queued[i].selection[key];
        selection.key = i;
        listHTML += Templates.Render("torrents."+this.queued[i].action+".item", selection);
      }
      this.queued[i].list = listHTML;
      this.queued[i].key = i;
      div[this.queued[i].action] += Templates.Render("torrents."+this.queued[i].action+".block", this.queued[i]);
    }
    this.progress_count = 0;
    this.progress_max = listLength;
    document.querySelector(".modal .edit_changes").innerHTML = div["edit"];
    document.querySelector(".modal .delete_changes").innerHTML = div["delete"];
  },
  toggleList: function(el) {
    el.parentNode.nextSibling.style.display = (el.parentNode.nextSibling.style.display != "block") ? "block" : "none"
  },
  addToLog: function(type, msg) {
    var logDiv = document.querySelector(".modal .logs_mess");
    if (logDiv.style.display == "none") logDiv.style.display = "block"
    logDiv.innerHTML += Templates.Render("torrents.logs."+type, msg);
  },
  updateProgressBar: function() {
    document.querySelector("#"+this.progress_bar_id).style.display = "block";
    var progress_green = document.querySelector("#"+this.progress_bar_id+" .progress-green");
    var perc = this.progress_count/this.progress_max*100;
    progress_green.style.width=perc+"%";
    progress_green.innerText = this.progress_count+"/"+this.progress_max;
  },
  resetModal: function() {
    var logDiv = document.querySelector(".modal .logs_mess");
    logDiv.style.display = "none";
    document.querySelector("#"+this.progress_bar_id).style.display = "none";
    logDiv.innerHTML = "";
    document.querySelector(".modal .edit_changes").innerHTML = "";
    document.querySelector(".modal .delete_changes").innerHTML = "";
    this.enableApplyChangesBtn();
  },
  statusToClassName: function(status) {
    var className = ["", "normal", "remake", "trusted", "aplus", ""]
    return className[status];
  },

  // Selection Management Methods
  addToSelection: function (torrent) {
    this.selected[torrent.id] = torrent;
  },
  removeFromSelection: function(torrent) {
    delete this.selected[torrent.id];
    for (var t in this.selected) {
      return
    }
    this.selected = [];
  },

  // Query Queue Management Methods
  AddToQueue: function(QueueAction) {
    QueueAction.unique_id = this.getId(); // used for DOM interaction
    this.queued.push(QueueAction);
    this.enableBtnSubmit()
  },
  RemoveFromQueueAfterItems: function(i) {
    for (t in this.queued[i].selection) {
      this.RemoveItemFromQueue(i, t);
    }
  },
  RemoveFromQueue: function(i) {
    this.progress_max = (this.progress_max - 1 >= 0) ? this.progress_max-1 : 0;
    this.RemoveFromQueueAction(i)
    return false;
  },
  RemoveFromQueueAction: function(i) {
    this.removeFromParent(document.getElementById("list_"+this.queued[i].unique_id));
    this.queued.splice(i, 1);
    if (this.queued.length == 0) {
      this.disableBtnSubmit();
      if (this.progress_max>0) {
        this.disableApplyChangesBtn();
      } else {
        Modal.CloseActive();
      }
    }
  },
  formatSelectionToQuery: function(selection) {
    var format = "";
    for (var s in selection) {
      format += "&torrent_id="+selection[s].id
    }
    return (format != "") ? format.substr(1) : ""
  },
  RemoveItemFromQueue: function(i, id) {
    this.removeFromParent(document.getElementById("list_item_"+id));
    delete this.queued[i].selection[id];
    document.getElementById("torrent_cb_"+id).checked=false;
    document.getElementById("torrent_"+id).style.display="";
    var test = 0;
    for (t in this.queued[i].selection) {
      test++
      break;
    }
    if (test == 0) this.RemoveFromQueue(i);
    return false;
  },
  newQueryAttempt: function(queryUrl, queryPost, callback) {
    Query.Post(queryUrl, queryPost, function (response) {
      if ((response.length == 0)||(!response.ok)) { // Query has failed
        var errorMsg = response.errors.join("
");
        TorrentsMod.addToLog("error", errorMsg);
        TorrentsMod.error_count++;
        if (TorrentsMod.error_count < 2) {
          TorrentsMod.addToLog("success", T.r("try_new_attempt"));
          TorrentsMod.newQueryAttempt(queryUrl, queryPost, callback)
        } else {
          TorrentsMod.addToLog("error", T.r("query_is_broken", queryUrl, queryPost));
          if (callback != undefined) {
            TorrentsMod.addToLog("error", "Passing to the next query...");
            callback(response) // So we can query only one item
          }
        }
      } else {
        var succesMsg = (response.infos != null) ? response.infos.join("
") : T.r("query_executed_success");
        TorrentsMod.addToLog("success", succesMsg)
        if (callback != undefined) callback(response) // So we can query only one item
      }
    });
  },
  QueryQueue: function(i, callback) {
    if (this.queued.length > 0) {
      var QueueAction = this.queued[i]; // we clone it so we can delete it safely
      this.RemoveFromQueueAction(i);
      var queryPost = "";
      var queryUrl = "/mod/api/torrents";
      QueueAction.queryPost = TorrentsMod.formatSelectionToQuery(QueueAction.selection)
      if (QueueAction.action == "delete") {
        queryPost="action="+QueueAction.action;
        queryPost+="&withreport="+QueueAction.withReport;
        queryPost += "&status="+((QueueAction.status != undefined) ? QueueAction.status : "");
        queryPost += "&"+QueueAction.queryPost; // we add torrent id
      } else if (QueueAction.action == "edit") {
        queryPost="action=multiple";
        queryPost += "&status="+QueueAction.status;
        queryPost += "&owner="+QueueAction.owner;
        queryPost += "&category="+QueueAction.category;
        queryPost += "&"+QueueAction.queryPost; // we add torrent id
      }
      TorrentsMod.newQueryAttempt(queryUrl, queryPost, callback)
    } else {
      TorrentsMod.addToLog("success", T.r("all_operations_done"))
      if (TorrentsMod.refreshTimeout > 0) {
        TorrentsMod.addToLog("success", T.r("refreshing_in", TorrentsMod.refreshTimeout/1000))
        setTimeout(function(){
          window.location.reload()
        }, TorrentsMod.refreshTimeout);
      }
    }
  },
  QueryLoop: function() {
    if (TorrentsMod.progress_count <= TorrentsMod.progress_max) {
      TorrentsMod.updateProgressBar()
      TorrentsMod.progress_count++;
      if (TorrentsMod.progress_count > TorrentsMod.progress_max) TorrentsMod.progress_count = TorrentsMod.progress_max;
      TorrentsMod.QueryQueue(0, TorrentsMod.QueryLoop);
    }
  },

  // Event Handlers
  checkboxEventHandler: function(e) {
    var el = e.target;
    TorrentsMod.checkboxEventHandlerFunc(el);
  },
  checkboxEventHandlerFunc: function(el) {
    var name = el.dataset.name;
    var id = el.value;
    if (el.checked) TorrentsMod.addToSelection({name:name, id:id});
    else TorrentsMod.removeFromSelection({name:name, id:id});
    if (TorrentsMod.selected.length > 0) TorrentsMod.enableBtnActions();
    else TorrentsMod.disableBtnActions();
  },

  // Action Methods
  DeleteHandler: function(locked) {
    var withReport = confirm(T.r("delete_reports_with_torrents"))
    var selection = TorrentsMod.selected;
    if (locked)
      TorrentsMod.AddToQueue({ action: "delete",
        withReport: withReport,
        selection: selection,
        queryPost: "",
        infos: T.r("with_st", T.r("lock")) + ((withReport) ? T.r("and_reports") : ""),
        status: "5" });
    else TorrentsMod.AddToQueue({
      action: "delete",
      withReport: withReport,
      selection: selection,
      infos: (withReport) ? T.r("with_st", T.r("reports")) : "",
      queryPost: ""});
    for (i in selection) document.getElementById("torrent_"+i).style.display="none";
    TorrentsMod.selected = []
    TorrentsMod.disableBtnActions();
  },
  Delete: function(e) {
    TorrentsMod.DeleteHandler(false);
    e.preventDefault();
  },
  LockDelete: function(e) {
    TorrentsMod.DeleteHandler(true);
    e.preventDefault();
  },
  Edit: function(e) {
    var selection = TorrentsMod.selected;
    var status = document.querySelector(".modtools *[name='"+TorrentsMod.status_input_name+"']").value;
    var owner_id = document.querySelector(".modtools *[name='"+TorrentsMod.owner_input_name+"']").value;
    var category = document.querySelector(".modtools *[name='"+TorrentsMod.category_input_name+"']").value;
    var infos = "";
    infos += (status != "") ? T.r("status_js", status) : "";
    infos += (owner_id != "") ? T.r("owner_id_js", owner_id) : "";
    infos += (category != "") ? T.r("category_js", category) : "";
    TorrentsMod.AddToQueue({
      action: "edit",
      selection: selection,
      queryPost: "", // We don't format now, we wait until the query is sent
      infos: (infos != "" ) ? T.r("with_st", infos) : T.r("no_changes"),
      status: status,
      category: category,
      owner: owner_id });
    if (status != "") {
      for (i in selection) document.getElementById("torrent_"+i).className="torrent-info "+TorrentsMod.statusToClassName(status);
    }
    TorrentsMod.selected = []
    TorrentsMod.disableBtnActions();
    e.preventDefault();
  },
  ApplyChanges: function() {
    this.pause = false;
    this.QueryLoop();
  }
};

    // Load torrentMods when DOM is ready
document.addEventListener("DOMContentLoaded", function() {
  TorrentsMod.checkboxes =  document.querySelectorAll("input[name='torrent_id']");
  TorrentsMod.Create();
});
    // @license-end
<|endoftext|>


<commit_before>'use strict';
page('/', authController.showSignup);
page('/')

page();<commit_msg>Update page.routes.js<commit_after>'use strict';
page('/', authController.showSignup);
page('/');

page();
<|endoftext|>


<commit_before>import $ from 'jquery';
import { config, translations } from 'grav-config';
import formatBytes from '../utils/formatbytes';
import { Instance as gpm } from '../utils/gpm';
import './check';
import './update';

export default class Updates {
    constructor(payload = {}) {
        this.setPayload(payload);
        this.task = `task${config.param_sep}`;
    }

    setPayload(payload = {}) {
        this.payload = payload;

        return this;
    }

    fetch(force = false) {
        gpm.fetch((response) => this.setPayload(response), force);

        return this;
    }

    maintenance(mode = 'hide') {
        let element = $('#updates [data-maintenance-update]');

        element[mode === 'show' ? 'fadeIn' : 'fadeOut']();

        if (mode === 'hide') {
            $('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();
        }

        return this;
    }

    grav() {
        let payload = this.payload.grav;

        if (payload.isUpdatable) {
            let task = this.task;
            let bar = `

            Grav v${payload.available} ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}! (${translations.PLUGIN_ADMIN.CURRENT}v${payload.version})
            `;

            if (!payload.isSymlink) {
                bar += `<button data-maintenance-update="${config.base_url_relative}/update.json/${task}updategrav/admin-nonce${config.param_sep}${config.admin_nonce}" class="button button-small secondary" id="grav-update-button">${translations.PLUGIN_ADMIN.UPDATE_GRAV_NOW}</button>`;
            } else {
                bar += `<span class="hint--left" style="float: right;" data-hint="${translations.PLUGIN_ADMIN.GRAV_SYMBOLICALLY_LINKED}"><i class="fa fa-fw fa-link"></i></span>`;
            }

            $('[data-gpm-grav]').addClass('grav').html(`<p>${bar}</p>`);
        }

        $('#grav-update-button').on('click', function() {
            $(this).html(`${translations.PLUGIN_ADMIN.UPDATING_PLEASE_WAIT} ${formatBytes(payload.assets['grav-update'].size)}..`);
        });

        return this;
    }

    resources() {
        if (!this.payload.resources.total) { return this.maintenance('hide'); }

        let map = ['plugins', 'themes'];
        let singles = ['plugin', 'theme'];
        let task = this.task;
        let { plugins, themes } = this.payload.resources;

        if (!this.payload.resources.total) { return this; }

        [plugins, themes].forEach(function(resources, index) {
            if (!resources || Array.isArray(resources)) { return; }
            let length = Object.keys(resources).length;
            let type = map[index];

            // sidebar
            $(`#admin-menu a[href$="/${map[index]}"]`)
                .find('.badges')
                .addClass('with-updates')
                .find('.badge.updates').text(length);

            // update all
            let title = type.charAt(0).toUpperCase() + type.substr(1).toLowerCase();
            let updateAll = $(`.grav-update.${type}`);
            updateAll.html(`

                ${length} ${translations.PLUGIN_ADMIN.OF_YOUR} ${type} ${translations.PLUGIN_ADMIN.HAVE_AN_UPDATE_AVAILABLE}

                ${translations.PLUGIN_ADMIN.UPDATE} All ${title}

            `);

            Object.keys(resources).forEach(function(item) {
                // listing page
                let element = $(`[data-gpm-${singles[index]}="${item}"] .gpm-name`);
                let url = element.find('a');

                if (type === 'plugins' && !element.find('.badge.update').length) {
                    element.append(`<a class="plugin-update-button" href="${url.attr('href')}"><span class="badge update">${translations.PLUGIN_ADMIN.UPDATE_AVAILABLE}!</span></a>`);
                } else if (type === 'themes') {
                    element.append(`<div class="gpm-ribbon"><a href="${url.attr('href')}">${translations.PLUGIN_ADMIN.UPDATE.toUpperCase()}</a></div>`);
                }

                // details page
                let details = $(`.grav-update.${singles[index]}`);
                if (details.length) {
                    details.html(`

                        v${resources[item].available} ${translations.PLUGIN_ADMIN.OF_THIS} ${singles[index]} ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}!
                        ${translations.PLUGIN_ADMIN.UPDATE} ${singles[index].charAt(0).toUpperCase() + singles[index].substr(1).toLowerCase()}

                    `);
                }
            });
        });
    }
}

let Instance = new Updates();
export { Instance };

// automatically refresh UI for updates (graph, sidebar, plugin/themes pages) after every fetch
gpm.on('fetched', (response, raw) => {
    Instance.setPayload(response.payload || {});
    Instance.grav().resources();
});

if (config.enable_auto_updates_check === '1') {
    gpm.fetch();
}
<commit_msg>Fix linting issue<commit_after>import $ from 'jquery';
import { config, translations } from 'grav-config';
import formatBytes from '../utils/formatbytes';
import { Instance as gpm } from '../utils/gpm';
import './check';
import './update';

export default class Updates {
    constructor(payload = {}) {
        this.setPayload(payload);
        this.task = `task${config.param_sep}`;
    }

    setPayload(payload = {}) {
        this.payload = payload;

        return this;
    }

    fetch(force = false) {
        gpm.fetch((response) => this.setPayload(response), force);

        return this;
    }

    maintenance(mode = 'hide') {
        let element = $('#updates [data-maintenance-update]');

        element[mode === 'show' ? 'fadeIn' : 'fadeOut']();

        if (mode === 'hide') {
            $('.badges.with-updates').removeClass('with-updates').find('.badge.updates').remove();
        }

        return this;
    }

    grav() {
        let payload = this.payload.grav;

        if (payload.isUpdatable) {
            let task = this.task;
            let bar = `

            Grav v${payload.available} ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}! (${translations.PLUGIN_ADMIN.CURRENT}v${payload.version})
            `;

            if (!payload.isSymlink) {
                bar += `<button data-maintenance-update="${config.base_url_relative}/update.json/${task}updategrav/admin-nonce${config.param_sep}${config.admin_nonce}" class="button button-small secondary" id="grav-update-button">${translations.PLUGIN_ADMIN.UPDATE_GRAV_NOW}</button>`;
            } else {
                bar += `<span class="hint--left" style="float: right;" data-hint="${translations.PLUGIN_ADMIN.GRAV_SYMBOLICALLY_LINKED}"><i class="fa fa-fw fa-link"></i></span>`;
            }

            $('[data-gpm-grav]').addClass('grav').html(`<p>${bar}</p>`);
        }

        $('#grav-update-button').on('click', function() {
            $(this).html(`${translations.PLUGIN_ADMIN.UPDATING_PLEASE_WAIT} ${formatBytes(payload.assets['grav-update'].size)}..`);
        });

        return this;
    }

    resources() {
        if (!this.payload.resources.total) { return this.maintenance('hide'); }

        let map = ['plugins', 'themes'];
        let singles = ['plugin', 'theme'];
        let { plugins, themes } = this.payload.resources;

        if (!this.payload.resources.total) { return this; }

        [plugins, themes].forEach(function(resources, index) {
            if (!resources || Array.isArray(resources)) { return; }
            let length = Object.keys(resources).length;
            let type = map[index];

            // sidebar
            $(`#admin-menu a[href$="/${map[index]}"]`)
                .find('.badges')
                .addClass('with-updates')
                .find('.badge.updates').text(length);

            // update all
            let title = type.charAt(0).toUpperCase() + type.substr(1).toLowerCase();
            let updateAll = $(`.grav-update.${type}`);
            updateAll.html(`

                ${length} ${translations.PLUGIN_ADMIN.OF_YOUR} ${type} ${translations.PLUGIN_ADMIN.HAVE_AN_UPDATE_AVAILABLE}

                ${translations.PLUGIN_ADMIN.UPDATE} All ${title}

            `);

            Object.keys(resources).forEach(function(item) {
                // listing page
                let element = $(`[data-gpm-${singles[index]}="${item}"] .gpm-name`);
                let url = element.find('a');

                if (type === 'plugins' && !element.find('.badge.update').length) {
                    element.append(`<a class="plugin-update-button" href="${url.attr('href')}"><span class="badge update">${translations.PLUGIN_ADMIN.UPDATE_AVAILABLE}!</span></a>`);
                } else if (type === 'themes') {
                    element.append(`<div class="gpm-ribbon"><a href="${url.attr('href')}">${translations.PLUGIN_ADMIN.UPDATE.toUpperCase()}</a></div>`);
                }

                // details page
                let details = $(`.grav-update.${singles[index]}`);
                if (details.length) {
                    details.html(`

                        v${resources[item].available} ${translations.PLUGIN_ADMIN.OF_THIS} ${singles[index]} ${translations.PLUGIN_ADMIN.IS_NOW_AVAILABLE}!
                        ${translations.PLUGIN_ADMIN.UPDATE} ${singles[index].charAt(0).toUpperCase() + singles[index].substr(1).toLowerCase()}

                    `);
                }
            });
        });
    }
}

let Instance = new Updates();
export { Instance };

// automatically refresh UI for updates (graph, sidebar, plugin/themes pages) after every fetch
gpm.on('fetched', (response, raw) => {
    Instance.setPayload(response.payload || {});
    Instance.grav().resources();
});

if (config.enable_auto_updates_check === '1') {
    gpm.fetch();
}
<|endoftext|>