<commit_before>/* ========================================================================= */
/*	Preloader
/* ========================================================================= */

jQuery(window).load(function(){

	$("#preloader").fadeOut("slow");

});

jQuery(document).ready(function(){

    $(window).scroll(function () {
        if ($(window).scrollTop() > 150) {
            $("#options").css("background-color","rgb(14, 180, 147)");
        } else {
			$("#options").css("background-color","rgba(13, 96, 80, 0.3)");
        }
    });

	jQuery('.cv').hover(function() {
		jQuery(this).find('.movable-contentFormations').stop().animate({
			left: '620px'
		}, 200);
	}, function() {
		jQuery(this).find('.movable-contentFormations').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery('.cv').hover(function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '300px'
		}, 200);
	}, function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery('.realisations').hover(function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '300px',
		}, 200);
	}, function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery('.stages').hover(function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '300px'
		}, 200);
	}, function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery(window).load(function() {
			jQuery('.infosFormations').css({
			display: 'inline-block',
		});

		jQuery('.infos').css({
			display: 'inline-block',
		});
	/* ========================================================================= */
	/*	Back to Top
	/* ========================================================================= */

    $(window).scroll(function () {
        if ($(window).scrollTop() > 400) {
            $("#back-top").fadeIn(200)
        } else {
            $("#back-top").fadeOut(200)
        }
    });
    $("#back-top").click(function () {
        $("html, body").stop().animate({
            scrollTop: 0
        }, 1500, "easeInOutExpo")
    });

	$("#lAccueil").click(function () {
        $("html, body").stop().animate({
             scrollTop: 700 + 'px'
        }, 1500, "easeInOutExpo")
    });

    $("#leBts").click(function () {
        $("html, body").stop().animate({
            scrollTop: 700 + 'px'
        }, 1500, "easeInOutExpo")
    });

	 $("#leCv").click(function () {
        $("html, body").stop().animate({
            scrollTop: 700 + 'px'
        }, 1500, "easeInOutExpo")
    });

	 $("#leStage").click(function () {
        $("html, body").stop().animate({
            scrollTop: 700  + 'px'
        }, 1500, "easeInOutExpo")
    });

	 $("#laReal").click(function () {
        $("html, body").stop().animate({
			scrollTop: 700 + 'px'
        }, 1500, "easeInOutExpo")
    });
	 $("#laMusique").click(function () {
        $("html, body").stop().animate({
            scrollTop: 700 + 'px'
        }, 1500, "easeInOutExpo")
    });

	/* ========================================================================= */
	/*	Fix Slider Height
	/* ========================================================================= */

	var slideHeight = $(window).height();

	$('#slider, .carousel.slide, .carousel-inner, .carousel-inner .item').css('height',slideHeight);
	$('#owl-demo, .owl-item div, .owl-item img').css('height',slideHeight);

	$(window).resize(function(){'use strict',
		$('#slider, .carousel.slide, .carousel-inner, .carousel-inner .item').css('height',slideHeight);

		$('#owl-demo, .owl-item div, .owl-item img').css('height',slideHeight);
	});

});

	$(".fancybox").fancybox({
		padding: 0,

		openEffect : 'elastic',
		openSpeed  : 650,

		closeEffect : 'elastic',
		closeSpeed  : 550,

		closeClick : true,
	});

	$("#owl-demo").owlCarousel({
	  autoPlay : 3000,
      navigation : true, // Show next and prev buttons
      slideSpeed : 300,
      paginationSpeed : 400,
      singleItem:true

      // "singleItem:true" is a shortcut for:
      // items : 1,
      // itemsDesktop : false,
      // itemsDesktopSmall : false,
      // itemsTablet: false,
      // itemsMobile : false

  });

  //Automatisme du slider

	var options = {

			$AutoPlay: true,
			$DragOrientation: 1
		};

		var jssor_slider1 = new $JssorSlider$("slider1_container", options);

});

<commit_msg>Réglages scroll menu<commit_after>/* ========================================================================= */
/*	Preloader
/* ========================================================================= */

jQuery(window).load(function(){

	$("#preloader").fadeOut("slow");

});

jQuery(document).ready(function(){

    $(window).scroll(function () {
        if ($(window).scrollTop() > 150) {
            $("#options").css("background-color","rgb(14, 180, 147)");
        } else {
			$("#options").css("background-color","rgba(13, 96, 80, 0.3)");
        }
    });

	jQuery('.cv').hover(function() {
		jQuery(this).find('.movable-contentFormations').stop().animate({
			left: '620px'
		}, 200);
	}, function() {
		jQuery(this).find('.movable-contentFormations').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery('.cv').hover(function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '300px'
		}, 200);
	}, function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery('.realisations').hover(function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '300px',
		}, 200);
	}, function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery('.stages').hover(function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '300px'
		}, 200);
	}, function() {
		jQuery(this).find('.movable-content').stop().animate({
			left: '0px'
		}, 200);
	});

	jQuery(window).load(function() {
			jQuery('.infosFormations').css({
			display: 'inline-block',
		});

		jQuery('.infos').css({
			display: 'inline-block',
		});
	/* ========================================================================= */
	/*	Back to Top
	/* ========================================================================= */

    $(window).scroll(function () {
        if ($(window).scrollTop() > 400) {
            $("#back-top").fadeIn(200)
        } else {
            $("#back-top").fadeOut(200)
        }
    });
    $("#back-top").click(function () {
        $("html, body").stop().animate({
            scrollTop: 0
        }, 1500, "easeInOutExpo")
    });

	$("#lAccueil").click(function () {
        $("html, body").stop().animate({
             scrollTop:  $(window).height() - 40 +'px'
        }, 1500, "easeInOutExpo")
    });

    $("#leBts").click(function () {
        $("html, body").stop().animate({
             scrollTop:  $(window).height() - 40 +'px'
        }, 1500, "easeInOutExpo")
    });

	 $("#leCv").click(function () {
        $("html, body").stop().animate({
             scrollTop:  $(window).height() - 40 +'px'
        }, 1500, "easeInOutExpo")
    });

	 $("#leStage").click(function () {
        $("html, body").stop().animate({
             scrollTop:  $(window).height() - 40 +'px'
        }, 1500, "easeInOutExpo")
    });

	 $("#laReal").click(function () {
        $("html, body").stop().animate({
             scrollTop:  $(window).height() - 40 +'px'
        }, 1500, "easeInOutExpo")
    });
	 $("#laMusique").click(function () {
        $("html, body").stop().animate({
             scrollTop:  $(window).height() - 40 +'px'
        }, 1500, "easeInOutExpo")
    });

	/* ========================================================================= */
	/*	Fix Slider Height
	/* ========================================================================= */

	var slideHeight = $(window).height();

	$('#slider, .carousel.slide, .carousel-inner, .carousel-inner .item').css('height',slideHeight);
	$('#owl-demo, .owl-item div, .owl-item img').css('height',slideHeight);

	$(window).resize(function(){'use strict',
		$('#slider, .carousel.slide, .carousel-inner, .carousel-inner .item').css('height',slideHeight);

		$('#owl-demo, .owl-item div, .owl-item img').css('height',slideHeight);
	});

});

	$(".fancybox").fancybox({
		padding: 0,

		openEffect : 'elastic',
		openSpeed  : 650,

		closeEffect : 'elastic',
		closeSpeed  : 550,

		closeClick : true,
	});

	$("#owl-demo").owlCarousel({
	  autoPlay : 3000,
      navigation : true, // Show next and prev buttons
      slideSpeed : 300,
      paginationSpeed : 400,
      singleItem:true

      // "singleItem:true" is a shortcut for:
      // items : 1,
      // itemsDesktop : false,
      // itemsDesktopSmall : false,
      // itemsTablet: false,
      // itemsMobile : false

  });

  //Automatisme du slider

	var options = {

			$AutoPlay: true,
			$DragOrientation: 1
		};

		var jssor_slider1 = new $JssorSlider$("slider1_container", options);

});

<|endoftext|>


<commit_before>let headerIcons = [new icon("desktop","Full Stack Web Developer"),new icon("database","Database Desginer"),new icon("code","Software Engineer")];
let bootstrapColors = [null,"success","info","warning","danger"];
let languages = [
    new language("HTML5", 99),
    new language("Javascript", 90),
    new language("Typescript", 85),
    new language("JQuery", 80),
    new language("SQL", 90),
    new language("Java", 80),
    new language("C#", 99),
    new language("PHP", 80),
    new language("Swift", 20),
    new language("Haskell", 25),
    new language("Visual Basic", 70),
    new language("Python", 50),
    new language("R", 40),
    new language("SCSS", 80)];
let frameworks = [
    new language("Angular JS", 80),
    new language("Classic ASP", 70),
    new language("ASP.NET Web forms", 90),
    new language("Entity Framework", 80),
    new language("Dapper", 80),
    new language("ASP.NET CORE", 80),
    new language("ASP.NET MVC", 90),
    new language("ReactJs", 40),
    new language("Angular 2", 75),
    new language("Laravel", 25)];
let certificates = [
  new certificate("DAT210x: Programming with Python for Data Science", "https://courses.edx.org/certificates/d72c63decab84f2086133a3ef6fa9297"),
  new certificate("DEV218x: Advanced CSS Concepts", "https://courses.edx.org/certificates/7768968d7c40422492be77b204fc4e31"),
  new certificate("DEV273x: Introduction to TypeScript 2","https://courses.edx.org/certificates/6f13094fe578422cb162df9bf6de96ce"),
  new certificate("DAT203.1x: Data Science Essentials","https://courses.edx.org/certificates/647c851f50664505927887b8bf26075d"),
  new certificate("DAT203.2x: Principles of Machine Learning","https://courses.edx.org/certificates/28dd835085594fa78400193155b42de5"),
  new certificate("DAT208x: Introduction to Python for Data Science","https://courses.edx.org/certificates/0df7dc821b9a404e8b4e6020af98afb8"),
  new certificate("AZURE207x: Databases in Azure","https://courses.edx.org/certificates/dfe7bd6fc4f0417ebb2042093d4765be"),
  new certificate("DAT101x: Introduction to Data Science","https://courses.edx.org/certificates/79652a17c9f4426e9d150763887aca93"),
  new certificate("DAT201x: Querying Data with Transact-SQL","https://courses.edx.org/certificates/ea4a300b87d74f7a850e34a19a0d81d4"),
  new certificate("DAT220x: Delivering a Data Warehouse in the Cloud","https://courses.edx.org/certificates/e4d4b93e3eb14d97a27b5b7685df2379"),
  new certificate("DAT221x: Introduction to NoSQL Data Solutions","https://courses.edx.org/certificates/2fa7f175036f40f8a0086362dc653f1d"),
  new certificate("DAT222x: Essential Statistics for Data Analysis using Excel","https://courses.edx.org/certificates/234f191e0ecf468bb77ddd5b4a5eb37e"),
  new certificate("DAT223.1x: Processing Big Data with Azure Data Lake Analytics","https://courses.edx.org/certificates/3738fb11b3794f28bdab759f6461da19"),
  new certificate("DAT223.2x: Processing Real-Time Data Streams in Azure","https://courses.edx.org/certificates/891c813b2f3e41e197697e6fe3e2361a"),
  new certificate("DAT223.3x: Orchestrating Big Data with Azure Data Factory","https://courses.edx.org/certificates/d21766b63cba466a948619eb5c044749"),
  new certificate("DAT228x: Developing Big Data Solutions with Azure Machine Learning","https://courses.edx.org/certificates/136cc2b1101a4ed293c19784948ed3de"),
  new certificate("DAT229x: Microsoft Professional Orientation : Big Data","https://courses.edx.org/certificates/7185c8a6bd994d48aa5a0fd0dd49a24a"),
  new certificate("DAT230x: Microsoft Professional Capstone : Big Data","https://courses.edx.org/certificates/bc53d0e8133244d089609c80fb489457"),
  new certificate("DEV211.1x: Introduction to HTML and JavaScript","https://courses.edx.org/certificates/f8050e146c6a41a6b500cf2964813f80"),
  new certificate("Microsoft Profession Program - Big Data","https://academy.microsoft.com/en-us/certificates/982ef251-ecd1-46a8-85ae-1d3f4cbd80c1/"),
  new certificate("AZURE215x: Microsoft Professional Orientation : Cloud Administration","https://courses.edx.org/certificates/a5dfa83fda374b1d8cef29aaa69530e0"),
  new certificate("CSS.0x: CSS Basics","https://courses.edx.org/certificates/8b4ae9286a954c769df1004aca4a21d3"),
  new certificate("DAT206x: Analyzing and Visualizing Data with Excel","https://courses.edx.org/certificates/bf3ad5a46e894f4d8e1b56091ffa5855"),
  new certificate("DAT211x: Developing Intelligent Apps and Bots","https://courses.edx.org/certificates/c3feecc381734784bf340a7baa5fb136"),
  new certificate("DEV237x: Microsoft Professional Program : Front End Web Development","https://courses.edx.org/certificates/30aca75413a449d3bbc8b99690a086e5"),
  new certificate("PH125.1x: Data Science: R Basics","https://courses.edx.org/certificates/917e67e0fb6b4958b0ba6643b106be6d"),
  new certificate("DEV203x: Introduction to Bootstrap - A Tutorial","https://courses.edx.org/certificates/237296096de244ae8ae791f98d72bead"),
  new certificate("DEV208x: Introduction to jQuery","https://courses.edx.org/certificates/09b2af922eb44c609dbe1e84c4fdc837"),
  new certificate("DEV220x: AngularJS: Framework Fundamentals","https://courses.edx.org/certificates/f6eb597d56c4439999f5cf14fa7914e7"),
  new certificate("DEV221x: AngularJS: Advanced Framework Techniques","https://courses.edx.org/certificates/dc8648b75b9249e28f5611fae154fb14"),
  new certificate("DAT263x: Introduction to Artificial Intelligence (AI)","https://courses.edx.org/certificates/afe640024bfd48af84b2fa5deb5e56f3"),
  new certificate("DAT256x: Essential Mathematics for Artificial Intelligence","https://courses.edx.org/certificates/0ea7810bf5c44d4ebd709209054a88cc")
];
let footerIcons = [
    new icon("envelope","Email","mailto:kylebradshaw18@gmail.com?subject=Website Contact"),
    new icon("phone","Phone","tel:+18452402066"),
    new icon("file-pdf-o","Resume","./Resume.pdf"),
    new icon("linkedin","LinkedIn","https://www.linkedin.com/in/kyle-bradshaw"),
    new icon("github","GitHub","https://github.com/kylebradshaw18"),
    new icon("bitbucket","BitBucket","https://bitbucket.org/kyle_bradshaw1"),
    new icon("facebook","Facebook","https://www.facebook.com/kylebradshaw18"),
    new icon("twitter","Twitter","https://twitter.com/kylebradshaw18"),
    new icon("instagram","Instagram","https://www.instagram.com/kylebradshaw18/?hl=en"),
    new icon("youtube","Youtube","https://www.youtube.com/user/18kylebradshaw")];
$( document ).ready(function() {
  $('#loader').show();
  buildHeaderIcons(headerIcons);
  buildPortfolioInner("Languages", languages);
  buildPortfolioInner("Frameworks", frameworks);
  buildPortfolioInnerCert("Certificates", certificates);
  buildFooterIcons(footerIcons);
  $('#loader').hide();
});
function buildHeaderIcons(items){
  let html = [];
  for(let item of items)
    html.push('

'+item.text+'

');
  $('#HeaderIcons').html(html.join(''));
}
function buildPortfolioInner(name, types){
  let html = [], colorsIndex = 0;
  shuffle(bootstrapColors);
  sortTypes(types);
  for(let index = 0; index < types.length; index++){
    if (index == 0) html.push('
'+name+'
');
    if(index % 2 == 0) html.push('
');
    html.push('

'+types[index].name+'
');
    let progressBarColor = ( bootstrapColors[colorsIndex] != null )? "progress-bar-"+bootstrapColors[colorsIndex]:"";
    html.push('

'+types[index].percent+'%

');
    html.push('

');
    if(index % 2 == 0) html.push('

');
    if(index % 2 != 0 || index == types.length - 1) html.push('
');
    colorsIndex = (colorsIndex < bootstrapColors.length)?colorsIndex + 1:0;
  }
  $('#portfolioInner'+name).html(html.join(''));
}
function buildPortfolioInnerCert(name, types){
  let html = [];
  let MultNumber = ($('#portfolioSort').val() == "NameDesc")?1:-1;
  types.sort(function(a, b) {
    if (a.name  b.name)return -1 * MultNumber;
    return 0;
  });
  for(let index = 0; index < types.length; index++){
    if (index == 0) html.push('
'+name+'
');
    if(index % 2 == 0) html.push('
');
    html.push('

'+types[index].name+'
');
    html.push('

');
    if(index % 2 == 0) html.push('

');
    if(index % 2 != 0 || index == types.length - 1) html.push('
');
  }
  $('#portfolioInner'+name).html(html.join(''));
}
function buildFooterIcons(items){
  let html = [];
  for(let item of items)
    html.push('');
  $('#FooterIcons').html(html.join(''));
}
function sortTypes(types){
  types.sort(function(a, b) {
    switch($('#portfolioSort').val()){
      case "PercentAsc":
        return a.percent - b.percent;
      case "NameAsc":
          if (a.name  b.name)return 1;
          return 0;
      case "NameDesc":
          if (a.name  b.name)return -1;
          return 0;
      default:return b.percent - a.percent;
    }
  });
}
function shuffle(array) {
  let currentIndex = array.length, temporaryValue, randomIndex;
  while (0 !== currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }
}
//Constructors
function language(name, percent){
  this.name = name;
  this.percent = percent;
}
function icon(icon, text, link){
  this.icon = icon;
  this.text = text;
  this.link = (typeof link == undefined || typeof link == null) ? null : link;
}
function certificate(name, url){
  this.name = name;
  this.url = url;
}<commit_msg>New Certificate<commit_after>let headerIcons = [new icon("desktop","Full Stack Web Developer"),new icon("database","Database Desginer"),new icon("code","Software Engineer")];
let bootstrapColors = [null,"success","info","warning","danger"];
let languages = [
    new language("HTML5", 99),
    new language("Javascript", 90),
    new language("Typescript", 85),
    new language("JQuery", 80),
    new language("SQL", 90),
    new language("Java", 80),
    new language("C#", 99),
    new language("PHP", 80),
    new language("Swift", 20),
    new language("Haskell", 25),
    new language("Visual Basic", 70),
    new language("Python", 50),
    new language("R", 40),
    new language("SCSS", 80)];
let frameworks = [
    new language("Angular JS", 80),
    new language("Classic ASP", 70),
    new language("ASP.NET Web forms", 90),
    new language("Entity Framework", 80),
    new language("Dapper", 80),
    new language("ASP.NET CORE", 80),
    new language("ASP.NET MVC", 90),
    new language("ReactJs", 40),
    new language("Angular 2", 75),
    new language("Laravel", 25)];
let certificates = [
  new certificate("DAT210x: Programming with Python for Data Science", "https://courses.edx.org/certificates/d72c63decab84f2086133a3ef6fa9297"),
  new certificate("DEV218x: Advanced CSS Concepts", "https://courses.edx.org/certificates/7768968d7c40422492be77b204fc4e31"),
  new certificate("DEV273x: Introduction to TypeScript 2","https://courses.edx.org/certificates/6f13094fe578422cb162df9bf6de96ce"),
  new certificate("DAT203.1x: Data Science Essentials","https://courses.edx.org/certificates/647c851f50664505927887b8bf26075d"),
  new certificate("DAT203.2x: Principles of Machine Learning","https://courses.edx.org/certificates/28dd835085594fa78400193155b42de5"),
  new certificate("DAT208x: Introduction to Python for Data Science","https://courses.edx.org/certificates/0df7dc821b9a404e8b4e6020af98afb8"),
  new certificate("AZURE207x: Databases in Azure","https://courses.edx.org/certificates/dfe7bd6fc4f0417ebb2042093d4765be"),
  new certificate("DAT101x: Introduction to Data Science","https://courses.edx.org/certificates/79652a17c9f4426e9d150763887aca93"),
  new certificate("DAT201x: Querying Data with Transact-SQL","https://courses.edx.org/certificates/ea4a300b87d74f7a850e34a19a0d81d4"),
  new certificate("DAT220x: Delivering a Data Warehouse in the Cloud","https://courses.edx.org/certificates/e4d4b93e3eb14d97a27b5b7685df2379"),
  new certificate("DAT221x: Introduction to NoSQL Data Solutions","https://courses.edx.org/certificates/2fa7f175036f40f8a0086362dc653f1d"),
  new certificate("DAT222x: Essential Statistics for Data Analysis using Excel","https://courses.edx.org/certificates/234f191e0ecf468bb77ddd5b4a5eb37e"),
  new certificate("DAT223.1x: Processing Big Data with Azure Data Lake Analytics","https://courses.edx.org/certificates/3738fb11b3794f28bdab759f6461da19"),
  new certificate("DAT223.2x: Processing Real-Time Data Streams in Azure","https://courses.edx.org/certificates/891c813b2f3e41e197697e6fe3e2361a"),
  new certificate("DAT223.3x: Orchestrating Big Data with Azure Data Factory","https://courses.edx.org/certificates/d21766b63cba466a948619eb5c044749"),
  new certificate("DAT228x: Developing Big Data Solutions with Azure Machine Learning","https://courses.edx.org/certificates/136cc2b1101a4ed293c19784948ed3de"),
  new certificate("DAT229x: Microsoft Professional Orientation : Big Data","https://courses.edx.org/certificates/7185c8a6bd994d48aa5a0fd0dd49a24a"),
  new certificate("DAT230x: Microsoft Professional Capstone : Big Data","https://courses.edx.org/certificates/bc53d0e8133244d089609c80fb489457"),
  new certificate("DEV211.1x: Introduction to HTML and JavaScript","https://courses.edx.org/certificates/f8050e146c6a41a6b500cf2964813f80"),
  new certificate("Microsoft Profession Program - Big Data","https://academy.microsoft.com/en-us/certificates/982ef251-ecd1-46a8-85ae-1d3f4cbd80c1/"),
  new certificate("AZURE215x: Microsoft Professional Orientation : Cloud Administration","https://courses.edx.org/certificates/a5dfa83fda374b1d8cef29aaa69530e0"),
  new certificate("CSS.0x: CSS Basics","https://courses.edx.org/certificates/8b4ae9286a954c769df1004aca4a21d3"),
  new certificate("DAT206x: Analyzing and Visualizing Data with Excel","https://courses.edx.org/certificates/bf3ad5a46e894f4d8e1b56091ffa5855"),
  new certificate("DAT211x: Developing Intelligent Apps and Bots","https://courses.edx.org/certificates/c3feecc381734784bf340a7baa5fb136"),
  new certificate("DEV237x: Microsoft Professional Program : Front End Web Development","https://courses.edx.org/certificates/30aca75413a449d3bbc8b99690a086e5"),
  new certificate("PH125.1x: Data Science: R Basics","https://courses.edx.org/certificates/917e67e0fb6b4958b0ba6643b106be6d"),
  new certificate("DEV203x: Introduction to Bootstrap - A Tutorial","https://courses.edx.org/certificates/237296096de244ae8ae791f98d72bead"),
  new certificate("DEV208x: Introduction to jQuery","https://courses.edx.org/certificates/09b2af922eb44c609dbe1e84c4fdc837"),
  new certificate("DEV220x: AngularJS: Framework Fundamentals","https://courses.edx.org/certificates/f6eb597d56c4439999f5cf14fa7914e7"),
  new certificate("DEV221x: AngularJS: Advanced Framework Techniques","https://courses.edx.org/certificates/dc8648b75b9249e28f5611fae154fb14"),
  new certificate("DAT263x: Introduction to Artificial Intelligence (AI)","https://courses.edx.org/certificates/afe640024bfd48af84b2fa5deb5e56f3"),
  new certificate("DAT256x: Essential Mathematics for Artificial Intelligence","https://courses.edx.org/certificates/0ea7810bf5c44d4ebd709209054a88cc"),
  new certificate("DAT249x: Ethics and Law in Data and Analytics","https://courses.edx.org/certificates/423f2b9e72104e81bea4e8e3f3199d5d")
];
let footerIcons = [
    new icon("envelope","Email","mailto:kylebradshaw18@gmail.com?subject=Website Contact"),
    new icon("phone","Phone","tel:+18452402066"),
    new icon("file-pdf-o","Resume","./Resume.pdf"),
    new icon("linkedin","LinkedIn","https://www.linkedin.com/in/kyle-bradshaw"),
    new icon("github","GitHub","https://github.com/kylebradshaw18"),
    new icon("bitbucket","BitBucket","https://bitbucket.org/kyle_bradshaw1"),
    new icon("facebook","Facebook","https://www.facebook.com/kylebradshaw18"),
    new icon("twitter","Twitter","https://twitter.com/kylebradshaw18"),
    new icon("instagram","Instagram","https://www.instagram.com/kylebradshaw18/?hl=en"),
    new icon("youtube","Youtube","https://www.youtube.com/user/18kylebradshaw")];
$( document ).ready(function() {
  $('#loader').show();
  buildHeaderIcons(headerIcons);
  buildPortfolioInner("Languages", languages);
  buildPortfolioInner("Frameworks", frameworks);
  buildPortfolioInnerCert("Certificates", certificates);
  buildFooterIcons(footerIcons);
  $('#loader').hide();
});
function buildHeaderIcons(items){
  let html = [];
  for(let item of items)
    html.push('

'+item.text+'

');
  $('#HeaderIcons').html(html.join(''));
}
function buildPortfolioInner(name, types){
  let html = [], colorsIndex = 0;
  shuffle(bootstrapColors);
  sortTypes(types);
  for(let index = 0; index < types.length; index++){
    if (index == 0) html.push('
'+name+'
');
    if(index % 2 == 0) html.push('
');
    html.push('

'+types[index].name+'
');
    let progressBarColor = ( bootstrapColors[colorsIndex] != null )? "progress-bar-"+bootstrapColors[colorsIndex]:"";
    html.push('

'+types[index].percent+'%

');
    html.push('

');
    if(index % 2 == 0) html.push('

');
    if(index % 2 != 0 || index == types.length - 1) html.push('
');
    colorsIndex = (colorsIndex < bootstrapColors.length)?colorsIndex + 1:0;
  }
  $('#portfolioInner'+name).html(html.join(''));
}
function buildPortfolioInnerCert(name, types){
  let html = [];
  let MultNumber = ($('#portfolioSort').val() == "NameDesc")?1:-1;
  types.sort(function(a, b) {
    if (a.name  b.name)return -1 * MultNumber;
    return 0;
  });
  for(let index = 0; index < types.length; index++){
    if (index == 0) html.push('
'+name+'
');
    if(index % 2 == 0) html.push('
');
    html.push('

'+types[index].name+'
');
    html.push('

');
    if(index % 2 == 0) html.push('

');
    if(index % 2 != 0 || index == types.length - 1) html.push('
');
  }
  $('#portfolioInner'+name).html(html.join(''));
}
function buildFooterIcons(items){
  let html = [];
  for(let item of items)
    html.push('');
  $('#FooterIcons').html(html.join(''));
}
function sortTypes(types){
  types.sort(function(a, b) {
    switch($('#portfolioSort').val()){
      case "PercentAsc":
        return a.percent - b.percent;
      case "NameAsc":
          if (a.name  b.name)return 1;
          return 0;
      case "NameDesc":
          if (a.name  b.name)return -1;
          return 0;
      default:return b.percent - a.percent;
    }
  });
}
function shuffle(array) {
  let currentIndex = array.length, temporaryValue, randomIndex;
  while (0 !== currentIndex) {
    randomIndex = Math.floor(Math.random() * currentIndex);
    currentIndex -= 1;
    temporaryValue = array[currentIndex];
    array[currentIndex] = array[randomIndex];
    array[randomIndex] = temporaryValue;
  }
}
//Constructors
function language(name, percent){
  this.name = name;
  this.percent = percent;
}
function icon(icon, text, link){
  this.icon = icon;
  this.text = text;
  this.link = (typeof link == undefined || typeof link == null) ? null : link;
}
function certificate(name, url){
  this.name = name;
  this.url = url;
}<|endoftext|>


<commit_before>(function () {
  'use strict';

  function Dialog () {
    if (!SAM.DialogOverlay) {
      SAM.DialogOverlay = $('<div>')
                .appendTo('body')
                .css({
                  'position': 'fixed',
                  'left': '0px',
                  'width': '100%',
                  'background-color': '#AAA',
                  'opacity': '0.4',
                  'z-index': '10010'})
                .saFullHeight()
                .hide();
    }

    this.Dialog =
            $('<div>')
            .appendTo('body')
            .css({'z-index': '1011'})
            .addClass('sa-view-dialog-div');

    this.Row1 = $('<div>')
            .addClass('sa-view-dialog-title')
            .appendTo(this.Dialog)
            .css({'width': '100%',
              'height': '2.25em',
              'box-sizing': 'border-box'});
    this.Title = $('<div>')
            .appendTo(this.Row1)
            .css({'float': 'left'})
            .addClass('sa-view-dialog-title')
            .text('Title');
    this.CloseButton = $('<div>')
            .appendTo(this.Row1)
            .css({'float': 'right'})
            .addClass('sa-view-dialog-close')
            .text('Close');

    this.Body =
            $('<div>')
            .appendTo(this.Dialog)
            .css({'width': '100%',
              'box-sizing': 'border-box',
              'margin-bottom': '30px'});

    this.ApplyButtonDiv = $('<div>')
            .appendTo(this.Dialog)
            .addClass('sa-view-dialog-apply-div');
    this.ApplyButton = $('<button>')
            .appendTo(this.ApplyButtonDiv)
            .addClass('sa-view-dialog-apply-button')
            .text('Apply');
  }

  Dialog.prototype.SetApplyCallback = function (layer, callback) {
    var self = this;
    // Return true needed to hide the spectrum color picker.
    self.ApplyButton.click(function (e) {
      // hack
      SA.ContentEditableHasFocus = false;
      self.Hide();
      (callback)();
      return true;
    });
  };

  Dialog.prototype.SetCloseCallback = function (layer, callback) {
    var self = this;
    // Return true needed to hide the spectrum color picker.
    this.CloseButton.click(function (e) {
      SA.ContentEditableHasFocus = false;
      self.Hide();
      (callback)();
      return true;
    });
  };

  Dialog.prototype.Show = function (modal) {
        // hack
    SA.ContentEditableHasFocus = true;
    var self = this;
    SAM.DialogOverlay.show();
    this.Dialog.fadeIn(300);

    if (modal) {
      SAM.DialogOverlay.off('click.dialog');
    } else {
      SAM.DialogOverlay.on(
                'click.dialog',
                function (e) { self.Hide(); });
    }
    SAM.ContentEditableHasFocus = true; // blocks viewer events.
  };

  Dialog.prototype.Hide = function () {
    SAM.DialogOverlay.off('click.dialog');
    SAM.DialogOverlay.hide();
    this.Dialog.fadeOut(300);
    SAM.ContentEditableHasFocus = false;
  };

  SAM.Dialog = Dialog;
})();
<commit_msg>Dialog on top and save text arrow state 4<commit_after>(function () {
  'use strict';

  function Dialog () {
    if (!SAM.DialogOverlay) {
      SAM.DialogOverlay = $('<div>')
                .appendTo('body')
                .css({
                  'position': 'fixed',
                  'left': '0px',
                  'width': '100%',
                  'background-color': '#AAA',
                  'opacity': '0.4',
                  'z-index': '10010'})
                .saFullHeight()
                .hide();
    }

    this.Dialog =
            $('<div>')
            .appendTo('body')
            .css({'z-index': '10011'})
            .addClass('sa-view-dialog-div');

    this.Row1 = $('<div>')
            .addClass('sa-view-dialog-title')
            .appendTo(this.Dialog)
            .css({'width': '100%',
              'height': '2.25em',
              'box-sizing': 'border-box'});
    this.Title = $('<div>')
            .appendTo(this.Row1)
            .css({'float': 'left'})
            .addClass('sa-view-dialog-title')
            .text('Title');
    this.CloseButton = $('<div>')
            .appendTo(this.Row1)
            .css({'float': 'right'})
            .addClass('sa-view-dialog-close')
            .text('Close');

    this.Body =
            $('<div>')
            .appendTo(this.Dialog)
            .css({'width': '100%',
              'box-sizing': 'border-box',
              'margin-bottom': '30px'});

    this.ApplyButtonDiv = $('<div>')
            .appendTo(this.Dialog)
            .addClass('sa-view-dialog-apply-div');
    this.ApplyButton = $('<button>')
            .appendTo(this.ApplyButtonDiv)
            .addClass('sa-view-dialog-apply-button')
            .text('Apply');
  }

  Dialog.prototype.SetApplyCallback = function (layer, callback) {
    var self = this;
    // Return true needed to hide the spectrum color picker.
    self.ApplyButton.click(function (e) {
      // hack
      SA.ContentEditableHasFocus = false;
      self.Hide();
      (callback)();
      return true;
    });
  };

  Dialog.prototype.SetCloseCallback = function (layer, callback) {
    var self = this;
    // Return true needed to hide the spectrum color picker.
    this.CloseButton.click(function (e) {
      SA.ContentEditableHasFocus = false;
      self.Hide();
      (callback)();
      return true;
    });
  };

  Dialog.prototype.Show = function (modal) {
        // hack
    SA.ContentEditableHasFocus = true;
    var self = this;
    SAM.DialogOverlay.show();
    this.Dialog.fadeIn(300);

    if (modal) {
      SAM.DialogOverlay.off('click.dialog');
    } else {
      SAM.DialogOverlay.on(
                'click.dialog',
                function (e) { self.Hide(); });
    }
    SAM.ContentEditableHasFocus = true; // blocks viewer events.
  };

  Dialog.prototype.Hide = function () {
    SAM.DialogOverlay.off('click.dialog');
    SAM.DialogOverlay.hide();
    this.Dialog.fadeOut(300);
    SAM.ContentEditableHasFocus = false;
  };

  SAM.Dialog = Dialog;
})();
<|endoftext|>


<commit_before>$("#char-search").on('change keydown paste input', function(){
    search=document.getElementById('char-search').value.toLowerCase()
    if (search == ''){
        chars=document.getElementsByClassName('char_band');
        for (var c =0; c<chars.length; c++){
            chars[c].style.display = 'block'
        }
    }else{
        chars=document.getElementsByClassName('char_band');
        for (var c =0; c<chars.length; c++){
            if (chars[c].childNodes[0].innerHTML.toLowerCase().match(search)==null){
                chars[c].style.display = 'none'
            }else{
                chars[c].style.display = 'block'
            }
        }
    }

})

function submit(){
    obj = getSessionObject()
    donation = obj['allocationAmounts']
    charities = Object.keys(donation).sort()
    modal_msg = document.getElementById('donation_summary')
    sub_list = document.createElement('ul')
    sub_list.style.listStyleType= 'none'
    total = document.createElement('li')
    total.innerHTML = "TOTAL DONATION: $" + obj['totalFunds']
    sub_list.appendChild(total)
    for (var i=0; i<charities.length; i++){
        ul = document.createElement('li')
        ul.innerHTML = charities[i] + ": $" + donation[charities[i]]*60/100.0
        sub_list.appendChild(ul)
    }
    modal_msg.appendChild(sub_list)

    var modal = document.getElementById("submitModal");
    modal.style.display = "block";

  var modalCloseButton = document.getElementById("subCloseButton");
  modalCloseButton.onclick = function(){
    modal.style.display = "none";
    obj = getSessionObject()
    obj['allocationAmounts'] = {}
    obj['percentAllocated'] = 0
    setSessionObject(obj)
  };

  // Click anywhere outside of modal causes it to close
  window.onclick = function(event){
    if (event.target == modal){
      modal.style.display = "none";
      obj = getSessionObject()
      obj['allocationAmounts'] = {}
      obj['percentAllocated'] = 0
      setSessionObject(obj)
      window.location.href = "./index.html";
    }
  }
}

function makeCharList(my_charities) {
    // Create the list element:
    charities = Object.keys(my_charities).sort()

    list_header = document.createTextNode('My Charities (' + charities.length + ')')
    document.getElementById('My_Charities').appendChild(list_header)

    var list = document.createElement('div');
    document.getElementById('charity_list').appendChild(list);

    var char_num_chars = document.createElement('span');
    char_num_chars.className ='num_chars'
    var no_char_msg = document.createTextNode('You Have Not Selected Any Charities Yet');
    char_num_chars.appendChild(no_char_msg);
    if (charities.length == 0){
        char_num_chars.style.display = 'block'
    }else{
        char_num_chars.style.display = 'none'
    }
    list.appendChild(char_num_chars);

    for(var i = 0; i < charities.length; i++) {
        // Create the list item:
        var char_band = document.createElement('div');
        char_band.className = "char_band";
        list.appendChild(char_band);
        var char_content_name = document.createElement('span');
        char_content_name.className ='char_name';
        var char_name = document.createTextNode(charities[i]);
        char_content_name.appendChild(char_name);
        char_band.appendChild(char_content_name);

        var slider = document.createElement('div')
        slider.className="sliders"
        slider.setAttribute('id', 'slider_'+i)
        char_band.appendChild(slider);

       $('#slider_'+i).slider({
            step: 1,
            min: 0,
            max: 100,
            value: my_charities[char_name],
            slide: function( event, ui ) {
                var amount = ui.value;
                char_name = this.parentNode.childNodes[0].innerHTML
                //total_alloc = 100 - total_alloc - my_charities[char_name]
                my_charities[char_name] = amount
                money = 100 - Object.values(my_charities).reduce(function(a,b){return a+b;},0)
                obj_slide = getSessionObject()
                if (money < 0){
                    char_error.style.visibility = 'visible'
                    my_charities[char_name] += money;
                    obj_slide['allocationAmounts'] = my_charities;
                    obj_slide['percentAllocated'] = 100;
                    setSessionObject(obj_slide);
                    this.parentNode.childNodes[2].innerHTML = my_charities[char_name]+'%';
                    $('#'+this.getAttribute('id')).slider('value', my_charities[char_name]);
                    prog_bar = document.getElementsByClassName('progress-bar')[0]
                    prog_bar.setAttribute('aria-valuenow', obj_slide['percentAllocated'])
                    prog_bar.setAttribute('style', "width:"+obj_slide['percentAllocated']+"%")
                    prog_bar.innerHTML = obj_slide['percentAllocated']+'%'
                    return false;
                }else{
                    char_error.style.visibility = 'hidden'
                    my_charities[char_name] = amount
                    obj_slide['allocationAmounts'] = my_charities;
                    obj_slide['percentAllocated'] = Object.values(my_charities).reduce(function(a,b){return a+b;},0);
                    setSessionObject(obj_slide);
                    this.parentNode.childNodes[2].innerHTML = amount+'%';
                    prog_bar = document.getElementsByClassName('progress-bar')[0]
                    prog_bar.setAttribute('aria-valuenow', obj_slide['percentAllocated'])
                    prog_bar.setAttribute('style', "width:"+obj_slide['percentAllocated']+"%")
                    prog_bar.innerHTML = obj_slide['percentAllocated']+'%'
                }
                update_pie(char_name, my_charities[char_name])
                //document.getElementById('fund').innerHTML = '$'+(obj_slide['percentAllocated']/100.0*obj_slide['totalFunds'])+'/$'+obj_slide['totalFunds']+' allocated'
                $("#"+this.getAttribute('id') +" .ui-slider-range").css( "background-color", '#C43E00' );

                $( "#"+this.getAttribute('id') +" .ui-state-default, .ui-widget-content .ui-state-default" ).css( "background-color", '#C43E00' );
            }
        });

        var char_content_value = document.createElement('span');
        char_content_value.className ='alloc_val'
        var char_value = document.createTextNode(my_charities[charities[i]]+'%');
        char_content_value.appendChild(char_value);
        char_band.appendChild(char_content_value);

        //creates trash can remove buttons
        var button = document.createElement("button");
        button.setAttribute('class', 'trash');
        var trash = document.createElement("span");
        trash.setAttribute('class', 'glyphicon glyphicon-trash');
        button.appendChild(trash)
        button.onclick = function(){
            obj_del = getSessionObject()
            obj_del['percentAllocated'] -= my_charities[this.parentNode.childNodes[0].childNodes[0].nodeValue]
            setSessionObject(obj_del);
            update_pie(this.parentNode.childNodes[0].childNodes[0].nodeValue, 0);
            delete my_charities[this.parentNode.childNodes[0].childNodes[0].nodeValue]
            obj_del['allocationAmounts'] = my_charities;
            this.parentNode.parentNode.removeChild(this.parentNode);
            document.getElementById("My_Charities").childNodes[0].nodeValue = 'My Charities (' + Object.keys(my_charities).length + ')'
            total_alloc = Object.values(my_charities).reduce(function(a,b){return a+b;},0);

            prog_bar = document.getElementsByClassName('progress-bar')[0]
            prog_bar.setAttribute('aria-valuenow', total_alloc)
            prog_bar.setAttribute('style', "width:"+total_alloc+"%")
            prog_bar.innerHTML = total_alloc+'%'
        }
        char_band.appendChild(button);

        // Add it to the list:
        //list.appendChild(char_band);
    }
    var char_error = document.createElement('span');
    char_error.className ='error_msg'
    var msg = document.createTextNode('Donation Budget Reached - Please Reduce One Or More Donations to Continue');
    char_error.appendChild(msg);
    char_error.style.visibility = 'hidden'
    char_error.style.color= '#C43E00'
    list.appendChild(char_error);

    // Finally, return the constructed list:
    return list;
}
<commit_msg>removing donate hardcode<commit_after>$("#char-search").on('change keydown paste input', function(){
    search=document.getElementById('char-search').value.toLowerCase()
    if (search == ''){
        chars=document.getElementsByClassName('char_band');
        for (var c =0; c<chars.length; c++){
            chars[c].style.display = 'block'
        }
    }else{
        chars=document.getElementsByClassName('char_band');
        for (var c =0; c<chars.length; c++){
            if (chars[c].childNodes[0].innerHTML.toLowerCase().match(search)==null){
                chars[c].style.display = 'none'
            }else{
                chars[c].style.display = 'block'
            }
        }
    }

})

function submit(){
    obj = getSessionObject()
    donation = obj['allocationAmounts']
    charities = Object.keys(donation).sort()
    modal_msg = document.getElementById('donation_summary')
    sub_list = document.createElement('ul')
    sub_list.style.listStyleType= 'none'
    total = document.createElement('li')
    total.innerHTML = "TOTAL DONATION: $" + obj['totalFunds']
    sub_list.appendChild(total)
    for (var i=0; i<charities.length; i++){
        ul = document.createElement('li')
        ul.innerHTML = charities[i] + ": $" + donation[charities[i]]*60/100.0
        sub_list.appendChild(ul)
    }
    modal_msg.appendChild(sub_list)

    var modal = document.getElementById("submitModal");
    modal.style.display = "block";

  var modalCloseButton = document.getElementById("subCloseButton");
  modalCloseButton.onclick = function(){
    modal.style.display = "none";
    obj = getSessionObject()
    obj['allocationAmounts'] = {}
    obj['percentAllocated'] = 0
    setSessionObject(obj)
  };

  // Click anywhere outside of modal causes it to close
  window.onclick = function(event){
    if (event.target == modal){
      modal.style.display = "none";
      obj = getSessionObject()
      obj['allocationAmounts'] = {}
      obj['percentAllocated'] = 0
      setSessionObject(obj)
      window.location.href = "./index.html";
    }
  }
}

function makeCharList(my_charities) {
    // Create the list element:
    console.log(my_charities)
    charities = Object.keys(my_charities).sort()

    list_header = document.createTextNode('My Charities (' + charities.length + ')')
    document.getElementById('My_Charities').appendChild(list_header)

    var list = document.createElement('div');
    document.getElementById('charity_list').appendChild(list);

    var char_num_chars = document.createElement('span');
    char_num_chars.className ='num_chars'
    var no_char_msg = document.createTextNode('You Have Not Selected Any Charities Yet');
    char_num_chars.appendChild(no_char_msg);
    if (charities.length == 0){
        char_num_chars.style.display = 'block'
    }else{
        char_num_chars.style.display = 'none'
    }
    list.appendChild(char_num_chars);

    for(var i = 0; i < charities.length; i++) {
        // Create the list item:
        var char_band = document.createElement('div');
        char_band.className = "char_band";
        list.appendChild(char_band);
        var char_content_name = document.createElement('span');
        char_content_name.className ='char_name';
        var char_name = document.createTextNode(charities[i]);
        char_content_name.appendChild(char_name);
        char_band.appendChild(char_content_name);

        var slider = document.createElement('div')
        slider.className="sliders"
        slider.setAttribute('id', 'slider_'+i)
        char_band.appendChild(slider);

       $('#slider_'+i).slider({
            step: 1,
            min: 0,
            max: 100,
            value: my_charities[char_name],
            slide: function( event, ui ) {
                var amount = ui.value;
                char_name = this.parentNode.childNodes[0].innerHTML
                //total_alloc = 100 - total_alloc - my_charities[char_name]
                my_charities[char_name] = amount
                money = 100 - Object.values(my_charities).reduce(function(a,b){return a+b;},0)
                obj_slide = getSessionObject()
                if (money < 0){
                    char_error.style.visibility = 'visible'
                    my_charities[char_name] += money;
                    obj_slide['allocationAmounts'] = my_charities;
                    obj_slide['percentAllocated'] = 100;
                    setSessionObject(obj_slide);
                    this.parentNode.childNodes[2].innerHTML = my_charities[char_name]+'%';
                    $('#'+this.getAttribute('id')).slider('value', my_charities[char_name]);
                    prog_bar = document.getElementsByClassName('progress-bar')[0]
                    prog_bar.setAttribute('aria-valuenow', obj_slide['percentAllocated'])
                    prog_bar.setAttribute('style', "width:"+obj_slide['percentAllocated']+"%")
                    prog_bar.innerHTML = obj_slide['percentAllocated']+'%'
                    return false;
                }else{
                    char_error.style.visibility = 'hidden'
                    my_charities[char_name] = amount
                    obj_slide['allocationAmounts'] = my_charities;
                    obj_slide['percentAllocated'] = Object.values(my_charities).reduce(function(a,b){return a+b;},0);
                    setSessionObject(obj_slide);
                    this.parentNode.childNodes[2].innerHTML = amount+'%';
                    prog_bar = document.getElementsByClassName('progress-bar')[0]
                    prog_bar.setAttribute('aria-valuenow', obj_slide['percentAllocated'])
                    prog_bar.setAttribute('style', "width:"+obj_slide['percentAllocated']+"%")
                    prog_bar.innerHTML = obj_slide['percentAllocated']+'%'
                }
                update_pie(char_name, my_charities[char_name])
                //document.getElementById('fund').innerHTML = '$'+(obj_slide['percentAllocated']/100.0*obj_slide['totalFunds'])+'/$'+obj_slide['totalFunds']+' allocated'
                $("#"+this.getAttribute('id') +" .ui-slider-range").css( "background-color", '#C43E00' );

                $( "#"+this.getAttribute('id') +" .ui-state-default, .ui-widget-content .ui-state-default" ).css( "background-color", '#C43E00' );
            }
        });

        var char_content_value = document.createElement('span');
        char_content_value.className ='alloc_val'
        var char_value = document.createTextNode(my_charities[charities[i]]+'%');
        char_content_value.appendChild(char_value);
        char_band.appendChild(char_content_value);

        //creates trash can remove buttons
        var button = document.createElement("button");
        button.setAttribute('class', 'trash');
        var trash = document.createElement("span");
        trash.setAttribute('class', 'glyphicon glyphicon-trash');
        button.appendChild(trash)
        button.onclick = function(){
            obj_del = getSessionObject()
            obj_del['percentAllocated'] -= my_charities[this.parentNode.childNodes[0].childNodes[0].nodeValue]
            setSessionObject(obj_del);
            update_pie(this.parentNode.childNodes[0].childNodes[0].nodeValue, 0);
            delete my_charities[this.parentNode.childNodes[0].childNodes[0].nodeValue]
            obj_del['allocationAmounts'] = my_charities;
            this.parentNode.parentNode.removeChild(this.parentNode);
            document.getElementById("My_Charities").childNodes[0].nodeValue = 'My Charities (' + Object.keys(my_charities).length + ')'
            total_alloc = Object.values(my_charities).reduce(function(a,b){return a+b;},0);

            prog_bar = document.getElementsByClassName('progress-bar')[0]
            prog_bar.setAttribute('aria-valuenow', total_alloc)
            prog_bar.setAttribute('style', "width:"+total_alloc+"%")
            prog_bar.innerHTML = total_alloc+'%'
        }
        char_band.appendChild(button);

        // Add it to the list:
        //list.appendChild(char_band);
    }
    var char_error = document.createElement('span');
    char_error.className ='error_msg'
    var msg = document.createTextNode('Donation Budget Reached - Please Reduce One Or More Donations to Continue');
    char_error.appendChild(msg);
    char_error.style.visibility = 'hidden'
    char_error.style.color= '#C43E00'
    list.appendChild(char_error);

    // Finally, return the constructed list:
    return list;
}
<|endoftext|>


<commit_before>define(['underscore','jquery','events','codemirror','alto','mybackbone','cmmode', 'dialog'],
    function (_,$,events,CodeMirror,alto,mybackbone, dialog) {
    "use strict";

    var View = mybackbone.View.extend({

        initialize: function () {
            var re = new RegExp("[0-9a-f]{32}");
            var uidarr = re.exec(document.URL);
            var uid = uidarr[0]
            var options = {
                type:'GET',
                url: "/api/id/"+uid+"/ping",
                statusCode: {
                    401: function() {events.trigger("saveFailed401", 'pinging the backend')},
                    403: function() {events.trigger("saveFailed", 'Forbidden')},
                }
            };
            var readonly = false;
            $.ajax(options)
                .done(function(data){
                    console.log(data)
                    if(data.code == 13){
                        readonly = true;
                    }
                    view.render("ping");
                    console.log(readonly)
                    this.cmConfig = {
                        value: "",
                        lineWrapping: true,
                        mode: 'ocrui',
                        changedSince0Sequence: [],
                        changedSinceSaveSequence: [],
                        languageSequence: [],
                        tagSequence: [],
                        highlight: {},
                        readOnly: readonly
                    };
                    this.cMirror = new CodeMirror(this.$el.get(0), this.cmConfig);
                });
            var self = this;
            this.cmConfig = {
                value: "",
                lineWrapping: true,
                mode: 'ocrui',
                changedSince0Sequence: [],
                changedSinceSaveSequence: [],
                languageSequence: [],
                tagSequence: [],
                highlight: {},
                readOnly: readonly
            };
            this.cMirror = new CodeMirror(this.$el.get(0), this.cmConfig);

            // suppress default codemirror bindings
            CodeMirror.commands.goPageUp = function () { };
            CodeMirror.commands.goPageDown = function () { };

            this.cMirror.on('cursorActivity',function () {
                events.delayOrIgnore('setupHighlightChange',undefined,100);
            });
            this.cMirror.on('change',function (instance) {
                if (self.suppressChanged) return ;
                self.changed(instance);
            });

            self.cMirror.setOption('highlight',{17: true});

        },
        el: '#editor',
        myEvents: {
            'virtualKeyboard':'virtualKeyboard',
            'cursorToCoordinate': 'cursorToCoordinate',
            'refocus':'refocus',
            'changePage':'changePage',
            'changeMode':'changeMode',
            'requestLanguageChange':'requestLanguageChange',
            'setupHighlightChange':'setupHighlightChange',
            'pageDirtyStateChanged':'pageDirtyStateChanged',
            'showLanguage':'showLanguage',
            'showTag': 'showTag',
            'showOriginalChanges':'showOriginalChanges',
            'showSavedChanges':'showSavedChanges',
            'highlightEditorWord':'highlightEditorWord',
            'toggleLineBreak':'toggleLineBreak',
            'altoRefreshed':'altoRefreshed',
            'tagWord': 'tagWord',
            'tagTheWord': 'tagTheWord'
        },
        events: {
            'mouseover .cm-tag': 'mouseoverTag',
            'mouseout .cm-tag': 'mouseoutTag'
        },
        myModes: ['page'],
        altoRefreshed:function(alto) {

            // happens after save
            if (alto.get('pageNumber') == this.attributes.pageNumber) {

                this.setAlto(alto);

            }

        },
        setCMOption:function(opt,val) {
            this.cMirror.setOption(opt,val);
            this.refreshCM();
        },
        refreshCM:function() {

            // No idea what is the proper way, but these three lines together
            // seem to make it work always
            this.cMirror.doc.frontier = this.cMirror.doc.first;
            this.cMirror.setOption('mode',this.cmConfig.mode);
            this.cMirror.replaceSelection(this.cMirror.getSelection());

        },
        mouseoverTag:function(event){
            console.log(event.currentTarget.innerHTML)

            //For some reason for each doesn't work here
            //Loop through the words on a page and show a tooltip when a tagged word is hovered over
            var tagIndex = 0;
            for(var i = 0; i < this.alto.editorWords.length; i++){
                if(this.alto.editorWords[i].content == $.trim(event.currentTarget.innerHTML)){
                    tagIndex = i;
                    break;
                }
            }

            var offset = $(event.currentTarget).offset();

            $("#tagtcontainer").css({'top':offset.top-23,'left':offset.left+25});
            $("#tagt").html("
Tag: "+this.alto.getTagSequence()[tagIndex]+"
");
            $("#tagt").fadeIn(200);

        },
        mouseoutTag:function(event){
            $("#tagt").fadeOut(100);
        },
        toggleLineBreak:function(newState) {

            this.lineBreaks = newState;
            this.setCMOption('lineWrapping', newState ? false : true);
            this.setValueFromAlto();

        },
        highlightEditorWord:function(newState) {
            this.setCMOption('showHighlight',newState);
        },
        showSavedChanges:function(newState) {
            this.setCMOption('showUnsavedChanges',newState);
        },
        showOriginalChanges:function(newState) {
            this.setCMOption('showOriginalChanges',newState);
        },
        showLanguage:function(newState) {
            this.setCMOption('showLanguage',newState);
        },
        showTag:function(newState) {
            this.setCMOption('showTag',newState);
        },
        virtualKeyboard: function(data) {
            this.cMirror.replaceSelection(data);
            this.cMirror.focus();
            var cursor = this.cMirror.getCursor();
            this.cMirror.setCursor(cursor);
        },
        requestLanguageChange: function(selected) {
            var wordIndexes = this.getCurrentWordIndexes();
            for (var wordIndexIndex in wordIndexes) {
                var i = wordIndexes[wordIndexIndex];
                this.alto.setNthWordLanguage(i,selected);
            }
            this.alto.changedSinceSave = true;
            this.cMirror.focus();
        },
        tagWord: function(ev){
            var wordIndexes = this.getCurrentWordIndexes();
            var i = 0;
            for (var wordIndexIndex in wordIndexes) {
                i = wordIndexes[wordIndexIndex];
            }
            events.trigger('showTagDialog', i);
        },
        tagTheWord: function(tagArray){
            console.log(tagArray.index + " " + tagArray.tag);
            this.alto.setNthWordTag(tagArray.index, tagArray.tag);
            this.alto.changedSinceSave = true;
            events.trigger("saveDocument");
            this.cMirror.focus();
        },
        refocus: function(ev) {
            this.cMirror.focus();
        },
        cursorToCoordinate: function(coords) {
            var content = this.cMirror.getValue();
            var line = 0;
            var ch = 0;
            var anchor,head;
            var betweenWords = false;
            if (!this.alto) { return; }
            var word = this.alto.getWordAt(coords.x,coords.y);
            if (word === undefined) {return;}
            var wordIndex = word.index;
            var wordLength = word.content.length;
            for (var i in content) {
                var c = content[i];
                if (c == '\n') {
                    line ++;
                    ch = -1;
                }
                if (c.match(/\s/)) {
                    betweenWords = true;
                } else {
                    if (betweenWords) wordIndex --;
                    if (wordIndex === 0) {
                        if (anchor === undefined) {
                            anchor = {
                                line: line,
                                ch: ch
                            }
                        }
                        head = {
                            line: line,
                            ch: ch + 1
                        }
                        wordLength --;
                        if (wordLength == 0) {
                            break;
                        }
                    }
                    betweenWords = false;
                }
                ch ++;
            }
            this.cMirror.setSelection(anchor,head);
            this.cMirror.focus();
        },
        configureCMMode: function () {
            this.cmConfig.changedSinceSaveSequence =
                this.alto.getChangedSinceSaveSequence();
            this.cmConfig.changedSince0Sequence
                = this.alto.getChangedSince0Sequence();
            this.cmConfig.languageSequence = this.alto.getLanguageSequence();
            this.cmConfig.tagSequence = this.alto.getTagSequence();
        },
        changed: function (instance) {
            var content = instance.getValue();

            if (!this.alto) return;

            this.alto.updateStringsContent(content.split(/\s+/));
            this.configureCMMode();
            this.setupHighlightChange();
        },
        getCurrentWordIndexes: function () {
            var wordIndexes = {};
            var wordIndex = -1; // in between words before first word...
            var content = this.cMirror.getValue();
            var start = this.cMirror.getCursor('start');
            var end = this.cMirror.getCursor('end');
            var s_line = start.line;
            var s_ch = start.ch;
            var e_line = end.line;
            var e_ch = end.ch;
            var betweenWords = true;
            var stillBetweenWords = false;

            for (var i in content) {

                var c = content[i];

                if (c.match(/\s/)) {

                    if (betweenWords) stillBetweenWords = true;
                    betweenWords = true;

                } else {

                    if (betweenWords) wordIndex ++;
                    betweenWords = false;
                    stillBetweenWords = false;

                }

                if (s_line <= 0) {
                    s_ch --;
                    if ((s_ch < 0) && (!stillBetweenWords)) {
                        wordIndexes[wordIndex] = true;
                    }
                }

                if (e_line <=0) {
                    e_ch --;
                    if (e_ch < 0) break;
                }

                if (c == '\n') {
                    s_line --;
                    e_line --;
                }
            }

            this.words = wordIndexes;
            var wordIndexArray = _.map(wordIndexes,function (v,k) {
                return parseInt(k,10);
            });
            return wordIndexArray;
        },
        setupHighlightChange: function () {

            var wordIndexes = this.getCurrentWordIndexes();
            var self = this;
            console.log(wordIndexes);
            var words = _.map(wordIndexes,function (v,k) {

                return self.alto.getNthWord(v);

            });

            self.cMirror.setOption('highlight',this.words);
            this.suppressChanged = true;
            this.cMirror.doc.frontier = this.cMirror.doc.first;
            this.cMirror.replaceSelection(this.cMirror.getSelection());
            this.suppressChanged = false;

            events.trigger('changeCoordinates',words);

        },
        changePage: function(attributes) {
            var self = this;
            this.attributes = attributes;
            alto.get(attributes).then(
                function(myAlto) {
                    /* if (this.attributes != attributes) return;*/
                    self.setAlto(myAlto);
                },
                function(msg) {
                    events.trigger('editorRenderError',{
                        error: 'editorRenderError',
                        message: msg
                    });
                }
            );
        },
        pageDirtyStateChanged: function() {
            if(this.alto.isDirty()) {
                this.$el.addClass('dirty');
            } else {
                this.$el.removeClass('dirty');
            }
        },
        setValueFromAlto: function(alto) {
            if (this.alto === undefined) {
                this.cMirror.setValue("");
            } else {
                var s = this.alto.getString(this.lineBreaks);
                this.cMirror.setValue(s);
            }
        },
        setAlto: function(alto) {
            this.alto = alto;
            this.setValueFromAlto();
            this.cMirror.clearHistory();
            var word = this.alto.getNthWord(0);
            this.cMirror.focus();
            events.trigger('editorRendered',this.attributes);
        },
        render: function() {
            return;     // Nothing to do, CodeMirror renders itself
        }
    });

    return {
        view: new View()
    };

});
<commit_msg>read only mode<commit_after>define(['underscore','jquery','events','codemirror','alto','mybackbone','cmmode', 'dialog'],
    function (_,$,events,CodeMirror,alto,mybackbone, dialog) {
    "use strict";

    var View = mybackbone.View.extend({

        initialize: function () {
            var re = new RegExp("[0-9a-f]{32}");
            var uidarr = re.exec(document.URL);
            var uid = uidarr[0]
            var options = {
                type:'GET',
                url: "/api/id/"+uid+"/ping",
                statusCode: {
                    401: function() {events.trigger("saveFailed401", 'pinging the backend')},
                    403: function() {events.trigger("saveFailed", 'Forbidden')},
                }
            };
            var readonly = false;
            $.ajax(options)
                .done(function(data){
                    console.log(data)
                    if(data.code == 13){
                        readonly = true;
                    }
                    console.log(readonly)
                    this.cmConfig = {
                        value: "",
                        lineWrapping: true,
                        mode: 'ocrui',
                        changedSince0Sequence: [],
                        changedSinceSaveSequence: [],
                        languageSequence: [],
                        tagSequence: [],
                        highlight: {},
                        readOnly: readonly
                    };
                    this.cMirror = new CodeMirror(this.$el.get(0), this.cmConfig);
                });
            var self = this;
            this.cmConfig = {
                value: "",
                lineWrapping: true,
                mode: 'ocrui',
                changedSince0Sequence: [],
                changedSinceSaveSequence: [],
                languageSequence: [],
                tagSequence: [],
                highlight: {},
                readOnly: readonly
            };
            this.cMirror = new CodeMirror(this.$el.get(0), this.cmConfig);

            // suppress default codemirror bindings
            CodeMirror.commands.goPageUp = function () { };
            CodeMirror.commands.goPageDown = function () { };

            this.cMirror.on('cursorActivity',function () {
                events.delayOrIgnore('setupHighlightChange',undefined,100);
            });
            this.cMirror.on('change',function (instance) {
                if (self.suppressChanged) return ;
                self.changed(instance);
            });

            self.cMirror.setOption('highlight',{17: true});

        },
        el: '#editor',
        myEvents: {
            'virtualKeyboard':'virtualKeyboard',
            'cursorToCoordinate': 'cursorToCoordinate',
            'refocus':'refocus',
            'changePage':'changePage',
            'changeMode':'changeMode',
            'requestLanguageChange':'requestLanguageChange',
            'setupHighlightChange':'setupHighlightChange',
            'pageDirtyStateChanged':'pageDirtyStateChanged',
            'showLanguage':'showLanguage',
            'showTag': 'showTag',
            'showOriginalChanges':'showOriginalChanges',
            'showSavedChanges':'showSavedChanges',
            'highlightEditorWord':'highlightEditorWord',
            'toggleLineBreak':'toggleLineBreak',
            'altoRefreshed':'altoRefreshed',
            'tagWord': 'tagWord',
            'tagTheWord': 'tagTheWord'
        },
        events: {
            'mouseover .cm-tag': 'mouseoverTag',
            'mouseout .cm-tag': 'mouseoutTag'
        },
        myModes: ['page'],
        altoRefreshed:function(alto) {

            // happens after save
            if (alto.get('pageNumber') == this.attributes.pageNumber) {

                this.setAlto(alto);

            }

        },
        setCMOption:function(opt,val) {
            this.cMirror.setOption(opt,val);
            this.refreshCM();
        },
        refreshCM:function() {

            // No idea what is the proper way, but these three lines together
            // seem to make it work always
            this.cMirror.doc.frontier = this.cMirror.doc.first;
            this.cMirror.setOption('mode',this.cmConfig.mode);
            this.cMirror.replaceSelection(this.cMirror.getSelection());

        },
        mouseoverTag:function(event){
            console.log(event.currentTarget.innerHTML)

            //For some reason for each doesn't work here
            //Loop through the words on a page and show a tooltip when a tagged word is hovered over
            var tagIndex = 0;
            for(var i = 0; i < this.alto.editorWords.length; i++){
                if(this.alto.editorWords[i].content == $.trim(event.currentTarget.innerHTML)){
                    tagIndex = i;
                    break;
                }
            }

            var offset = $(event.currentTarget).offset();

            $("#tagtcontainer").css({'top':offset.top-23,'left':offset.left+25});
            $("#tagt").html("
Tag: "+this.alto.getTagSequence()[tagIndex]+"
");
            $("#tagt").fadeIn(200);

        },
        mouseoutTag:function(event){
            $("#tagt").fadeOut(100);
        },
        toggleLineBreak:function(newState) {

            this.lineBreaks = newState;
            this.setCMOption('lineWrapping', newState ? false : true);
            this.setValueFromAlto();

        },
        highlightEditorWord:function(newState) {
            this.setCMOption('showHighlight',newState);
        },
        showSavedChanges:function(newState) {
            this.setCMOption('showUnsavedChanges',newState);
        },
        showOriginalChanges:function(newState) {
            this.setCMOption('showOriginalChanges',newState);
        },
        showLanguage:function(newState) {
            this.setCMOption('showLanguage',newState);
        },
        showTag:function(newState) {
            this.setCMOption('showTag',newState);
        },
        virtualKeyboard: function(data) {
            this.cMirror.replaceSelection(data);
            this.cMirror.focus();
            var cursor = this.cMirror.getCursor();
            this.cMirror.setCursor(cursor);
        },
        requestLanguageChange: function(selected) {
            var wordIndexes = this.getCurrentWordIndexes();
            for (var wordIndexIndex in wordIndexes) {
                var i = wordIndexes[wordIndexIndex];
                this.alto.setNthWordLanguage(i,selected);
            }
            this.alto.changedSinceSave = true;
            this.cMirror.focus();
        },
        tagWord: function(ev){
            var wordIndexes = this.getCurrentWordIndexes();
            var i = 0;
            for (var wordIndexIndex in wordIndexes) {
                i = wordIndexes[wordIndexIndex];
            }
            events.trigger('showTagDialog', i);
        },
        tagTheWord: function(tagArray){
            console.log(tagArray.index + " " + tagArray.tag);
            this.alto.setNthWordTag(tagArray.index, tagArray.tag);
            this.alto.changedSinceSave = true;
            events.trigger("saveDocument");
            this.cMirror.focus();
        },
        refocus: function(ev) {
            this.cMirror.focus();
        },
        cursorToCoordinate: function(coords) {
            var content = this.cMirror.getValue();
            var line = 0;
            var ch = 0;
            var anchor,head;
            var betweenWords = false;
            if (!this.alto) { return; }
            var word = this.alto.getWordAt(coords.x,coords.y);
            if (word === undefined) {return;}
            var wordIndex = word.index;
            var wordLength = word.content.length;
            for (var i in content) {
                var c = content[i];
                if (c == '\n') {
                    line ++;
                    ch = -1;
                }
                if (c.match(/\s/)) {
                    betweenWords = true;
                } else {
                    if (betweenWords) wordIndex --;
                    if (wordIndex === 0) {
                        if (anchor === undefined) {
                            anchor = {
                                line: line,
                                ch: ch
                            }
                        }
                        head = {
                            line: line,
                            ch: ch + 1
                        }
                        wordLength --;
                        if (wordLength == 0) {
                            break;
                        }
                    }
                    betweenWords = false;
                }
                ch ++;
            }
            this.cMirror.setSelection(anchor,head);
            this.cMirror.focus();
        },
        configureCMMode: function () {
            this.cmConfig.changedSinceSaveSequence =
                this.alto.getChangedSinceSaveSequence();
            this.cmConfig.changedSince0Sequence
                = this.alto.getChangedSince0Sequence();
            this.cmConfig.languageSequence = this.alto.getLanguageSequence();
            this.cmConfig.tagSequence = this.alto.getTagSequence();
        },
        changed: function (instance) {
            var content = instance.getValue();

            if (!this.alto) return;

            this.alto.updateStringsContent(content.split(/\s+/));
            this.configureCMMode();
            this.setupHighlightChange();
        },
        getCurrentWordIndexes: function () {
            var wordIndexes = {};
            var wordIndex = -1; // in between words before first word...
            var content = this.cMirror.getValue();
            var start = this.cMirror.getCursor('start');
            var end = this.cMirror.getCursor('end');
            var s_line = start.line;
            var s_ch = start.ch;
            var e_line = end.line;
            var e_ch = end.ch;
            var betweenWords = true;
            var stillBetweenWords = false;

            for (var i in content) {

                var c = content[i];

                if (c.match(/\s/)) {

                    if (betweenWords) stillBetweenWords = true;
                    betweenWords = true;

                } else {

                    if (betweenWords) wordIndex ++;
                    betweenWords = false;
                    stillBetweenWords = false;

                }

                if (s_line <= 0) {
                    s_ch --;
                    if ((s_ch < 0) && (!stillBetweenWords)) {
                        wordIndexes[wordIndex] = true;
                    }
                }

                if (e_line <=0) {
                    e_ch --;
                    if (e_ch < 0) break;
                }

                if (c == '\n') {
                    s_line --;
                    e_line --;
                }
            }

            this.words = wordIndexes;
            var wordIndexArray = _.map(wordIndexes,function (v,k) {
                return parseInt(k,10);
            });
            return wordIndexArray;
        },
        setupHighlightChange: function () {

            var wordIndexes = this.getCurrentWordIndexes();
            var self = this;
            console.log(wordIndexes);
            var words = _.map(wordIndexes,function (v,k) {

                return self.alto.getNthWord(v);

            });

            self.cMirror.setOption('highlight',this.words);
            this.suppressChanged = true;
            this.cMirror.doc.frontier = this.cMirror.doc.first;
            this.cMirror.replaceSelection(this.cMirror.getSelection());
            this.suppressChanged = false;

            events.trigger('changeCoordinates',words);

        },
        changePage: function(attributes) {
            var self = this;
            this.attributes = attributes;
            alto.get(attributes).then(
                function(myAlto) {
                    /* if (this.attributes != attributes) return;*/
                    self.setAlto(myAlto);
                },
                function(msg) {
                    events.trigger('editorRenderError',{
                        error: 'editorRenderError',
                        message: msg
                    });
                }
            );
        },
        pageDirtyStateChanged: function() {
            if(this.alto.isDirty()) {
                this.$el.addClass('dirty');
            } else {
                this.$el.removeClass('dirty');
            }
        },
        setValueFromAlto: function(alto) {
            if (this.alto === undefined) {
                this.cMirror.setValue("");
            } else {
                var s = this.alto.getString(this.lineBreaks);
                this.cMirror.setValue(s);
            }
        },
        setAlto: function(alto) {
            this.alto = alto;
            this.setValueFromAlto();
            this.cMirror.clearHistory();
            var word = this.alto.getNthWord(0);
            this.cMirror.focus();
            events.trigger('editorRendered',this.attributes);
        },
        render: function() {
            return;     // Nothing to do, CodeMirror renders itself
        }
    });

    return {
        view: new View()
    };

});
<|endoftext|>


<commit_before>// An subclass of CodeMirror which adds a few methods that make it easier
// to work with character indexes rather than {line, ch} objects.
function IndexableCodeMirror(place, givenOptions) {
  var codeMirror = CodeMirror(place, givenOptions);

  // This is the reverse of CodeMirror2's coordsFromIndex() method.
  codeMirror.indexFromCoords = function(pos) {
    var index = pos.ch;
    for (var i = 0; i < pos.line; i++)
      index += codeMirror.getLine(i).length + 1;
    return index;
  };

  // Returns the character index of the cursor position.
  codeMirror.getCursorIndex = function() {
    return codeMirror.indexFromCoords(codeMirror.getCursor());
  };

  return codeMirror;
}

// A subclass of IndexableCodeMirror which continuously re-parses
// the code in its editor. Also adds a Backbone.Events interface
// for extension points to hook into.
function ParsingCodeMirror(place, givenOptions) {
  // Called whenever content of the editor area changes.
  function reparse() {
    var sourceCode = codeMirror.getValue();
    var result = givenOptions.parse(sourceCode);
    codeMirror.trigger("reparse", {
      error: result.error,
      sourceCode: sourceCode,
      document: result.document
    });
    // Cursor activity would've been fired before us, so call it again
    // to make sure it displays the right context-sensitive help based
    // on the new state of the document.
    onCursorActivity();
  }

  // Called whenever the user moves their cursor in the editor area.
  function onCursorActivity() {
    codeMirror.trigger("cursor-activity");
  }

  // The number of milliseconds to wait before re-parsing the editor
  // content.
  var parseDelay = givenOptions.parseDelay || 300;
  var reparseTimeout;

  givenOptions.onChange = function() {
    clearTimeout(reparseTimeout);
    reparseTimeout = setTimeout(reparse, parseDelay);
  };
  givenOptions.onCursorActivity = onCursorActivity;

  var codeMirror = IndexableCodeMirror(place, givenOptions);
  _.extend(codeMirror, Backbone.Events);
  codeMirror.reparse = reparse;
  return codeMirror;
}

// This helper class keeps track of different kinds of highlighting in
// a CodeMirror instance.
function MarkTracker(codeMirror) {
  var classNames = {};
  var marks = [];

  return {
    // Mark a given start/end interval in the CodeMirror, based on character
    // indices (not {line, ch} objects), with the given class name. If
    // an element is provided, give it the class name too.
    mark: function(start, end, className, element) {
      if (!(className in classNames))
        classNames[className] = [];
      if (element) {
        classNames[className].push(element);
        $(element).addClass(className);
      }
      start = codeMirror.coordsFromIndex(start);
      end = codeMirror.coordsFromIndex(end);
      marks.push(codeMirror.markText(start, end, className));
    },
    // Clear all marks made so far and remove the class from any elements
    // it was previously given to.
    clear: function() {
      marks.forEach(function(mark) {
        // Odd, from the CodeMirror docs you'd think this would remove
        // the class from the highlighted text, too, but it doesn't.
        // I guess we're just garbage collecting here.
        mark.clear();
      });
      var wrapper = codeMirror.getWrapperElement();
      for (var className in classNames) {
        classNames[className].forEach(function(element) {
          $(element).removeClass(className);
        });
        $("." + className, wrapper).removeClass(className);
      }

      marks = [];
      classNames = {};
    }
  };
}

// Provides context-sensitive help for a ParsingCodeMirror based on
// the current cursor position.
function ContextSensitiveHelp(options) {
  var self = {};
  var codeMirror = options.codeMirror;
  var template = options.template;
  var helpArea = options.helpArea;
  var helpIndex = options.helpIndex;
  var lastEvent = null;

  // Keep track of context-sensitive help highlighting.
  var cursorHelpMarks = MarkTracker(codeMirror);

  codeMirror.on("reparse", function(event) {
    lastEvent = event;
    helpIndex.clear();
    if (event.error)
      helpArea.hide();
    else
      helpIndex.build(event.document, event.sourceCode);
  });

  codeMirror.on("cursor-activity", function() {
    cursorHelpMarks.clear();
    var help = helpIndex.get(codeMirror.getCursorIndex());
    if (help) {
      if (help.type == "cssSelector") {
        // TODO: Because we're looking at the generated document fragment and
        // not an actual HTML document, implied elements like <body> may not
        // be captured here.
        var selector = help.highlights[0].value;
        var matches = lastEvent.document.querySelectorAll(selector).length;
        help.matchCount = matches;
      }
      helpArea.html(template(help)).show();
      help.highlights.forEach(function(interval) {
        cursorHelpMarks.mark(interval.start, interval.end,
                             "cursor-help-highlight");
      });
    } else
      helpArea.hide();
  });

  return self;
}

// Provides helpful Slowparse-based error suggestions for a
// ParsingCodeMirror.
function ErrorHelp(options) {
  var self = {};
  var codeMirror = options.codeMirror;
  var errorArea = options.errorArea;

  // Keep track of error highlighting.
  var errorHelpMarks = MarkTracker(codeMirror);

  // Report the given Slowparse error.
  function reportError(error) {
    errorArea.fillError(error).eachErrorHighlight(function(start, end, i) {
      errorHelpMarks.mark(start, end, "highlight-" + (i+1), this);
    });
  }

  codeMirror.on("reparse", function(event) {
    errorHelpMarks.clear();
    if (event.error)
      reportError(event.error);
    else
      errorArea.hide();
  });
  return self;
}

// Displays the HTML source of a CodeMirror editor as a rendered preview
// in an iframe.
function LivePreview(options) {
  var self = {};

  options.codeMirror.on("reparse", function(event) {
    if (!event.error || options.ignoreErrors) {
      // Update the preview area with the given HTML.
      var doc = options.previewArea.contents()[0];
      var wind = doc.defaultView;
      var x = wind.pageXOffset;
      var y = wind.pageYOffset;

      doc.open();
      doc.write(event.sourceCode);
      doc.close();

      // TODO: If the document has images that take a while to load
      // and the previous scroll position of the document depends on
      // their dimensions being set on load, we may need to refresh
      // this scroll position after the document has loaded.
      wind.scroll(x, y);
    }
  });

  return self;
}

// This helper saves the editor's data to local storage just before
// the page unloads, and provides a method to restore it. Useful for
// when a user accidentally refreshes/navigates away from the editor
// and wants to retrieve their old content.
//
// TODO: This could be a privacy concern, since people at shared terminals
// might not want the next user to be able to see what they were just
// working on.
function Parachute(window, codeMirror) {
  // We would use window.sessionStorage, but it goes away too quickly,
  // e.g. if the user accidentally closes the current window.
  var key = "FRIENDLYCODE_PARACHUTE_DATA";
  var storage = window.localStorage;
  var originalData = codeMirror.getValue();
  var self = {
    restore: function() {
      if (key in storage) {
        codeMirror.setValue(storage[key]);
        self.refresh();
      }
    },
    save: function() {
      if (codeMirror.getValue() != originalData)
        storage[key] = codeMirror.getValue();
    },
    refresh: function() {
      originalData = codeMirror.getValue();
    },
    destroy: function() {
      window.removeEventListener("beforeunload", self.save, true);
      delete storage[key];
    }
  };

  window.addEventListener("beforeunload", self.save, true);
  return self;
}

function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split("&");
  for (var i = 0; i < vars.length; i++) {
    var pair = vars[i].split("=");
    if (pair[0] == variable) {
      return unescape(pair[1]);
    }
  }
}

$(window).load(function() {
  jQuery.loadErrors("slowparse/spec/", ["base", "forbidjs"], function() {
    var codeMirror = ParsingCodeMirror($("#source")[0], {
      mode: "text/html",
      theme: "jsbin",
      tabMode: "indent",
      lineWrapping: true,
      lineNumbers: true,
      value: $("#initial-html").text().trim(),
      parse: function(html) {
        return Slowparse.HTML(document, html, [TreeInspectors.forbidJS]);
      }
    });
    var cursorHelp = ContextSensitiveHelp({
      codeMirror: codeMirror,
      helpIndex: Help.Index(),
      template: _.template($("#help-template").text()),
      helpArea: $(".help")
    });
    var errorHelp = ErrorHelp({
      codeMirror: codeMirror,
      errorArea: $(".error")
    });
    var preview = LivePreview({
      codeMirror: codeMirror,
      ignoreErrors: true,
      previewArea: $("#preview")
    });
    var publishUI = PublishUI({
      codeMirror: codeMirror,
      publisher: Publisher("http://wpm.toolness.org"),
      dialog: $("#publish-dialog")
    });
    var parachute = Parachute(window, codeMirror);

    $("#undo").click(function() { codeMirror.undo(); codeMirror.reparse(); });
    $("#redo").click(function() { codeMirror.redo(); codeMirror.reparse(); });
    $("#publish").click(function() { publishUI.saveCode(); });

    // TODO: Restoring the parachute here will get overwritten by a
    // loaded file, and the user will need to click 'undo' to retrieve
    // their lost data, which is not at all obvious--but for now, it's
    // better than nothing.
    parachute.restore();
    codeMirror.reparse();
    if (getQueryVariable('p'))
      publishUI.loadCode(getQueryVariable('p'), function() {
        $("#editor").removeClass("loading");
        // Parachute should only save lost data if it's different from
        // the URL we just (hopefully) loaded.
        parachute.refresh();
      });
    else
      $("#editor").removeClass("loading");
    codeMirror.focus();

    // We're only exposing these as globals so we can debug via
    // the console. Other parts of our code should never reference them.
    window._codeMirror = codeMirror;
    window._parachute = parachute;
  });
});
<commit_msg>Insert a BASE TARGET tag into the preview frame so that links clicked in it don't replace the preview frame content.<commit_after>// An subclass of CodeMirror which adds a few methods that make it easier
// to work with character indexes rather than {line, ch} objects.
function IndexableCodeMirror(place, givenOptions) {
  var codeMirror = CodeMirror(place, givenOptions);

  // This is the reverse of CodeMirror2's coordsFromIndex() method.
  codeMirror.indexFromCoords = function(pos) {
    var index = pos.ch;
    for (var i = 0; i < pos.line; i++)
      index += codeMirror.getLine(i).length + 1;
    return index;
  };

  // Returns the character index of the cursor position.
  codeMirror.getCursorIndex = function() {
    return codeMirror.indexFromCoords(codeMirror.getCursor());
  };

  return codeMirror;
}

// A subclass of IndexableCodeMirror which continuously re-parses
// the code in its editor. Also adds a Backbone.Events interface
// for extension points to hook into.
function ParsingCodeMirror(place, givenOptions) {
  // Called whenever content of the editor area changes.
  function reparse() {
    var sourceCode = codeMirror.getValue();
    var result = givenOptions.parse(sourceCode);
    codeMirror.trigger("reparse", {
      error: result.error,
      sourceCode: sourceCode,
      document: result.document
    });
    // Cursor activity would've been fired before us, so call it again
    // to make sure it displays the right context-sensitive help based
    // on the new state of the document.
    onCursorActivity();
  }

  // Called whenever the user moves their cursor in the editor area.
  function onCursorActivity() {
    codeMirror.trigger("cursor-activity");
  }

  // The number of milliseconds to wait before re-parsing the editor
  // content.
  var parseDelay = givenOptions.parseDelay || 300;
  var reparseTimeout;

  givenOptions.onChange = function() {
    clearTimeout(reparseTimeout);
    reparseTimeout = setTimeout(reparse, parseDelay);
  };
  givenOptions.onCursorActivity = onCursorActivity;

  var codeMirror = IndexableCodeMirror(place, givenOptions);
  _.extend(codeMirror, Backbone.Events);
  codeMirror.reparse = reparse;
  return codeMirror;
}

// This helper class keeps track of different kinds of highlighting in
// a CodeMirror instance.
function MarkTracker(codeMirror) {
  var classNames = {};
  var marks = [];

  return {
    // Mark a given start/end interval in the CodeMirror, based on character
    // indices (not {line, ch} objects), with the given class name. If
    // an element is provided, give it the class name too.
    mark: function(start, end, className, element) {
      if (!(className in classNames))
        classNames[className] = [];
      if (element) {
        classNames[className].push(element);
        $(element).addClass(className);
      }
      start = codeMirror.coordsFromIndex(start);
      end = codeMirror.coordsFromIndex(end);
      marks.push(codeMirror.markText(start, end, className));
    },
    // Clear all marks made so far and remove the class from any elements
    // it was previously given to.
    clear: function() {
      marks.forEach(function(mark) {
        // Odd, from the CodeMirror docs you'd think this would remove
        // the class from the highlighted text, too, but it doesn't.
        // I guess we're just garbage collecting here.
        mark.clear();
      });
      var wrapper = codeMirror.getWrapperElement();
      for (var className in classNames) {
        classNames[className].forEach(function(element) {
          $(element).removeClass(className);
        });
        $("." + className, wrapper).removeClass(className);
      }

      marks = [];
      classNames = {};
    }
  };
}

// Provides context-sensitive help for a ParsingCodeMirror based on
// the current cursor position.
function ContextSensitiveHelp(options) {
  var self = {};
  var codeMirror = options.codeMirror;
  var template = options.template;
  var helpArea = options.helpArea;
  var helpIndex = options.helpIndex;
  var lastEvent = null;

  // Keep track of context-sensitive help highlighting.
  var cursorHelpMarks = MarkTracker(codeMirror);

  codeMirror.on("reparse", function(event) {
    lastEvent = event;
    helpIndex.clear();
    if (event.error)
      helpArea.hide();
    else
      helpIndex.build(event.document, event.sourceCode);
  });

  codeMirror.on("cursor-activity", function() {
    cursorHelpMarks.clear();
    var help = helpIndex.get(codeMirror.getCursorIndex());
    if (help) {
      if (help.type == "cssSelector") {
        // TODO: Because we're looking at the generated document fragment and
        // not an actual HTML document, implied elements like <body> may not
        // be captured here.
        var selector = help.highlights[0].value;
        var matches = lastEvent.document.querySelectorAll(selector).length;
        help.matchCount = matches;
      }
      helpArea.html(template(help)).show();
      help.highlights.forEach(function(interval) {
        cursorHelpMarks.mark(interval.start, interval.end,
                             "cursor-help-highlight");
      });
    } else
      helpArea.hide();
  });

  return self;
}

// Provides helpful Slowparse-based error suggestions for a
// ParsingCodeMirror.
function ErrorHelp(options) {
  var self = {};
  var codeMirror = options.codeMirror;
  var errorArea = options.errorArea;

  // Keep track of error highlighting.
  var errorHelpMarks = MarkTracker(codeMirror);

  // Report the given Slowparse error.
  function reportError(error) {
    errorArea.fillError(error).eachErrorHighlight(function(start, end, i) {
      errorHelpMarks.mark(start, end, "highlight-" + (i+1), this);
    });
  }

  codeMirror.on("reparse", function(event) {
    errorHelpMarks.clear();
    if (event.error)
      reportError(event.error);
    else
      errorArea.hide();
  });
  return self;
}

// Displays the HTML source of a CodeMirror editor as a rendered preview
// in an iframe.
function LivePreview(options) {
  var self = {};

  options.codeMirror.on("reparse", function(event) {
    if (!event.error || options.ignoreErrors) {
      // Update the preview area with the given HTML.
      var doc = options.previewArea.contents()[0];
      var wind = doc.defaultView;
      var x = wind.pageXOffset;
      var y = wind.pageYOffset;

      doc.open();
      doc.write(event.sourceCode);
      doc.close();

      // Insert a BASE TARGET tag so that links don't open in
      // the iframe.
      var baseTag = doc.createElement('base');
      baseTag.setAttribute('target', '_blank');
      doc.querySelector("head").appendChild(baseTag);

      // TODO: If the document has images that take a while to load
      // and the previous scroll position of the document depends on
      // their dimensions being set on load, we may need to refresh
      // this scroll position after the document has loaded.
      wind.scroll(x, y);
    }
  });

  return self;
}

// This helper saves the editor's data to local storage just before
// the page unloads, and provides a method to restore it. Useful for
// when a user accidentally refreshes/navigates away from the editor
// and wants to retrieve their old content.
//
// TODO: This could be a privacy concern, since people at shared terminals
// might not want the next user to be able to see what they were just
// working on.
function Parachute(window, codeMirror) {
  // We would use window.sessionStorage, but it goes away too quickly,
  // e.g. if the user accidentally closes the current window.
  var key = "FRIENDLYCODE_PARACHUTE_DATA";
  var storage = window.localStorage;
  var originalData = codeMirror.getValue();
  var self = {
    restore: function() {
      if (key in storage) {
        codeMirror.setValue(storage[key]);
        self.refresh();
      }
    },
    save: function() {
      if (codeMirror.getValue() != originalData)
        storage[key] = codeMirror.getValue();
    },
    refresh: function() {
      originalData = codeMirror.getValue();
    },
    destroy: function() {
      window.removeEventListener("beforeunload", self.save, true);
      delete storage[key];
    }
  };

  window.addEventListener("beforeunload", self.save, true);
  return self;
}

function getQueryVariable(variable) {
  var query = window.location.search.substring(1);
  var vars = query.split("&");
  for (var i = 0; i < vars.length; i++) {
    var pair = vars[i].split("=");
    if (pair[0] == variable) {
      return unescape(pair[1]);
    }
  }
}

$(window).load(function() {
  jQuery.loadErrors("slowparse/spec/", ["base", "forbidjs"], function() {
    var codeMirror = ParsingCodeMirror($("#source")[0], {
      mode: "text/html",
      theme: "jsbin",
      tabMode: "indent",
      lineWrapping: true,
      lineNumbers: true,
      value: $("#initial-html").text().trim(),
      parse: function(html) {
        return Slowparse.HTML(document, html, [TreeInspectors.forbidJS]);
      }
    });
    var cursorHelp = ContextSensitiveHelp({
      codeMirror: codeMirror,
      helpIndex: Help.Index(),
      template: _.template($("#help-template").text()),
      helpArea: $(".help")
    });
    var errorHelp = ErrorHelp({
      codeMirror: codeMirror,
      errorArea: $(".error")
    });
    var preview = LivePreview({
      codeMirror: codeMirror,
      ignoreErrors: true,
      previewArea: $("#preview")
    });
    var publishUI = PublishUI({
      codeMirror: codeMirror,
      publisher: Publisher("http://wpm.toolness.org"),
      dialog: $("#publish-dialog")
    });
    var parachute = Parachute(window, codeMirror);

    $("#undo").click(function() { codeMirror.undo(); codeMirror.reparse(); });
    $("#redo").click(function() { codeMirror.redo(); codeMirror.reparse(); });
    $("#publish").click(function() { publishUI.saveCode(); });

    // TODO: Restoring the parachute here will get overwritten by a
    // loaded file, and the user will need to click 'undo' to retrieve
    // their lost data, which is not at all obvious--but for now, it's
    // better than nothing.
    parachute.restore();
    codeMirror.reparse();
    if (getQueryVariable('p'))
      publishUI.loadCode(getQueryVariable('p'), function() {
        $("#editor").removeClass("loading");
        // Parachute should only save lost data if it's different from
        // the URL we just (hopefully) loaded.
        parachute.refresh();
      });
    else
      $("#editor").removeClass("loading");
    codeMirror.focus();

    // We're only exposing these as globals so we can debug via
    // the console. Other parts of our code should never reference them.
    window._codeMirror = codeMirror;
    window._parachute = parachute;
  });
});
<|endoftext|>