<commit_before>initialize("body");

function initialize(element) {

  $(element+' td.click_to_show').click(function (e) {
    popup_show($(this), e);
    return false;
  });

  $(element+' li.click_to_add_new').click(function (e) {
    popup_new($(this), e, this);
    return false;
  });

  $(element+' li.click_to_edit_timeslot').click(function (e) {
    popup_edit_timeslot($(this), e);
    return false;
  });

  $(element+' a.click_to_delete_repeating_timeslot').click(function (e) {
    popup_delete_repeating_timeslot($(this), e);
    return false;
  });

  //don't stop links from firing
  $(element+' li.click_to_edit_timeslot a.delete_link').click(function (e) {
    e.stopPropagation();
  });

  $(element+' li.click_to_show').click(function (e) {
    popup_show($(this), e);
    return false;
  });

  $(element+' div.click_to_add_new').click(function (e) {
    popup_generic_new($(this), e);
    return false;
  });

  $(element+' li.click_to_add_new_timeslot').click(function (e) {
    popup_new_timeslot($(this), e, this);
    return false;
  });

  $(element+' li.click_to_add_new_shift').click(function (e) {
    popup_new_shift($(this), e, this);
    return false;
  });

  $(element+' li.click_to_edit_shift').click(function (e) {
    popup_edit_shift($(this), e);
    return false;
  });

  $(element+' li.click_to_edit_timeslot').click(function (e) {
    popup_edit_timeslot($(this), e);
    return false;
  });

  $(element+' a.click_to_delete_repeating_shift').click(function (e) {
    popup_delete_repeating_shift($(this), e);
    return false;
  });

  $(element+' a.click_to_delete_repeating_timeslot').click(function (e) {
    popup_delete_repeating_timeslot($(this), e);
    return false;
  });

  $(element+' li.click_to_edit_shift a.delete_link').click(function (e) {
    e.stopPropagation();
  });

  $(element+' li.click_to_edit_timeslot a.delete_link').click(function (e) {
    e.stopPropagation();
  });

  show_visible(element);
}

function popup_show(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(5); //remove "shift" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({dataType:'script', type:'get', url:shiftsPath+'/'+id, async: false});
}

function loading_tooltip(x,y){
  $('body').append("
Loading...
");
}

function getXOffset(element){
  var x = 0
  while(element){
      x += element.offsetLeft;
      element = element.offsetParent;
  }
  return x;
}

function popup_new(parent_element, e, raw_element){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id
  var date = params[1];

  //cursor position magic
  var relX = e.pageX - getXOffset(parent_element.closest('.events').get(0));
  var widthPercentage = relX / parent_element.closest('.events').width();

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"location_id="+locationID+"&date="+date+"&xPercentage="+widthPercentage, dataType:'script', type:'get', url:newShiftPath});
}

function popup_generic_new(parent_element, e){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id
  var date = params[1];

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"location_id="+locationID+"&date="+date, dataType:'script', type:'get', url:newShiftPath, async: false});
}

function popup_edit_timeslot(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(8); //remove "timeslot" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({dataType:'script', type:'get', url:timeSlotsPath+'/'+id+'/edit', async: false});
}

function popup_delete_repeating_timeslot(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(17); //remove "delete_repeating_" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"delete_options=true", dataType:'script', type:'get', url:timeSlotsPath+'/'+id+'/edit', async: false});
}

function popup_new_timeslot(parent_element, e, raw_element){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id

  //cursor position magic
  var relX = e.pageX - getXOffset(raw_element);
  var widthPercentage = relX / parent_element.width();
  var date = params[1];

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar+"&location_id="+locationID+"&date="+date+"&xPercentage="+widthPercentage, dataType:'script', type:'get', url:newTimeSlotPath, async: false});
}

function popup_new_shift(parent_element, e, raw_element){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id
  var date = params[1];

  //cursor position magic
  var relX = e.pageX - getXOffset(raw_element);
  var widthPercentage = relX / parent_element.width();

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar+"&location_id="+locationID+"&date="+date+"&xPercentage="+widthPercentage, dataType:'script', type:'get', url:newShiftPath, async: false});
}

function popup_edit_shift(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(5); //remove "shift" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar, dataType:'script', type:'get', url:shiftsPath+'/'+id, async: false});
}

function popup_delete_repeating_shift(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(17); //remove "delete_repeating_" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar+"&delete_options=true", dataType:'script', type:'get', url:shiftsPath+'/'+id, async: false});
}
//show all calendars that are currently visible, even after rerender
function show_visible(element){
  for (calendar_id in calendar_visible) {
    if (calendar_visible[calendar_id] == true) {
      $(element+' .calendar'+calendar_id).show();
    }
    else {
      $(element+' .calendar'+calendar_id).hide();
    }
  }
}

//hide tooltip upon hitting escape
$(document).keypress(
  function (e){
    if (e.which == 0)
    {
      $(".tooltip").remove();
    }
  }
);

//close window when pressing [esc]
$(this).keyup(function(event) {
  if (event.keyCode == 27) {
     $('#tooltip').fadeOut(function (){ $(this).remove() });
   return false;
   }
});
//close window when clicking on the page
$(this).click(function(event) {
  if ($('#tooltip').length == 1) {
     $('#tooltip').fadeOut(function (){ $(this).remove() });
    return(false);
  }
});
// make sure that the
$("#tooltip").click(function(e){
  e.stopPropagation();
});

var calendar_visible = {};

//Hide the new timeslot link when Javascript it enabled
$('#new_time_slot_link').toggle();

// For the stats pages
$(document).ready(function(){$.tablesorter.defaults.widgets = ['zebra'];$("#stats_table").tablesorter({sortList: [[1,0],[0,1]]});});

var opts = {
                formElements:{"stat_start_date_3i":"j",
                              "stat_start_date_1i":"Y",
                              "stat_start_date_2i":"n"
                },
                statusFormat:"l-cc-sp-d-sp-F-sp-Y",
                noFadeEffect:true,
                       };
datePickerController.createDatePicker(opts);

var opts = {
                formElements:{"stat_end_date_3i":"j",
                              "stat_end_date_1i":"Y",
                              "stat_end_date_2i":"n"
                },
                statusFormat:"l-cc-sp-d-sp-F-sp-Y",
                noFadeEffect:true,
                       };
datePickerController.createDatePicker(opts);<commit_msg>fixed Loading... forever a little more<commit_after>initialize("body");

function initialize(element) {

  $(element+' td.click_to_show').click(function (e) {
    popup_show($(this), e);
    return false;
  });

  $(element+' li.click_to_add_new').click(function (e) {
    popup_new($(this), e, this);
    return false;
  });

  $(element+' li.click_to_edit_timeslot').click(function (e) {
    popup_edit_timeslot($(this), e);
    return false;
  });

  $(element+' a.click_to_delete_repeating_timeslot').click(function (e) {
    popup_delete_repeating_timeslot($(this), e);
    return false;
  });

  //don't stop links from firing
  $(element+' li.click_to_edit_timeslot a.delete_link').click(function (e) {
    e.stopPropagation();
  });

  $(element+' li.click_to_show').click(function (e) {
    popup_show($(this), e);
    return false;
  });

  $(element+' div.click_to_add_new').click(function (e) {
    popup_generic_new($(this), e);
    return false;
  });

  $(element+' li.click_to_add_new_timeslot').click(function (e) {
    popup_new_timeslot($(this), e, this);
    return false;
  });

  $(element+' li.click_to_add_new_shift').click(function (e) {
    popup_new_shift($(this), e, this);
    return false;
  });

  $(element+' li.click_to_edit_shift').click(function (e) {
    popup_edit_shift($(this), e);
    return false;
  });

  $(element+' li.click_to_edit_timeslot').click(function (e) {
    popup_edit_timeslot($(this), e);
    return false;
  });

  $(element+' a.click_to_delete_repeating_shift').click(function (e) {
    popup_delete_repeating_shift($(this), e);
    return false;
  });

  $(element+' a.click_to_delete_repeating_timeslot').click(function (e) {
    popup_delete_repeating_timeslot($(this), e);
    return false;
  });

  $(element+' li.click_to_edit_shift a.delete_link').click(function (e) {
    e.stopPropagation();
  });

  $(element+' li.click_to_edit_timeslot a.delete_link').click(function (e) {
    e.stopPropagation();
  });

  show_visible(element);
}

function popup_show(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(5); //remove "shift" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({dataType:'script', type:'get', url:shiftsPath+'/'+id});
}

function loading_tooltip(x,y){
  $('body').append("
Loading...
");
}

function getXOffset(element){
  var x = 0
  while(element){
      x += element.offsetLeft;
      element = element.offsetParent;
  }
  return x;
}

function popup_new(parent_element, e, raw_element){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id
  var date = params[1];

  //cursor position magic
  var relX = e.pageX - getXOffset(parent_element.closest('.events').get(0));
  var widthPercentage = relX / parent_element.closest('.events').width();

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"location_id="+locationID+"&date="+date+"&xPercentage="+widthPercentage, dataType:'script', type:'get', url:newShiftPath});
}

function popup_generic_new(parent_element, e){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id
  var date = params[1];

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"location_id="+locationID+"&date="+date, dataType:'script', type:'get', url:newShiftPath});
}

function popup_edit_timeslot(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(8); //remove "timeslot" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({dataType:'script', type:'get', url:timeSlotsPath+'/'+id+'/edit'});
}

function popup_delete_repeating_timeslot(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(17); //remove "delete_repeating_" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"delete_options=true", dataType:'script', type:'get', url:timeSlotsPath+'/'+id+'/edit'});
}

function popup_new_timeslot(parent_element, e, raw_element){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id

  //cursor position magic
  var relX = e.pageX - getXOffset(raw_element);
  var widthPercentage = relX / parent_element.width();
  var date = params[1];

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar+"&location_id="+locationID+"&date="+date+"&xPercentage="+widthPercentage, dataType:'script', type:'get', url:newTimeSlotPath});
}

function popup_new_shift(parent_element, e, raw_element){
  $("#tooltip").remove();

  var elementID = parent_element.attr('id');
  var params = elementID.split("_", 2);
  var locationID = params[0].substring(8); //remove "location" from id
  var date = params[1];

  //cursor position magic
  var relX = e.pageX - getXOffset(raw_element);
  var widthPercentage = relX / parent_element.width();

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar+"&location_id="+locationID+"&date="+date+"&xPercentage="+widthPercentage, dataType:'script', type:'get', url:newShiftPath});
}

function popup_edit_shift(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(5); //remove "shift" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar, dataType:'script', type:'get', url:shiftsPath+'/'+id});
}

function popup_delete_repeating_shift(parent_element, e){
  $("#tooltip").remove();

  var id = parent_element.attr('id').substring(17); //remove "delete_repeating_" from id

  loading_tooltip(e.pageX, e.pageY);
  $.ajax({data:"calendar="+calendar+"&delete_options=true", dataType:'script', type:'get', url:shiftsPath+'/'+id});
}
//show all calendars that are currently visible, even after rerender
function show_visible(element){
  for (calendar_id in calendar_visible) {
    if (calendar_visible[calendar_id] == true) {
      $(element+' .calendar'+calendar_id).show();
    }
    else {
      $(element+' .calendar'+calendar_id).hide();
    }
  }
}

//hide tooltip upon hitting escape
$(document).keypress(
  function (e){
    if (e.which == 0)
    {
      $(".tooltip").remove();
    }
  }
);

//close window when pressing [esc]
$(this).keyup(function(event) {
  if (event.keyCode == 27) {
     $('#tooltip').fadeOut(function (){ $(this).remove() });
   return false;
   }
});
//close window when clicking on the page
$(this).click(function(event) {
  if ($('#tooltip').length == 1) {
     $('#tooltip').fadeOut(function (){ $(this).remove() });
    return(false);
  }
});
// make sure that the
$("#tooltip").click(function(e){
  e.stopPropagation();
});

var calendar_visible = {};

//Hide the new timeslot link when Javascript it enabled
$('#new_time_slot_link').toggle();

// For the stats pages
$(document).ready(function(){$.tablesorter.defaults.widgets = ['zebra'];$("#stats_table").tablesorter({sortList: [[1,0],[0,1]]});});

var opts = {
                formElements:{"stat_start_date_3i":"j",
                              "stat_start_date_1i":"Y",
                              "stat_start_date_2i":"n"
                },
                statusFormat:"l-cc-sp-d-sp-F-sp-Y",
                noFadeEffect:true,
                       };
datePickerController.createDatePicker(opts);

var opts = {
                formElements:{"stat_end_date_3i":"j",
                              "stat_end_date_1i":"Y",
                              "stat_end_date_2i":"n"
                },
                statusFormat:"l-cc-sp-d-sp-F-sp-Y",
                noFadeEffect:true,
                       };
datePickerController.createDatePicker(opts);<|endoftext|>


<commit_before>Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");
var EventUtils = Components.utils.import("resource://zotero-unit/EventUtils.jsm");

var ZoteroUnit = Components.classes["@mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit"].
	             getService(Components.interfaces.nsISupports).
	             wrappedJSObject;
var dump = ZoteroUnit.dump;

function quit(failed) {
	// Quit with exit status
	if(!failed) {
		OS.File.writeAtomic(FileUtils.getFile("ProfD", ["success"]).path, new Uint8Array(0));
	}
	if(!ZoteroUnit.noquit) {
		Components.classes['@mozilla.org/toolkit/app-startup;1'].
		getService(Components.interfaces.nsIAppStartup).
		quit(Components.interfaces.nsIAppStartup.eForceQuit);
	}
}

function Reporter(runner) {
	var indents = 0, passed = 0, failed = 0;

	function indent() {
		return Array(indents).join('  ');
	}

	runner.on('start', function(){});

	runner.on('suite', function(suite){
		++indents;
		dump(indent()+suite.title+"\n");
	});

	runner.on('suite end', function(suite){
		--indents;
		if (1 == indents) dump("\n");
	});

	runner.on('pending', function(test){
		dump(indent()+"pending  -"+test.title);
	});

	runner.on('pass', function(test){
		passed++;
		var msg = "\r"+indent()+Mocha.reporters.Base.symbols.ok+" "+test.title;
		if ('fast' != test.speed) {
			msg += " ("+Math.round(test.duration)+" ms)";
		}
		dump(msg+"\n");
	});

	runner.on('fail', function(test, err){
		failed++;
		dump("\r"+indent()+Mocha.reporters.Base.symbols.err+" "+test.title+"\n"+
		     indent()+"  "+err.toString()+" at\n"+
		     indent()+"    "+err.stack.replace("\n", "\n"+indent()+"    ", "g"));
	});

	runner.on('end', function() {
		dump(passed+"/"+(passed+failed)+" tests passed.\n");
		quit(failed != 0);
	});
}

// Setup Mocha
mocha.setup({ui:"bdd", reporter:Reporter});

// Enable Bluebird generator support in Mocha
(function () {
	var Runnable = Mocha.Runnable;
	var run = Runnable.prototype.run;
	Runnable.prototype.run = function (fn) {
		if (this.fn.constructor.name === 'GeneratorFunction') {
			this.fn = Zotero.Promise.coroutine(this.fn);
		}
		return run.call(this, fn);
	};
})();

var assert = chai.assert,
    expect = chai.expect;

// Set up tests to run
var run = true;
if(ZoteroUnit.tests) {
	var testDirectory = getTestDataDirectory().parent,
	    testFiles = [];
	if(ZoteroUnit.tests == "all") {
		var enumerator = testDirectory.directoryEntries;
		while(enumerator.hasMoreElements()) {
			var file = enumerator.getNext().QueryInterface(Components.interfaces.nsIFile);
			if(file.leafName.endsWith(".js")) {
				testFiles.push(file.leafName);
			}
		}
	} else {
		var specifiedTests = ZoteroUnit.tests.split(",");
		for(var test of specifiedTests) {
			var fname = test+".js",
			    file = testDirectory.clone();
			file.append(fname);
			if(!file.exists()) {
				dump("Invalid test file "+test+"\n");
				run = false;
				quit(true);
			}
			testFiles.push(fname);
		}
	}

	for(var fname of testFiles) {
		var el = document.createElement("script");
		el.type = "application/javascript;version=1.8";
		el.src = "resource://zotero-unit-tests/"+fname;
		document.body.appendChild(el);
	}
}

if(run) {
	window.onload = function() {
		Zotero.Schema.schemaUpdatePromise.then(function() {
			mocha.run();
		});
	};
}<commit_msg>Make the '✖' for test errors red<commit_after>Components.utils.import("resource://gre/modules/FileUtils.jsm");
Components.utils.import("resource://gre/modules/osfile.jsm");
var EventUtils = Components.utils.import("resource://zotero-unit/EventUtils.jsm");

var ZoteroUnit = Components.classes["@mozilla.org/commandlinehandler/general-startup;1?type=zotero-unit"].
	             getService(Components.interfaces.nsISupports).
	             wrappedJSObject;
var dump = ZoteroUnit.dump;

function quit(failed) {
	// Quit with exit status
	if(!failed) {
		OS.File.writeAtomic(FileUtils.getFile("ProfD", ["success"]).path, new Uint8Array(0));
	}
	if(!ZoteroUnit.noquit) {
		Components.classes['@mozilla.org/toolkit/app-startup;1'].
		getService(Components.interfaces.nsIAppStartup).
		quit(Components.interfaces.nsIAppStartup.eForceQuit);
	}
}

function Reporter(runner) {
	var indents = 0, passed = 0, failed = 0;

	function indent() {
		return Array(indents).join('  ');
	}

	runner.on('start', function(){});

	runner.on('suite', function(suite){
		++indents;
		dump(indent()+suite.title+"\n");
	});

	runner.on('suite end', function(suite){
		--indents;
		if (1 == indents) dump("\n");
	});

	runner.on('pending', function(test){
		dump(indent()+"pending  -"+test.title);
	});

	runner.on('pass', function(test){
		passed++;
		var msg = "\r"+indent()+Mocha.reporters.Base.symbols.ok+" "+test.title;
		if ('fast' != test.speed) {
			msg += " ("+Math.round(test.duration)+" ms)";
		}
		dump(msg+"\n");
	});

	runner.on('fail', function(test, err){
		failed++;
		dump("\r" + indent()
			// Dark red X for errors
			+ "\033[31;40m" + Mocha.reporters.Base.symbols.err + "\033[0m"
			+ " " + test.title + "\n"
			+ indent() + "  " + err.toString() + " at\n"
			+ indent() + "    " + err.stack.replace("\n", "\n" + indent() + "    ", "g"));
	});

	runner.on('end', function() {
		dump(passed+"/"+(passed+failed)+" tests passed.\n");
		quit(failed != 0);
	});
}

// Setup Mocha
mocha.setup({ui:"bdd", reporter:Reporter});

// Enable Bluebird generator support in Mocha
(function () {
	var Runnable = Mocha.Runnable;
	var run = Runnable.prototype.run;
	Runnable.prototype.run = function (fn) {
		if (this.fn.constructor.name === 'GeneratorFunction') {
			this.fn = Zotero.Promise.coroutine(this.fn);
		}
		return run.call(this, fn);
	};
})();

var assert = chai.assert,
    expect = chai.expect;

// Set up tests to run
var run = true;
if(ZoteroUnit.tests) {
	var testDirectory = getTestDataDirectory().parent,
	    testFiles = [];
	if(ZoteroUnit.tests == "all") {
		var enumerator = testDirectory.directoryEntries;
		while(enumerator.hasMoreElements()) {
			var file = enumerator.getNext().QueryInterface(Components.interfaces.nsIFile);
			if(file.leafName.endsWith(".js")) {
				testFiles.push(file.leafName);
			}
		}
	} else {
		var specifiedTests = ZoteroUnit.tests.split(",");
		for(var test of specifiedTests) {
			var fname = test+".js",
			    file = testDirectory.clone();
			file.append(fname);
			if(!file.exists()) {
				dump("Invalid test file "+test+"\n");
				run = false;
				quit(true);
			}
			testFiles.push(fname);
		}
	}

	for(var fname of testFiles) {
		var el = document.createElement("script");
		el.type = "application/javascript;version=1.8";
		el.src = "resource://zotero-unit-tests/"+fname;
		document.body.appendChild(el);
	}
}

if(run) {
	window.onload = function() {
		Zotero.Schema.schemaUpdatePromise.then(function() {
			mocha.run();
		});
	};
}<|endoftext|>


<commit_before>/**
 * ScriptLoader.js
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

(function(tinymce) {
	/**
	 * This class handles asynchronous/synchronous loading of JavaScript files it will execute callbacks when various items gets loaded. This class is useful to load external JavaScript files.
	 *
	 * @class tinymce.dom.ScriptLoader
	 * @example
	 * // Load a script from a specific URL using the global script loader
	 * tinymce.ScriptLoader.load('somescript.js');
	 *
	 * // Load a script using a unique instance of the script loader
	 * var scriptLoader = new tinymce.dom.ScriptLoader();
	 *
	 * scriptLoader.load('somescript.js');
	 *
	 * // Load multiple scripts
	 * var scriptLoader = new tinymce.dom.ScriptLoader();
	 *
	 * scriptLoader.add('somescript1.js');
	 * scriptLoader.add('somescript2.js');
	 * scriptLoader.add('somescript3.js');
	 *
	 * scriptLoader.loadQueue(function() {
	 *    alert('All scripts are now loaded.');
	 * });
	 */
	tinymce.dom.ScriptLoader = function(settings) {
		var QUEUED = 0,
			LOADING = 1,
			LOADED = 2,
			states = {},
			queue = [],
			scriptLoadedCallbacks = {},
			queueLoadedCallbacks = [],
			loading = 0,
			undef;

		/**
		 * Loads a specific script directly without adding it to the load queue.
		 *
		 * @method load
		 * @param {String} url Absolute URL to script to add.
		 * @param {function} callback Optional callback function to execute ones this script gets loaded.
		 * @param {Object} scope Optional scope to execute callback in.
		 */
		function loadScript(url, callback) {
			var t = this, dom = tinymce.DOM, elm, uri, loc, id;

			// Execute callback when script is loaded
			function done() {
				dom.remove(id);

				if (elm)
					elm.onreadystatechange = elm.onload = elm = null;

				callback();
			};

			function error() {
				// Report the error so it's easier for people to spot loading errors
				if (typeof(console) !== "undefined" && console.log)
					console.log("Failed to load: " + url);

				// We can't mark it as done if there is a load error since
				// A) We don't want to produce 404 errors on the server and
				// B) the onerror event won't fire on all browsers.
				// done();
			};

			id = dom.uniqueId();

			if (tinymce.isIE6) {
				uri = new tinymce.util.URI(url);
				loc = location;

				// If script is from same domain and we
				// use IE 6 then use XHR since it's more reliable
				if (uri.host == loc.hostname && uri.port == loc.port && (uri.protocol + ':') == loc.protocol && uri.protocol.toLowerCase() != 'file') {
					tinymce.util.XHR.send({
						url : tinymce._addVer(uri.getURI()),
						success : function(content) {
							// Create new temp script element
							var script = dom.create('script', {
								type : 'text/javascript'
							});

							// Evaluate script in global scope
							script.text = content;
							document.getElementsByTagName('head')[0].appendChild(script);
							dom.remove(script);

							done();
						},

						error : error
					});

					return;
				}
			}

			// Create new script element
			elm = dom.create('script', {
				id : id,
				type : 'text/javascript',
				src : tinymce._addVer(url)
			});

			// Add onload listener for non IE browsers since IE9
			// fires onload event before the script is parsed and executed
			if (!tinymce.isIE)
				elm.onload = done;

			// Add onerror event will get fired on some browsers but not all of them
			elm.onerror = error;

			// Opera 9.60 doesn't seem to fire the onreadystate event at correctly
			if (!tinymce.isOpera) {
				elm.onreadystatechange = function() {
					var state = elm.readyState;

					// Loaded state is passed on IE 6 however there
					// are known issues with this method but we can't use
					// XHR in a cross domain loading
					if (state == 'complete' || state == 'loaded')
						done();
				};
			}

			// Most browsers support this feature so we report errors
			// for those at least to help users track their missing plugins etc
			// todo: Removed since it produced error if the document is unloaded by navigating away, re-add it as an option
			/*elm.onerror = function() {
				alert('Failed to load: ' + url);
			};*/

			// Add script to document
			(document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
		};

		/**
		 * Returns true/false if a script has been loaded or not.
		 *
		 * @method isDone
		 * @param {String} url URL to check for.
		 * @return [Boolean} true/false if the URL is loaded.
		 */
		this.isDone = function(url) {
			return states[url] == LOADED;
		};

		/**
		 * Marks a specific script to be loaded. This can be useful if a script got loaded outside
		 * the script loader or to skip it from loading some script.
		 *
		 * @method markDone
		 * @param {string} u Absolute URL to the script to mark as loaded.
		 */
		this.markDone = function(url) {
			states[url] = LOADED;
		};

		/**
		 * Adds a specific script to the load queue of the script loader.
		 *
		 * @method add
		 * @param {String} url Absolute URL to script to add.
		 * @param {function} callback Optional callback function to execute ones this script gets loaded.
		 * @param {Object} scope Optional scope to execute callback in.
		 */
		this.add = this.load = function(url, callback, scope) {
			var item, state = states[url];

			// Add url to load queue
			if (state == undef) {
				queue.push(url);
				states[url] = QUEUED;
			}

			if (callback) {
				// Store away callback for later execution
				if (!scriptLoadedCallbacks[url])
					scriptLoadedCallbacks[url] = [];

				scriptLoadedCallbacks[url].push({
					func : callback,
					scope : scope || this
				});
			}
		};

		/**
		 * Starts the loading of the queue.
		 *
		 * @method loadQueue
		 * @param {function} callback Optional callback to execute when all queued items are loaded.
		 * @param {Object} scope Optional scope to execute the callback in.
		 */
		this.loadQueue = function(callback, scope) {
			this.loadScripts(queue, callback, scope);
		};

		/**
		 * Loads the specified queue of files and executes the callback ones they are loaded.
		 * This method is generally not used outside this class but it might be useful in some scenarios.
		 *
		 * @method loadScripts
		 * @param {Array} scripts Array of queue items to load.
		 * @param {function} callback Optional callback to execute ones all items are loaded.
		 * @param {Object} scope Optional scope to execute callback in.
		 */
		this.loadScripts = function(scripts, callback, scope) {
			var loadScripts;

			function execScriptLoadedCallbacks(url) {
				// Execute URL callback functions
				tinymce.each(scriptLoadedCallbacks[url], function(callback) {
					callback.func.call(callback.scope);
				});

				scriptLoadedCallbacks[url] = undef;
			};

			queueLoadedCallbacks.push({
				func : callback,
				scope : scope || this
			});

			loadScripts = function() {
				var loadingScripts = tinymce.grep(scripts);

				// Current scripts has been handled
				scripts.length = 0;

				// Load scripts that needs to be loaded
				tinymce.each(loadingScripts, function(url) {
					// Script is already loaded then execute script callbacks directly
					if (states[url] == LOADED) {
						execScriptLoadedCallbacks(url);
						return;
					}

					// Is script not loading then start loading it
					if (states[url] != LOADING) {
						states[url] = LOADING;
						loading++;

						loadScript(url, function() {
							states[url] = LOADED;
							loading--;

							execScriptLoadedCallbacks(url);

							// Load more scripts if they where added by the recently loaded script
							loadScripts();
						});
					}
				});

				// No scripts are currently loading then execute all pending queue loaded callbacks
				if (!loading) {
					tinymce.each(queueLoadedCallbacks, function(callback) {
						callback.func.call(callback.scope);
					});

					queueLoadedCallbacks.length = 0;
				}
			};

			loadScripts();
		};
	};

	// Global script loader
	tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();
})(tinymce);
<commit_msg>Optimized ScriptLoader.js by not using dom.create when creating the script tags.<commit_after>/**
 * ScriptLoader.js
 *
 * Copyright, Moxiecode Systems AB
 * Released under LGPL License.
 *
 * License: http://www.tinymce.com/license
 * Contributing: http://www.tinymce.com/contributing
 */

(function(tinymce) {
	/**
	 * This class handles asynchronous/synchronous loading of JavaScript files it will execute callbacks when various items gets loaded. This class is useful to load external JavaScript files.
	 *
	 * @class tinymce.dom.ScriptLoader
	 * @example
	 * // Load a script from a specific URL using the global script loader
	 * tinymce.ScriptLoader.load('somescript.js');
	 *
	 * // Load a script using a unique instance of the script loader
	 * var scriptLoader = new tinymce.dom.ScriptLoader();
	 *
	 * scriptLoader.load('somescript.js');
	 *
	 * // Load multiple scripts
	 * var scriptLoader = new tinymce.dom.ScriptLoader();
	 *
	 * scriptLoader.add('somescript1.js');
	 * scriptLoader.add('somescript2.js');
	 * scriptLoader.add('somescript3.js');
	 *
	 * scriptLoader.loadQueue(function() {
	 *    alert('All scripts are now loaded.');
	 * });
	 */
	tinymce.dom.ScriptLoader = function(settings) {
		var QUEUED = 0,
			LOADING = 1,
			LOADED = 2,
			states = {},
			queue = [],
			scriptLoadedCallbacks = {},
			queueLoadedCallbacks = [],
			loading = 0,
			undef;

		/**
		 * Loads a specific script directly without adding it to the load queue.
		 *
		 * @method load
		 * @param {String} url Absolute URL to script to add.
		 * @param {function} callback Optional callback function to execute ones this script gets loaded.
		 * @param {Object} scope Optional scope to execute callback in.
		 */
		function loadScript(url, callback) {
			var t = this, dom = tinymce.DOM, elm, uri, loc, id;

			// Execute callback when script is loaded
			function done() {
				dom.remove(id);

				if (elm)
					elm.onreadystatechange = elm.onload = elm = null;

				callback();
			};

			function error() {
				// Report the error so it's easier for people to spot loading errors
				if (typeof(console) !== "undefined" && console.log)
					console.log("Failed to load: " + url);

				// We can't mark it as done if there is a load error since
				// A) We don't want to produce 404 errors on the server and
				// B) the onerror event won't fire on all browsers.
				// done();
			};

			id = dom.uniqueId();

			if (tinymce.isIE6) {
				uri = new tinymce.util.URI(url);
				loc = location;

				// If script is from same domain and we
				// use IE 6 then use XHR since it's more reliable
				if (uri.host == loc.hostname && uri.port == loc.port && (uri.protocol + ':') == loc.protocol && uri.protocol.toLowerCase() != 'file') {
					tinymce.util.XHR.send({
						url : tinymce._addVer(uri.getURI()),
						success : function(content) {
							// Create new temp script element
							var script = dom.create('script', {
								type : 'text/javascript'
							});

							// Evaluate script in global scope
							script.text = content;
							document.getElementsByTagName('head')[0].appendChild(script);
							dom.remove(script);

							done();
						},

						error : error
					});

					return;
				}
			}

			// Create new script element
			elm = document.createElement('script');
			elm.id = id;
			elm.type = 'text/javascript';
			elm.src = tinymce._addVer(url);

			// Add onload listener for non IE browsers since IE9
			// fires onload event before the script is parsed and executed
			if (!tinymce.isIE)
				elm.onload = done;

			// Add onerror event will get fired on some browsers but not all of them
			elm.onerror = error;

			// Opera 9.60 doesn't seem to fire the onreadystate event at correctly
			if (!tinymce.isOpera) {
				elm.onreadystatechange = function() {
					var state = elm.readyState;

					// Loaded state is passed on IE 6 however there
					// are known issues with this method but we can't use
					// XHR in a cross domain loading
					if (state == 'complete' || state == 'loaded')
						done();
				};
			}

			// Most browsers support this feature so we report errors
			// for those at least to help users track their missing plugins etc
			// todo: Removed since it produced error if the document is unloaded by navigating away, re-add it as an option
			/*elm.onerror = function() {
				alert('Failed to load: ' + url);
			};*/

			// Add script to document
			(document.getElementsByTagName('head')[0] || document.body).appendChild(elm);
		};

		/**
		 * Returns true/false if a script has been loaded or not.
		 *
		 * @method isDone
		 * @param {String} url URL to check for.
		 * @return [Boolean} true/false if the URL is loaded.
		 */
		this.isDone = function(url) {
			return states[url] == LOADED;
		};

		/**
		 * Marks a specific script to be loaded. This can be useful if a script got loaded outside
		 * the script loader or to skip it from loading some script.
		 *
		 * @method markDone
		 * @param {string} u Absolute URL to the script to mark as loaded.
		 */
		this.markDone = function(url) {
			states[url] = LOADED;
		};

		/**
		 * Adds a specific script to the load queue of the script loader.
		 *
		 * @method add
		 * @param {String} url Absolute URL to script to add.
		 * @param {function} callback Optional callback function to execute ones this script gets loaded.
		 * @param {Object} scope Optional scope to execute callback in.
		 */
		this.add = this.load = function(url, callback, scope) {
			var item, state = states[url];

			// Add url to load queue
			if (state == undef) {
				queue.push(url);
				states[url] = QUEUED;
			}

			if (callback) {
				// Store away callback for later execution
				if (!scriptLoadedCallbacks[url])
					scriptLoadedCallbacks[url] = [];

				scriptLoadedCallbacks[url].push({
					func : callback,
					scope : scope || this
				});
			}
		};

		/**
		 * Starts the loading of the queue.
		 *
		 * @method loadQueue
		 * @param {function} callback Optional callback to execute when all queued items are loaded.
		 * @param {Object} scope Optional scope to execute the callback in.
		 */
		this.loadQueue = function(callback, scope) {
			this.loadScripts(queue, callback, scope);
		};

		/**
		 * Loads the specified queue of files and executes the callback ones they are loaded.
		 * This method is generally not used outside this class but it might be useful in some scenarios.
		 *
		 * @method loadScripts
		 * @param {Array} scripts Array of queue items to load.
		 * @param {function} callback Optional callback to execute ones all items are loaded.
		 * @param {Object} scope Optional scope to execute callback in.
		 */
		this.loadScripts = function(scripts, callback, scope) {
			var loadScripts;

			function execScriptLoadedCallbacks(url) {
				// Execute URL callback functions
				tinymce.each(scriptLoadedCallbacks[url], function(callback) {
					callback.func.call(callback.scope);
				});

				scriptLoadedCallbacks[url] = undef;
			};

			queueLoadedCallbacks.push({
				func : callback,
				scope : scope || this
			});

			loadScripts = function() {
				var loadingScripts = tinymce.grep(scripts);

				// Current scripts has been handled
				scripts.length = 0;

				// Load scripts that needs to be loaded
				tinymce.each(loadingScripts, function(url) {
					// Script is already loaded then execute script callbacks directly
					if (states[url] == LOADED) {
						execScriptLoadedCallbacks(url);
						return;
					}

					// Is script not loading then start loading it
					if (states[url] != LOADING) {
						states[url] = LOADING;
						loading++;

						loadScript(url, function() {
							states[url] = LOADED;
							loading--;

							execScriptLoadedCallbacks(url);

							// Load more scripts if they where added by the recently loaded script
							loadScripts();
						});
					}
				});

				// No scripts are currently loading then execute all pending queue loaded callbacks
				if (!loading) {
					tinymce.each(queueLoadedCallbacks, function(callback) {
						callback.func.call(callback.scope);
					});

					queueLoadedCallbacks.length = 0;
				}
			};

			loadScripts();
		};
	};

	// Global script loader
	tinymce.ScriptLoader = new tinymce.dom.ScriptLoader();
})(tinymce);
<|endoftext|>


<commit_before>const config = require('./config.json');
const sync = require('browser-sync');
const reload = sync.reload;

let isProd = false;
let isWatch = false;
let isServer = false;

/**
 * Default Task: watch
 */
export default async function () {
	await this.start('watch');
}

/**
 * Run a dev server & Recompile when files change
 */
export async function watch() {
	isWatch = true;
	isProd = false;
	await this.start('clean');
	await this.watch(config.templates.src, 'templates');
	await this.watch(config.scripts.src, ['lint', 'scripts']);
	await this.watch(config.styles.src, 'styles');
	await this.watch(config.images.src, 'images');
	await this.watch(config.fonts.src, 'fonts');
	await this.watch(config.html.src, 'html');
	await this.start(['extras', 'serve']);
}

/**
 * Build the production files
 */
export async function build() {
	isProd = true;
	isWatch = false;
	await this.start('clean');
	await this.start(['lint', 'images', 'fonts', 'templates', 'styles', 'html', 'extras'], {parallel: true});
	await this.start(['scripts', 'rev'], {parallel: false});
}

// ###
// # Sub-Tasks
// ###

// Delete the output directories
export async function clean() {
	await this.clear('dist');
}

// Lint javascript
export async function lint() {
	await this.source(config.scripts.src).xo({
		globals: ['document', 'angular']
	});
}

// Copy all images, compress them, then send to dest
export async function images() {
	await this.source(config.images.src)
		.target(config.images.dest, {depth: 1});

	if (isWatch && isServer) {
		reload();
	}
}

// Copy all fonts, then send to dest
export async function fonts() {
	await this.source(config.fonts.src).target(config.fonts.dest);

	if (isWatch && isServer) {
		reload();
	}
}

// Move static HTML files to dist. If isProd, minify!
export async function html() {
	const dest = config.html.dest;

	await this.source(config.html.src).target(dest);

	if (isWatch && isServer) {
		reload();
	} else if (isProd) {
		await this.source(`${dest}/*.html`)
			.htmlmin({
				removeComments: true,
				collapseWhitespace: true,
				collapseBooleanAttributes: true,
				removeAttributeQuotes: true,
				removeRedundantAttributes: true,
				removeEmptyAttributes: true,
				removeScriptTypeAttributes: true,
				removeStyleLinkTypeAttributes: true,
				removeOptionalTags: true
			})
			.target(dest);
	}
}

// Copy other root-level files
export async function extras() {
	await this.source(config.extras.src).target(config.extras.dest);
}

// Compile scripts
export async function scripts() {
	await this.source(config.scripts.src)
		.babel({
			presets: ['es2015'],
			sourceMaps: !isProd
		})
		.concat('main.js')
		.target(config.scripts.dest);

	if (isWatch && isServer) {
		reload();
	} else if (isProd) {
		return await this.start('uglify');
	}
}

export async function templates() {
	await this.source(config.templates.src)
		.ngTemplates({
			standalone: true,
			moduleName: 'app.templates',
			transformUrl: (url) => url.replace('src/app/', '')
		})
		.target(config.templates.dest);
}

// minify & optimize production js files
export async function uglify() {
	await this.source(`${config.scripts.dest}/*.js`)
		.uglify({
			compress: {
				conditionals: true,
				comparisons: true,
				booleans: true,
				loops: true,
				join_vars: true,
				drop_console: true
			}
		})
		.target(config.scripts.dest);
}

// Compile & automatically prefix stylesheets
export async function styles() {
	await this
		.source(config.styles.src)
		.sass({
			outputStyle: 'compressed'
		})
		.autoprefixer({
			browsers: [
				'ie >= 10',
				'ie_mob >= 10',
				'ff >= 30',
				'chrome >= 34',
				'safari >= 7',
				'opera >= 23',
				'ios >= 7',
				'android >= 4.4',
				'bb >= 10'
			]
		})
		.concat('main.css')
		.target(config.styles.dest);

	if (isWatch && isServer) {
		reload();
	}
}

// Revision asset names (Cache-busting)
export async function rev() {
	const src = ['scripts', 'styles', 'images'].map(type => `${paths[type].dest}/**/*`);
	return this.source(src).rev({
		base: config.html.dest,
		replace: true
	});
}

// Launch loacl serve at develop directory
export async function serve() {
	isServer = true;

	sync({
		notify: false,
		logPrefix: 'Fly',
		server: {
			baseDir: config.html.dest
		}
	});
}
<commit_msg>fix path => config<commit_after>const config = require('./config.json');
const sync = require('browser-sync');
const reload = sync.reload;

let isProd = false;
let isWatch = false;
let isServer = false;

/**
 * Default Task: watch
 */
export default async function () {
	await this.start('watch');
}

/**
 * Run a dev server & Recompile when files change
 */
export async function watch() {
	isWatch = true;
	isProd = false;
	await this.start('clean');
	await this.watch(config.templates.src, 'templates');
	await this.watch(config.scripts.src, ['lint', 'scripts']);
	await this.watch(config.styles.src, 'styles');
	await this.watch(config.images.src, 'images');
	await this.watch(config.fonts.src, 'fonts');
	await this.watch(config.html.src, 'html');
	await this.start(['extras', 'serve']);
}

/**
 * Build the production files
 */
export async function build() {
	isProd = true;
	isWatch = false;
	await this.start('clean');
	await this.start(['lint', 'images', 'fonts', 'templates', 'styles', 'html', 'extras'], {parallel: true});
	await this.start(['scripts', 'rev'], {parallel: false});
}

// ###
// # Sub-Tasks
// ###

// Delete the output directories
export async function clean() {
	await this.clear('dist');
}

// Lint javascript
export async function lint() {
	await this.source(config.scripts.src).xo({
		globals: ['document', 'angular']
	});
}

// Copy all images, compress them, then send to dest
export async function images() {
	await this.source(config.images.src)
		.target(config.images.dest, {depth: 1});

	if (isWatch && isServer) {
		reload();
	}
}

// Copy all fonts, then send to dest
export async function fonts() {
	await this.source(config.fonts.src).target(config.fonts.dest);

	if (isWatch && isServer) {
		reload();
	}
}

// Move static HTML files to dist. If isProd, minify!
export async function html() {
	const dest = config.html.dest;

	await this.source(config.html.src).target(dest);

	if (isWatch && isServer) {
		reload();
	} else if (isProd) {
		await this.source(`${dest}/*.html`)
			.htmlmin({
				removeComments: true,
				collapseWhitespace: true,
				collapseBooleanAttributes: true,
				removeAttributeQuotes: true,
				removeRedundantAttributes: true,
				removeEmptyAttributes: true,
				removeScriptTypeAttributes: true,
				removeStyleLinkTypeAttributes: true,
				removeOptionalTags: true
			})
			.target(dest);
	}
}

// Copy other root-level files
export async function extras() {
	await this.source(config.extras.src).target(config.extras.dest);
}

// Compile scripts
export async function scripts() {
	await this.source(config.scripts.src)
		.babel({
			presets: ['es2015'],
			sourceMaps: !isProd
		})
		.concat('main.js')
		.target(config.scripts.dest);

	if (isWatch && isServer) {
		reload();
	} else if (isProd) {
		return await this.start('uglify');
	}
}

export async function templates() {
	await this.source(config.templates.src)
		.ngTemplates({
			standalone: true,
			moduleName: 'app.templates',
			transformUrl: (url) => url.replace('src/app/', '')
		})
		.target(config.templates.dest);
}

// minify & optimize production js files
export async function uglify() {
	await this.source(`${config.scripts.dest}/*.js`)
		.uglify({
			compress: {
				conditionals: true,
				comparisons: true,
				booleans: true,
				loops: true,
				join_vars: true,
				drop_console: true
			}
		})
		.target(config.scripts.dest);
}

// Compile & automatically prefix stylesheets
export async function styles() {
	await this
		.source(config.styles.src)
		.sass({
			outputStyle: 'compressed'
		})
		.autoprefixer({
			browsers: [
				'ie >= 10',
				'ie_mob >= 10',
				'ff >= 30',
				'chrome >= 34',
				'safari >= 7',
				'opera >= 23',
				'ios >= 7',
				'android >= 4.4',
				'bb >= 10'
			]
		})
		.concat('main.css')
		.target(config.styles.dest);

	if (isWatch && isServer) {
		reload();
	}
}

// Revision asset names (Cache-busting)
export async function rev() {
	const src = ['scripts', 'styles', 'images'].map(type => `${config[type].dest}/**/*`);
	return this.source(src).rev({
		base: config.html.dest,
		replace: true
	});
}

// Launch loacl serve at develop directory
export async function serve() {
	isServer = true;

	sync({
		notify: false,
		logPrefix: 'Fly',
		server: {
			baseDir: config.html.dest
		}
	});
}
<|endoftext|>


<commit_before>/* global moment */
{
  'use strict';

  class DateRangePicker extends TapBase {
    start(el) {
      this.config = {
        timePicker24Hour: true,
        locale: {
          format: 'D MMM YYYY'
        }
      };

      super.start(el);

      this.init();

      if (this.config.autoUpdateInput == false) {
        this.$el.on('apply.daterangepicker', function(ev, picker) {
          $(this).val(picker.startDate.format(this.config.locale.format) + ' - ' + picker.endDate.format(this.config.locale.format));
        });
        this.$el.on('cancel.daterangepicker', function(ev, picker) {
          $(this).val('');
        });
      }
    }

    init() {
      this.$el.daterangepicker(this.config);
    }
  }

  window.GOVUKAdmin.Modules.DateRangePicker = DateRangePicker;
}
<commit_msg>Fix date-range-picker module scoping issues<commit_after>/* global moment */
{
  'use strict';

  class DateRangePicker extends TapBase {
    start(el) {
      this.config = {
        timePicker24Hour: true,
        locale: {
          format: 'D MMM YYYY'
        }
      };

      super.start(el);

      this.init();
      this.bindEvents();
    }

    init() {
      this.$el.daterangepicker(this.config);
    }

    bindEvents() {
      if (this.config.autoUpdateInput == false) {
        this.$el.on('apply.daterangepicker', (ev, picker) => {
          this.$el.val(picker.startDate.format(this.config.locale.format) + ' - ' + picker.endDate.format(this.config.locale.format));
        });
        this.$el.on('cancel.daterangepicker', (ev, picker) => {
          this.$el.val('');
        });
      }
    }
  }

  window.GOVUKAdmin.Modules.DateRangePicker = DateRangePicker;
}
<|endoftext|>


<commit_before>/**
 * Created by lwc on 2017/5/5.
 */

import React, {Component} from 'react';
import { Input, Icon, Upload, message, Modal, Progress } from 'antd';
import EmojiPicker from './chatEmoji';
import {cutStr} from './utils';

/**
 * ChatSend Component
 *
 *
 */
class ChatSend extends Component{

    constructor(props){
        super(props);
        this.state = {
            percent: 0,
            isSendReady: false,
            isEmojiShow: false,
            textereaValue: "",
            socket: props.socket,
            isShowProcess: false
        };

        this.sendMessage = this.sendMessage.bind(this);
        this.emojiBtnHandle = this.emojiBtnHandle.bind(this);
        this.addEmojiHandle = this.addEmojiHandle.bind(this);
        this.textChangeHandle = this.textChangeHandle.bind(this);
        this.textFocusHandle = this.textFocusHandle.bind(this);
        this.blurHandle = this.blurHandle.bind(this);
        this.rateHandle = this.rateHandle.bind(this);
    }
    /***
     *
     * @param e
     */
    textChangeHandle(e){
        this.setState({
            textereaValue: e.target.value.substr(0, 512)
        });
        this.props.statusHandle(1);
    }
    blurHandle(){
        this.props.statusHandle(2);
    }
    textFocusHandle(){
        this.setState({
            isEmojiShow: false
        });
    }
    /***
     *
     * @param e
     */

    sendMessage(e){
        e.preventDefault();
        var msgVal = e.target.value,
            msg = msgVal.replace(/</g, "<").replace(/>/g, ">").replace(/ /gi, ' ').replace(/\n/gi, '#');

        if(msgVal.length > 0){
            this.props.sendMessage(cutStr(msg, 256));
        }
        this.setState({
            isEmojiShow: false,
            textereaValue: "",
            isSendReady: true
        });
    }
    /***
     *
     */
    emojiBtnHandle(){
        this.setState({
            isEmojiShow: !this.state.isEmojiShow
        })
    }

    /***
     *
     * @param emoj
     */
    addEmojiHandle(emoji){
        this.insertToCursorPosition(this.state.textereaValue, emoji);
    }

    insertToCursorPosition(s1, s2){
        var obj = document.getElementsByClassName("chat-textarea")[0];
        obj.focus();
        if(document.selection) {
            var sel = document.selection.createRange();
            sel.text = s2;
        }else if(typeof obj.selectionStart === 'number' && typeof obj.selectionEnd === 'number') {
            var startPos = obj.selectionStart,
                endPos = obj.selectionEnd,
                cursorPos = startPos,
                tmpStr = s1;

            var s3 = tmpStr.substring(0, startPos) + s2 + tmpStr.substring(endPos, tmpStr.length);

            this.setState({
                textereaValue: s3
            });
            cursorPos += s2.length;
            obj.selectionStart = obj.selectionEnd = cursorPos;
        }else{
             this.setState({
                textereaValue: this.state.textereaValue+ s2 +" "
             });
        }
    }
    rateHandle(e){
        var that = this;
        Modal.confirm({
            title: 'Invite user rate',
            okText: 'Yes',
            cancelText: 'Cancel',
            content: (

Are you sure invite the user rate?

            ),
            onOk(){
                message.success('Invitation has been sent!', 4);
                that.props.socket && that.props.socket.emit('cs.rate', that.props.cid, function(success){
                    if(success){
                    }else{
                    }
                });
            }
        });
    }

    render(){
        var sendMessage = this.props.sendMessage,
            that = this;

        const props = {
            name: 'image',
            action: '/messages/customer/'+this.props.cid+'/cs/'+this.props.csid+'/image',
            accept: 'image/*',
            headers: {
                authorization: 'authorization-text',
            },
            onChange(info) {
                var status = info.file.status;

                if(status === 'uploading'){
                    if(info.event){
                        that.setState({
                            isShowProcess: true,
                            percent: info.event.percent
                        });
                    }
                }else if (status === 'done') {
                    if(200 === info.file.response.code){
                        sendMessage(info.file.response.msg.resized+'|'+info.file.response.msg.original);
                    }
                    message.success(info.file.name+' file uploaded successfully', 2, function(){
                        that.setState({
                            isShowProcess: false
                        });
                    });
                } else if (status === 'error') {
                    message.error(info.file.name+' file upload failed.', 2, function(){
                        that.setState({
                            isShowProcess: false
                        });
                    });
                }
            }
        };
        return (

                <Progress type="circle" percent={this.state.percent} className="upload-process" width={60} style={{display: this.state.isShowProcess ? 'block' : 'none'}} />

                        <Icon onClick={this.emojiBtnHandle} className={"emoji-icon "+(this.state.isEmojiShow ? 'active' : '')} />
                        {
                            this.state.isEmojiShow &&  <EmojiPicker addEmojiHandle={this.addEmojiHandle} />
                        }

                        <Upload {...props}>
                            <Icon type="folder" className="upload-icon" />
                        </Upload>

                <Input
                    type="textarea"
                    className="chat-textarea"
                    onPressEnter={this.sendMessage}
                    placeholder={this.state.isSendReady ? "" : "Input text and press enter to send(max 256 words)"}
                    onChange={this.textChangeHandle}
                    value={this.state.textereaValue}
                    onFocus={this.textFocusHandle}
                    onBlur={this.blurHandle}
                    maxLength="256"
                    />

        );
    }
}

export default ChatSend;<commit_msg>upload percentage<commit_after>/**
 * Created by lwc on 2017/5/5.
 */

import React, {Component} from 'react';
import { Input, Icon, Upload, message, Modal, Progress } from 'antd';
import EmojiPicker from './chatEmoji';
import {cutStr} from './utils';

/**
 * ChatSend Component
 *
 *
 */
class ChatSend extends Component{

    constructor(props){
        super(props);
        this.state = {
            percent: 0,
            isSendReady: false,
            isEmojiShow: false,
            textereaValue: "",
            socket: props.socket,
            isShowProcess: false
        };

        this.sendMessage = this.sendMessage.bind(this);
        this.emojiBtnHandle = this.emojiBtnHandle.bind(this);
        this.addEmojiHandle = this.addEmojiHandle.bind(this);
        this.textChangeHandle = this.textChangeHandle.bind(this);
        this.textFocusHandle = this.textFocusHandle.bind(this);
        this.blurHandle = this.blurHandle.bind(this);
        this.rateHandle = this.rateHandle.bind(this);
    }
    /***
     *
     * @param e
     */
    textChangeHandle(e){
        this.setState({
            textereaValue: e.target.value.substr(0, 512)
        });
        this.props.statusHandle(1);
    }
    blurHandle(){
        this.props.statusHandle(2);
    }
    textFocusHandle(){
        this.setState({
            isEmojiShow: false
        });
    }
    /***
     *
     * @param e
     */

    sendMessage(e){
        e.preventDefault();
        var msgVal = e.target.value,
            msg = msgVal.replace(/</g, "<").replace(/>/g, ">").replace(/ /gi, ' ').replace(/\n/gi, '#');

        if(msgVal.length > 0){
            this.props.sendMessage(cutStr(msg, 256));
        }
        this.setState({
            isEmojiShow: false,
            textereaValue: "",
            isSendReady: true
        });
    }
    /***
     *
     */
    emojiBtnHandle(){
        this.setState({
            isEmojiShow: !this.state.isEmojiShow
        })
    }

    /***
     *
     * @param emoj
     */
    addEmojiHandle(emoji){
        this.insertToCursorPosition(this.state.textereaValue, emoji);
    }

    insertToCursorPosition(s1, s2){
        var obj = document.getElementsByClassName("chat-textarea")[0];
        obj.focus();
        if(document.selection) {
            var sel = document.selection.createRange();
            sel.text = s2;
        }else if(typeof obj.selectionStart === 'number' && typeof obj.selectionEnd === 'number') {
            var startPos = obj.selectionStart,
                endPos = obj.selectionEnd,
                cursorPos = startPos,
                tmpStr = s1;

            var s3 = tmpStr.substring(0, startPos) + s2 + tmpStr.substring(endPos, tmpStr.length);

            this.setState({
                textereaValue: s3
            });
            cursorPos += s2.length;
            obj.selectionStart = obj.selectionEnd = cursorPos;
        }else{
             this.setState({
                textereaValue: this.state.textereaValue+ s2 +" "
             });
        }
    }
    rateHandle(e){
        var that = this;
        Modal.confirm({
            title: 'Invite user rate',
            okText: 'Yes',
            cancelText: 'Cancel',
            content: (

Are you sure invite the user rate?

            ),
            onOk(){
                message.success('Invitation has been sent!', 4);
                that.props.socket && that.props.socket.emit('cs.rate', that.props.cid, function(success){
                    if(success){
                    }else{
                    }
                });
            }
        });
    }

    render(){
        var sendMessage = this.props.sendMessage,
            that = this;

        const props = {
            name: 'image',
            action: '/messages/customer/'+this.props.cid+'/cs/'+this.props.csid+'/image',
            accept: 'image/*',
            headers: {
                authorization: 'authorization-text',
            },
            onChange(info) {
                var status = info.file.status;

                if(status === 'uploading'){
                    if(info.event){
                        that.setState({
                            isShowProcess: true,
                            percent: Math.ceil(info.event.percent)
                        });
                    }
                }else if (status === 'done') {
                    if(200 === info.file.response.code){
                        sendMessage(info.file.response.msg.resized+'|'+info.file.response.msg.original);
                    }
                    message.success(info.file.name+' file uploaded successfully', 2, function(){
                        that.setState({
                            isShowProcess: false
                        });
                    });
                } else if (status === 'error') {
                    message.error(info.file.name+' file upload failed.', 2, function(){
                        that.setState({
                            isShowProcess: false
                        });
                    });
                }
            }
        };
        return (

                <Progress type="circle" percent={this.state.percent} className="upload-process" width={60} style={{display: this.state.isShowProcess ? 'block' : 'none'}} />

                        <Icon onClick={this.emojiBtnHandle} className={"emoji-icon "+(this.state.isEmojiShow ? 'active' : '')} />
                        {
                            this.state.isEmojiShow &&  <EmojiPicker addEmojiHandle={this.addEmojiHandle} />
                        }

                        <Upload {...props}>
                            <Icon type="folder" className="upload-icon" />
                        </Upload>

                <Input
                    type="textarea"
                    className="chat-textarea"
                    onPressEnter={this.sendMessage}
                    placeholder={this.state.isSendReady ? "" : "Input text and press enter to send(max 256 words)"}
                    onChange={this.textChangeHandle}
                    value={this.state.textereaValue}
                    onFocus={this.textFocusHandle}
                    onBlur={this.blurHandle}
                    maxLength="256"
                    />

        );
    }
}

export default ChatSend;<|endoftext|>


<commit_before>TC.control = TC.control || {};

if (!TC.Control) {
    TC.syncLoadJS(TC.apiLocation + 'TC/Control.js');
}

TC.control.MapContents = function () {
    var self = this;

    TC.Control.apply(self, arguments);

    self.layerTrees = {};
};

TC.inherit(TC.control.MapContents, TC.Control);

(function () {
    var ctlProto = TC.control.MapContents.prototype;

    ctlProto.CLASS = 'tc-ctl-mc';

    var _dataKeys = {
        img: 'tcImg'
    };

    ctlProto.render = function (callback) {
        var self = this;
        if (self.map) {
            self.renderData(self.map.getLayerTree(), callback);
        }
    };

    ctlProto.register = function (map) {
        var self = this;
        TC.Control.prototype.register.call(self, map);
        self.render(function () {

            for (var i = 0, len = map.layers.length; i < len; i++) {
                self.updateLayerTree(map.layers[i]);
            }

            map.on(TC.Consts.event.ZOOM, function () {
                self.updateScale();
            }).on(TC.Consts.event.UPDATEPARAMS, function (e) {
                var names = e.layer.names;
                var containsName = function containsName(node) {
                    var result = false;
                    if (node) {
                        if ($.inArray(node.name, names) >= 0) {
                            result = true;
                        }
                        else {
                            for (var i = 0; i < node.children.length; i++) {
                                if (containsName(node.children[i])) {
                                    result = true;
                                    break;
                                }
                            }
                        }
                    }
                    return result;
                };
                if (containsName(self.layerTrees[e.layer.id]) || names.length === 0) {
                    self.update();
                }
                else {
                    self.updateLayerTree(e.layer);
                }
            }).on(TC.Consts.event.LAYERVISIBILITY, function (e) {
                self.updateLayerVisibility(e.layer);
            }).on(TC.Consts.event.LAYERADD, function (e) {
                self.updateLayerTree(e.layer);
            }).on(TC.Consts.event.VECTORUPDATE + ' ' + TC.Consts.event.FEATUREADD + ' ' + TC.Consts.event.FEATURESADD, function (e) {
                // Se introduce un timeout porque pueden venir muchos eventos de este tipo seguidos y no tiene sentido actualizar con cada uno
                if (self._updateLayerTreeTimeout) {
                    clearTimeout(self._updateLayerTreeTimeout);
                }
                self._updateLayerTreeTimeout = setTimeout(function () {
                    if (self.map.workLayers.indexOf(e.layer) > -1) {
                    // GLS: Validamos si la capa que ha provocado el evento sigue en worklayers, si es borrada debido a la espera del timeout el TOC puede reflejar capas que ya no están
                        self.updateLayerTree(e.layer);
                        delete self._updateLayerTreeTimeout;
                    }
                }, 100);
            }).on(TC.Consts.event.LAYERREMOVE, function (e) {
                self.removeLayer(e.layer);
            });
        });
    };

    ctlProto.updateScale = function () {
    };

    ctlProto.updateLayerVisibility = function (layer) {
    };

    ctlProto.updateLayerTree = function (layer) {
        this.layerTrees[layer.id] = layer.getTree();
    };

    ctlProto.removeLayer = function (layer) {
        this.update();
    };

    var isGetLegendGraphic = function (url) {
        return /[&?]REQUEST=getLegendGraphic/i.test(url);
    };

    var setImgSrc = function ($img, src, SSLSupported) {
        var ERROR = 'error.tc';
        if (TC.Cfg.proxy) {
            $img.off(ERROR).on(ERROR, function () {
                $img.attr('src', TC.proxify(src));
            });
        }
        var startIdx = src.indexOf('//');
        if (TC.Util.isSecureURL(document.location.href) && !TC.Util.isSecureURL(src)) {
            var srcSSL = "";
            if (SSLSupported == true)
                srcSSL = src.replace(/^(f|ht)tp?:\/\//i, "https://");
            else if (TC.isUsingServiceWorker())
                srcSSL = TC.proxify(src)
            else
                srcSSL = src;
            $img.attr('src', srcSSL);
        }
        else {
            $img.attr('src', startIdx < 0 ? src : src.substr(startIdx));
        }
    };

    /**
     * Carga y le da estilo a la imagen de la leyenda.
     * @param {string} requestMethod Si queremos pedir la imagen de la leyenda por POST, podemos especificarlo utilizando el parámetro requestMethod.
     */
    ctlProto.styleLegendImage = function ($img, layer) {
        if (!$img.attr('src')) {
            var imgSrc = $img.data(_dataKeys.img);
            if (layer && layer.options.method && layer.options.method === "POST") {
                layer.getLegendGraphicImage()
                .done(function (src) {
                    setImgSrc($img, src);
                })
                .fail(function (err) { TC.error(err); });
            } else {
                if (isGetLegendGraphic(imgSrc)) {
                    var $watch = $img.parent();
                    // A\u00f1adimos el par\u00e1metro que define el estilo de los textos en la imagen
                    var colorStr = $watch.css('color');
                    // Convertimos el color de formato rgb(r,g,b) a 0xRRGGBB
                    var openIdx = colorStr.indexOf('(');
                    var closeIdx = colorStr.indexOf(')');
                    if (openIdx >= 0 && closeIdx > openIdx) {
                        color = colorStr
                            .substr(0, closeIdx)
                            .substr(openIdx + 1)
                            .split(',');
                        colorStr = '0x';
                        for (var i = 0; i < 3; i++) {
                            var component = parseInt(color[i]).toString(16);
                            colorStr += component.length === 1 ? '0' + component : component;
                        }
                    }
                    else {
                        colorStr.replace('#', '0x');
                    }
                    imgSrc += '&LEGEND_OPTIONS=fontName:' + $watch.css('font-family') +
                        ';fontSize:' + parseInt($watch.css('font-size')) +
                        ';fontColor:' + colorStr +
                        ';fontAntiAliasing:true';
                    $img.data(_dataKeys.img, imgSrc);
                }
                setImgSrc($img, imgSrc, layer.usesSSL);
            }
        }
    };

})();<commit_msg>Upgrade URL filter<commit_after>TC.control = TC.control || {};

if (!TC.Control) {
    TC.syncLoadJS(TC.apiLocation + 'TC/Control.js');
}

TC.control.MapContents = function () {
    var self = this;

    TC.Control.apply(self, arguments);

    self.layerTrees = {};
};

TC.inherit(TC.control.MapContents, TC.Control);

(function () {
    var ctlProto = TC.control.MapContents.prototype;

    ctlProto.CLASS = 'tc-ctl-mc';

    var _dataKeys = {
        img: 'tcImg'
    };

    ctlProto.render = function (callback) {
        var self = this;
        if (self.map) {
            self.renderData(self.map.getLayerTree(), callback);
        }
    };

    ctlProto.register = function (map) {
        var self = this;
        TC.Control.prototype.register.call(self, map);
        self.render(function () {

            for (var i = 0, len = map.layers.length; i < len; i++) {
                self.updateLayerTree(map.layers[i]);
            }

            map.on(TC.Consts.event.ZOOM, function () {
                self.updateScale();
            }).on(TC.Consts.event.UPDATEPARAMS, function (e) {
                var names = e.layer.names;
                var containsName = function containsName(node) {
                    var result = false;
                    if (node) {
                        if ($.inArray(node.name, names) >= 0) {
                            result = true;
                        }
                        else {
                            for (var i = 0; i < node.children.length; i++) {
                                if (containsName(node.children[i])) {
                                    result = true;
                                    break;
                                }
                            }
                        }
                    }
                    return result;
                };
                if (containsName(self.layerTrees[e.layer.id]) || names.length === 0) {
                    self.update();
                }
                else {
                    self.updateLayerTree(e.layer);
                }
            }).on(TC.Consts.event.LAYERVISIBILITY, function (e) {
                self.updateLayerVisibility(e.layer);
            }).on(TC.Consts.event.LAYERADD, function (e) {
                self.updateLayerTree(e.layer);
            }).on(TC.Consts.event.VECTORUPDATE + ' ' + TC.Consts.event.FEATUREADD + ' ' + TC.Consts.event.FEATURESADD, function (e) {
                // Se introduce un timeout porque pueden venir muchos eventos de este tipo seguidos y no tiene sentido actualizar con cada uno
                if (self._updateLayerTreeTimeout) {
                    clearTimeout(self._updateLayerTreeTimeout);
                }
                self._updateLayerTreeTimeout = setTimeout(function () {
                    if (self.map.workLayers.indexOf(e.layer) > -1) {
                    // GLS: Validamos si la capa que ha provocado el evento sigue en worklayers, si es borrada debido a la espera del timeout el TOC puede reflejar capas que ya no están
                        self.updateLayerTree(e.layer);
                        delete self._updateLayerTreeTimeout;
                    }
                }, 100);
            }).on(TC.Consts.event.LAYERREMOVE, function (e) {
                self.removeLayer(e.layer);
            });
        });
    };

    ctlProto.updateScale = function () {
    };

    ctlProto.updateLayerVisibility = function (layer) {
    };

    ctlProto.updateLayerTree = function (layer) {
        this.layerTrees[layer.id] = layer.getTree();
    };

    ctlProto.removeLayer = function (layer) {
        this.update();
    };

    var isGetLegendGraphic = function (url) {
        return /[&?]REQUEST=getLegendGraphic/i.test(url);
    };

    var setImgSrc = function ($img, src, SSLSupported) {
        var ERROR = 'error.tc';
        if (TC.Cfg.proxy) {
            $img.off(ERROR).on(ERROR, function () {
                $img.attr('src', TC.proxify(src));
            });
        }
        var urlStartRegEx = /^(https?:)?\/\//i;
        if (TC.Util.isSecureURL(document.location.href) && !TC.Util.isSecureURL(src)) {
            var srcSSL = "";
            if (SSLSupported == true)
                srcSSL = src.replace(urlStartRegEx, "https://");
            else if (TC.isUsingServiceWorker())
                srcSSL = TC.proxify(src)
            else
                srcSSL = src;
            $img.attr('src', srcSSL);
        }
        else {
            // Si es una ruta absoluta quitamos el protocolo
            $img.attr('src', urlStartRegEx.test(src) ? src.substr(src.indexOf('//')) : src);
        }
    };

    /**
     * Carga y le da estilo a la imagen de la leyenda.
     * @param {string} requestMethod Si queremos pedir la imagen de la leyenda por POST, podemos especificarlo utilizando el parámetro requestMethod.
     */
    ctlProto.styleLegendImage = function ($img, layer) {
        if (!$img.attr('src')) {
            var imgSrc = $img.data(_dataKeys.img);
            if (layer && layer.options.method && layer.options.method === "POST") {
                layer.getLegendGraphicImage()
                .done(function (src) {
                    setImgSrc($img, src);
                })
                .fail(function (err) { TC.error(err); });
            } else {
                if (isGetLegendGraphic(imgSrc)) {
                    var $watch = $img.parent();
                    // A\u00f1adimos el par\u00e1metro que define el estilo de los textos en la imagen
                    var colorStr = $watch.css('color');
                    // Convertimos el color de formato rgb(r,g,b) a 0xRRGGBB
                    var openIdx = colorStr.indexOf('(');
                    var closeIdx = colorStr.indexOf(')');
                    if (openIdx >= 0 && closeIdx > openIdx) {
                        color = colorStr
                            .substr(0, closeIdx)
                            .substr(openIdx + 1)
                            .split(',');
                        colorStr = '0x';
                        for (var i = 0; i < 3; i++) {
                            var component = parseInt(color[i]).toString(16);
                            colorStr += component.length === 1 ? '0' + component : component;
                        }
                    }
                    else {
                        colorStr.replace('#', '0x');
                    }
                    imgSrc += '&LEGEND_OPTIONS=fontName:' + $watch.css('font-family') +
                        ';fontSize:' + parseInt($watch.css('font-size')) +
                        ';fontColor:' + colorStr +
                        ';fontAntiAliasing:true';
                    $img.data(_dataKeys.img, imgSrc);
                }
                setImgSrc($img, imgSrc, layer.usesSSL);
            }
        }
    };

})();<|endoftext|>


<commit_before>'use strict';

var intervieweeSchema, Interviewee,
    mongoose        = require('mongoose'),
    //mongooseHistory = require('mongoose-history'),
    //options = {customCollectionName: "interviewee_hst"},
    Schema          = mongoose.Schema,
    ObjectId        = Schema.Types.ObjectId,
    modificationSchema = new Schema({
        modifiedBy: ObjectId,
        modifiedDate: {type: Date, default: Date.now}
    });

intervieweeSchema = new Schema({
    firstName: {
        type: String,
        required: '{PATH} is required!'},
    lastName: {
        type: String,
        required: '{PATH} is required!'},
    email: {
        type: String,
        required: '{PATH} is required!',
        unique: true
    },
    phone: String,
    role: {
        type: String,
        required: '{PATH} is required!'}, // gov, industry, CSO, expert or other
    title: String,
    salutation: String,
    organization: String,
    //tool mapping
    assessments: [String],
    questions: [ObjectId],
    answers: [String],
    users: [ObjectId],
    createdBy: ObjectId,
    creationDate: {
        type: Date,
        default: Date.now},
    modified: [modificationSchema]
});

//intervieweeSchema.plugin(mongooseHistory, options);

Interviewee = mongoose.model('Interviewee', intervieweeSchema);

function createDefaultInterviewees() {
    Interviewee.find({}).exec(function (err, collection) {
        if (collection.length === 0) {
            Interviewee.create({
                firstName: "Steve",
                lastName: "Jobs",
                email: "sj@gmail.com",
                phone: "666-666-6666",
                role: "government", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Fred",
                lastName: "Flinstone",
                email: "ff@gmail.com",
                phone: "666-666-6666",
                role: "industry", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Jack",
                lastName: "Jill",
                email: "jj@gmail.com",
                phone: "666-666-6666",
                role: "cso", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Foo",
                lastName: "Bar",
                email: "fb@gmail.com",
                phone: "666-666-6666",
                role: "expert", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Seven",
                lastName: "Up",
                email: "su@gmail.com",
                phone: "666-666-6666",
                role: "other", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
        }
    });
}

exports.createDefaultInterviewees = createDefaultInterviewees;<commit_msg>removed email requirement on new interview on mongoose model. closes #216.<commit_after>'use strict';

var intervieweeSchema, Interviewee,
    mongoose        = require('mongoose'),
    //mongooseHistory = require('mongoose-history'),
    //options = {customCollectionName: "interviewee_hst"},
    Schema          = mongoose.Schema,
    ObjectId        = Schema.Types.ObjectId,
    modificationSchema = new Schema({
        modifiedBy: ObjectId,
        modifiedDate: {type: Date, default: Date.now}
    });

intervieweeSchema = new Schema({
    firstName: {
        type: String,
        required: '{PATH} is required!'},
    lastName: {
        type: String,
        required: '{PATH} is required!'},
    email: String,
    phone: String,
    role: {
        type: String,
        required: '{PATH} is required!'}, // gov, industry, CSO, expert or other
    title: String,
    salutation: String,
    organization: String,
    //tool mapping
    assessments: [String],
    questions: [ObjectId],
    answers: [String],
    users: [ObjectId],
    createdBy: ObjectId,
    creationDate: {
        type: Date,
        default: Date.now},
    modified: [modificationSchema]
});

//intervieweeSchema.plugin(mongooseHistory, options);

Interviewee = mongoose.model('Interviewee', intervieweeSchema);

function createDefaultInterviewees() {
    Interviewee.find({}).exec(function (err, collection) {
        if (collection.length === 0) {
            Interviewee.create({
                firstName: "Steve",
                lastName: "Jobs",
                email: "sj@gmail.com",
                phone: "666-666-6666",
                role: "government", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Fred",
                lastName: "Flinstone",
                email: "ff@gmail.com",
                phone: "666-666-6666",
                role: "industry", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Jack",
                lastName: "Jill",
                email: "jj@gmail.com",
                phone: "666-666-6666",
                role: "cso", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Foo",
                lastName: "Bar",
                email: "fb@gmail.com",
                phone: "666-666-6666",
                role: "expert", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
            Interviewee.create({
                firstName: "Seven",
                lastName: "Up",
                email: "su@gmail.com",
                phone: "666-666-6666",
                role: "other", // gov, industry, CSO, expert or other
                assessments: ["AF-2015-PI"],
                questions: [],
                answers: [],
                users: [],
                creationDate: Date.now()
            });
        }
    });
}

exports.createDefaultInterviewees = createDefaultInterviewees;<|endoftext|>


<commit_before>let AppDomain = "org.standardnotes.sn";
var dateFormatter;

class Item {

  constructor(json_obj = {}) {
    this.appData = {};
    this.updateFromJSON(json_obj);
    this.observers = [];

    if(!this.uuid) {
      this.uuid = SFJS.crypto.generateUUIDSync();
    }
  }

  static sortItemsByDate(items) {
    items.sort(function(a,b){
      return new Date(b.created_at) - new Date(a.created_at);
    });
  }

  get contentObject() {
    if(!this.content) {
      return {};
    }

    if(this.content !== null && typeof this.content === 'object') {
      // this is the case when mapping localStorage content, in which case the content is already parsed
      return this.content;
    }

    try {
      return JSON.parse(this.content);
    } catch (e) {
      console.log("Error parsing json", e, this);
      return {};
    }
  }

  updateFromJSON(json) {
    _.merge(this, json);

    if(this.created_at) {
      this.created_at = new Date(this.created_at);
      this.updated_at = new Date(this.updated_at);
    } else {
      this.created_at = new Date();
      this.updated_at = new Date();
    }

    // Allows the getter to be re-invoked
    this._client_updated_at = null;

    if(json.content) {
      this.mapContentToLocalProperties(this.contentObject);
    } else if(json.deleted == true) {
      this.handleDeletedContent();
    }
  }

  refreshContentObject() {
    // Before an item can be duplicated or cloned, we must update this.content (if it is an object) with the object's
    // current physical properties, because updateFromJSON, which is what all new items must go through,
    // will call this.mapContentToLocalProperties(this.contentObject), which may have stale values if not explicitly updated.

    this.content = this.structureParams();
  }

  /* Allows the item to handle the case where the item is deleted and the content is null */
  handleDeletedContent() {
    // Subclasses can override
  }

  setDirty(dirty, dontUpdateClientDate) {
    this.dirty = dirty;

    // Allows the syncManager to check if an item has been marked dirty after a sync has been started
    // This prevents it from clearing it as a dirty item after sync completion, if someone else has marked it dirty
    // again after an ongoing sync.
    if(!this.dirtyCount) { this.dirtyCount = 0; }
    if(dirty) {
      this.dirtyCount++;
    } else {
      this.dirtyCount = 0;
    }

    if(dirty && !dontUpdateClientDate) {
      // Set the client modified date to now if marking the item as dirty
      this.client_updated_at = new Date();
    } else if(!this.hasRawClientUpdatedAtValue()) {
      // copy updated_at
      this.client_updated_at = new Date(this.updated_at);
    }

    if(dirty) {
      this.notifyObserversOfChange();
    }
  }

  markAllReferencesDirty(dontUpdateClientDate) {
    this.allReferencedObjects().forEach(function(reference){
      reference.setDirty(true, dontUpdateClientDate);
    })
  }

  addObserver(observer, callback) {
    if(!_.find(this.observers, observer)) {
      this.observers.push({observer: observer, callback: callback});
    }
  }

  removeObserver(observer) {
    _.remove(this.observers, {observer: observer})
  }

  notifyObserversOfChange() {
    for(var observer of this.observers) {
      observer.callback(this);
    }
  }

  mapContentToLocalProperties(contentObj) {
    if(contentObj.appData) {
      this.appData = contentObj.appData;
    }
    if(!this.appData) { this.appData = {}; }
  }

  createContentJSONFromProperties() {
    return this.structureParams();
  }

  referenceParams() {
    // must override
  }

  structureParams() {
    return {
      references: this.referenceParams(),
      appData: this.appData
    }
  }

  addItemAsRelationship(item) {
    // must override
  }

  removeItemAsRelationship(item) {
    // must override
  }

  isBeingRemovedLocally() {

  }

  removeAndDirtyAllRelationships() {
    // must override
    this.setDirty(true);
  }

  removeReferencesNotPresentIn(references) {

  }

  mergeMetadataFromItem(item) {
    _.merge(this, _.omit(item, ["content"]));
  }

  informReferencesOfUUIDChange(oldUUID, newUUID) {
    // optional override
  }

  potentialItemOfInterestHasChangedItsUUID(newItem, oldUUID, newUUID) {
    // optional override
  }

  allReferencedObjects() {
    // must override
    return [];
  }

  doNotEncrypt() {
    return false;
  }

  /*
  App Data
  */

  setDomainDataItem(key, value, domain) {
    var data = this.appData[domain];
    if(!data) {
      data = {}
    }
    data[key] = value;
    this.appData[domain] = data;
  }

  getDomainDataItem(key, domain) {
    var data = this.appData[domain];
    if(data) {
      return data[key];
    } else {
      return null;
    }
  }

  setAppDataItem(key, value) {
    this.setDomainDataItem(key, value, AppDomain);
  }

  getAppDataItem(key) {
    return this.getDomainDataItem(key, AppDomain);
  }

  get pinned() {
    return this.getAppDataItem("pinned");
  }

  get archived() {
    return this.getAppDataItem("archived");
  }

  get locked() {
    return this.getAppDataItem("locked");
  }

  hasRawClientUpdatedAtValue() {
    return this.getAppDataItem("client_updated_at") != null;
  }

  get client_updated_at() {
    if(!this._client_updated_at) {
      var saved = this.getAppDataItem("client_updated_at");
      if(saved) {
        this._client_updated_at = new Date(saved);
      } else {
        this._client_updated_at = new Date(this.updated_at);
      }
    }
    return this._client_updated_at;
  }

  set client_updated_at(date) {
    this._client_updated_at = date;

    this.setAppDataItem("client_updated_at", date);
  }

  /*
    During sync conflicts, when determing whether to create a duplicate for an item, we can omit keys that have no
    meaningful weight and can be ignored. For example, if one component has active = true and another component has active = false,
    it would be silly to duplicate them, so instead we ignore this.
   */
  keysToIgnoreWhenCheckingContentEquality() {
    return [];
  }

  isItemContentEqualWith(otherItem) {
    let omit = (obj, keys) => {
      for(var key of keys) {
        delete obj[key];
      }
      return obj;
    }
    var left = omit(this.structureParams(), this.keysToIgnoreWhenCheckingContentEquality());
    var right = omit(otherItem.structureParams(), otherItem.keysToIgnoreWhenCheckingContentEquality());

    return JSON.stringify(left) === JSON.stringify(right)
  }

  /*
  Dates
  */

  createdAtString() {
    return this.dateToLocalizedString(this.created_at);
  }

  updatedAtString() {
    return this.dateToLocalizedString(this.client_updated_at);
  }

  dateToLocalizedString(date) {
    if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
      if (!dateFormatter) {
        var locale = (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;
        dateFormatter = new Intl.DateTimeFormat(locale, {
          year: 'numeric',
          month: 'short',
          day: '2-digit',
          weekday: 'long',
          hour: '2-digit',
          minute: '2-digit',
        });
      }
      return dateFormatter.format(date);
    } else {
      // IE < 11, Safari <= 9.0.
      // In English, this generates the string most similar to
      // the toLocaleDateString() result above.
      return date.toDateString() + ' ' + date.toLocaleTimeString();
    }
  }

}
<commit_msg>Ignore client_updated_at when checking for equality<commit_after>let AppDomain = "org.standardnotes.sn";
var dateFormatter;

class Item {

  constructor(json_obj = {}) {
    this.appData = {};
    this.updateFromJSON(json_obj);
    this.observers = [];

    if(!this.uuid) {
      this.uuid = SFJS.crypto.generateUUIDSync();
    }
  }

  static sortItemsByDate(items) {
    items.sort(function(a,b){
      return new Date(b.created_at) - new Date(a.created_at);
    });
  }

  get contentObject() {
    if(!this.content) {
      return {};
    }

    if(this.content !== null && typeof this.content === 'object') {
      // this is the case when mapping localStorage content, in which case the content is already parsed
      return this.content;
    }

    try {
      return JSON.parse(this.content);
    } catch (e) {
      console.log("Error parsing json", e, this);
      return {};
    }
  }

  updateFromJSON(json) {
    _.merge(this, json);

    if(this.created_at) {
      this.created_at = new Date(this.created_at);
      this.updated_at = new Date(this.updated_at);
    } else {
      this.created_at = new Date();
      this.updated_at = new Date();
    }

    // Allows the getter to be re-invoked
    this._client_updated_at = null;

    if(json.content) {
      this.mapContentToLocalProperties(this.contentObject);
    } else if(json.deleted == true) {
      this.handleDeletedContent();
    }
  }

  refreshContentObject() {
    // Before an item can be duplicated or cloned, we must update this.content (if it is an object) with the object's
    // current physical properties, because updateFromJSON, which is what all new items must go through,
    // will call this.mapContentToLocalProperties(this.contentObject), which may have stale values if not explicitly updated.

    this.content = this.structureParams();
  }

  /* Allows the item to handle the case where the item is deleted and the content is null */
  handleDeletedContent() {
    // Subclasses can override
  }

  setDirty(dirty, dontUpdateClientDate) {
    this.dirty = dirty;

    // Allows the syncManager to check if an item has been marked dirty after a sync has been started
    // This prevents it from clearing it as a dirty item after sync completion, if someone else has marked it dirty
    // again after an ongoing sync.
    if(!this.dirtyCount) { this.dirtyCount = 0; }
    if(dirty) {
      this.dirtyCount++;
    } else {
      this.dirtyCount = 0;
    }

    if(dirty && !dontUpdateClientDate) {
      // Set the client modified date to now if marking the item as dirty
      this.client_updated_at = new Date();
    } else if(!this.hasRawClientUpdatedAtValue()) {
      // copy updated_at
      this.client_updated_at = new Date(this.updated_at);
    }

    if(dirty) {
      this.notifyObserversOfChange();
    }
  }

  markAllReferencesDirty(dontUpdateClientDate) {
    this.allReferencedObjects().forEach(function(reference){
      reference.setDirty(true, dontUpdateClientDate);
    })
  }

  addObserver(observer, callback) {
    if(!_.find(this.observers, observer)) {
      this.observers.push({observer: observer, callback: callback});
    }
  }

  removeObserver(observer) {
    _.remove(this.observers, {observer: observer})
  }

  notifyObserversOfChange() {
    for(var observer of this.observers) {
      observer.callback(this);
    }
  }

  mapContentToLocalProperties(contentObj) {
    if(contentObj.appData) {
      this.appData = contentObj.appData;
    }
    if(!this.appData) { this.appData = {}; }
  }

  createContentJSONFromProperties() {
    return this.structureParams();
  }

  referenceParams() {
    // must override
  }

  structureParams() {
    return {
      references: this.referenceParams(),
      appData: this.appData
    }
  }

  addItemAsRelationship(item) {
    // must override
  }

  removeItemAsRelationship(item) {
    // must override
  }

  isBeingRemovedLocally() {

  }

  removeAndDirtyAllRelationships() {
    // must override
    this.setDirty(true);
  }

  removeReferencesNotPresentIn(references) {

  }

  mergeMetadataFromItem(item) {
    _.merge(this, _.omit(item, ["content"]));
  }

  informReferencesOfUUIDChange(oldUUID, newUUID) {
    // optional override
  }

  potentialItemOfInterestHasChangedItsUUID(newItem, oldUUID, newUUID) {
    // optional override
  }

  allReferencedObjects() {
    // must override
    return [];
  }

  doNotEncrypt() {
    return false;
  }

  /*
  App Data
  */

  setDomainDataItem(key, value, domain) {
    var data = this.appData[domain];
    if(!data) {
      data = {}
    }
    data[key] = value;
    this.appData[domain] = data;
  }

  getDomainDataItem(key, domain) {
    var data = this.appData[domain];
    if(data) {
      return data[key];
    } else {
      return null;
    }
  }

  setAppDataItem(key, value) {
    this.setDomainDataItem(key, value, AppDomain);
  }

  getAppDataItem(key) {
    return this.getDomainDataItem(key, AppDomain);
  }

  get pinned() {
    return this.getAppDataItem("pinned");
  }

  get archived() {
    return this.getAppDataItem("archived");
  }

  get locked() {
    return this.getAppDataItem("locked");
  }

  hasRawClientUpdatedAtValue() {
    return this.getAppDataItem("client_updated_at") != null;
  }

  get client_updated_at() {
    if(!this._client_updated_at) {
      var saved = this.getAppDataItem("client_updated_at");
      if(saved) {
        this._client_updated_at = new Date(saved);
      } else {
        this._client_updated_at = new Date(this.updated_at);
      }
    }
    return this._client_updated_at;
  }

  set client_updated_at(date) {
    this._client_updated_at = date;

    this.setAppDataItem("client_updated_at", date);
  }

  /*
    During sync conflicts, when determing whether to create a duplicate for an item, we can omit keys that have no
    meaningful weight and can be ignored. For example, if one component has active = true and another component has active = false,
    it would be silly to duplicate them, so instead we ignore this.
   */
  keysToIgnoreWhenCheckingContentEquality() {
    return [];
  }

  // Same as above, but keys inside appData[AppDomain]
  appDataKeysToIgnoreWhenCheckingContentEquality() {
    return ["client_updated_at"];
  }

  isItemContentEqualWith(otherItem) {
    let omit = (obj, keys) => {
      for(var key of keys) {
        delete obj[key];
      }
      return obj;
    }

    var left = this.structureParams();
    left.appData[AppDomain] = omit(left.appData[AppDomain], this.appDataKeysToIgnoreWhenCheckingContentEquality());
    left = omit(left, this.keysToIgnoreWhenCheckingContentEquality());

    var right = otherItem.structureParams();
    right.appData[AppDomain] = omit(right.appData[AppDomain], otherItem.appDataKeysToIgnoreWhenCheckingContentEquality());
    right = omit(right, otherItem.keysToIgnoreWhenCheckingContentEquality());

    return JSON.stringify(left) === JSON.stringify(right)
  }

  /*
  Dates
  */

  createdAtString() {
    return this.dateToLocalizedString(this.created_at);
  }

  updatedAtString() {
    return this.dateToLocalizedString(this.client_updated_at);
  }

  dateToLocalizedString(date) {
    if (typeof Intl !== 'undefined' && Intl.DateTimeFormat) {
      if (!dateFormatter) {
        var locale = (navigator.languages && navigator.languages.length) ? navigator.languages[0] : navigator.language;
        dateFormatter = new Intl.DateTimeFormat(locale, {
          year: 'numeric',
          month: 'short',
          day: '2-digit',
          weekday: 'long',
          hour: '2-digit',
          minute: '2-digit',
        });
      }
      return dateFormatter.format(date);
    } else {
      // IE < 11, Safari <= 9.0.
      // In English, this generates the string most similar to
      // the toLocaleDateString() result above.
      return date.toDateString() + ' ' + date.toLocaleTimeString();
    }
  }

}
<|endoftext|>