<commit_before>import Ember from 'ember';
import Cookie from 'ember-cli-js-cookie';
import NodeJsonWebToken from 'npm:jsonwebtoken';
import ENV from 'bracco/config/environment';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  flashMessages: Ember.inject.service(),

  isAuthenticated: false,
  isPermitted: false,
  isAdmin: false,
  isProvider: false,
  isClient: false,
  fromCookie: false,
  uid: null,
  jwt: null,
  name: null,
  email: null,
  role_id: null,
  roleName: null,
  provider_id: null,
  client_id: null,
  sandbox_id: null,
  home: null,
  area: 'DOI Fabrica Personal area',
  sandbox: null,

  init() {
    this._super(...arguments);

    if (ENV.JWT_PRIVATE_KEY) {
      let payload = {
        uid: (ENV.USER_API_URL === "https://profiles.datacite.org/api") ? '0000-0002-1825-0097' : '0000-0001-5489-3594',
        name: 'Josiah Carberry',
        role_id: ENV.ROLE_ID
      }
      this.initUser(payload);
      this.setJwt();
    } else {
      // check for cookie containing jwt
      let jwt = Cookie.get('_datacite_jwt');
      this.set('jwt', jwt);

      // RSA public key
      let cert = ENV.JWT_PUBLIC_KEY ? ENV.JWT_PUBLIC_KEY.replace(/\\n/g, '\n') : null;

      // verify asymmetric token, using RSA with SHA-256 hash algorithm
      let self = this;
      NodeJsonWebToken.verify(jwt, cert, { algorithms: ['RS256'] }, function (error, payload) {
        if (payload) {
          this.set('fromCookie', true);
          self.initUser(payload);
        } else {
          Ember.Logger.assert(false, error);
        }
      });
    }
  },

  initUser(payload) {
    if (Ember.isPresent(payload)) {
      this.set('isAuthenticated', true);
      this.set('uid', payload.uid);
      this.set('name', payload.name);
      this.set('email', payload.email);
      this.set('provider_id', payload.provider_id);
      this.set('client_id', payload.client_id);

      this.setRole(payload.role_id);

      if (payload.sandbox_id) {
        this.set('sandbox_id', payload.sandbox_id);
        this.set('sandbox', '/clients/' + payload.sandbox_id);
      }
    }
  },

  setRole(role_id) {
    this.set('role_id', role_id);
    this.set('roleName', role_id.split('_').map(item => item.capitalize()).join(' '));

    if (['staff_admin', 'staff_user'].includes(role_id)) {
      this.set('isAdmin', true);
      this.set('home', '/');
      this.set('area', 'DataCite Administration area')
    } else if (['provider_admin', 'provider_user'].includes(role_id) && this.get('provider_id')) {
      this.set('isProvider', true);
      this.set('home', '/providers/' + this.get('provider_id'));
      this.set('area', 'Provider Administration area')
    } else if (['client_admin', 'client_user'].includes(role_id) && this.get('client_id')) {
      this.set('isClient', true);
      this.set('home', '/clients/' + this.get('client_id'));
      this.set('area', 'Client Administration area')
    } else {
      this.set('role_id', 'user');
      this.set('role_name', 'User');
      this.set('home', '/users/' + this.get('uid'));
    }

    this.get('flashMessages').info('Welcome ' + this.get('name') + ' to the ' + this.get('area') + '.');
  },

  setJwt() {
    let duration = (ENV.environment === 'test') ? 60 : (30 * 24 * 3600)
    let payload = {
      uid: this.get('uid'),
      name: this.get('name'),
      role_id: this.get('role_id'),
      exp: Math.floor(Date.now() / 1000) + duration
    };

    // RSA private key
    let cert = ENV.JWT_PRIVATE_KEY ? ENV.JWT_PRIVATE_KEY.replace(/\\n/g, '\n') : null;

    // sign asymmetric token, using RSA with SHA-256 hash algorithm
    NodeJsonWebToken.sign(payload, cert, { algorithm: 'RS256' }, function (error, jwt) {
      if (jwt) {
        self.set('jwt', jwt);
      } else {
        Ember.Logger.assert(false, error);
      }
    });
  }
});
<commit_msg>disable loading user via env variable<commit_after>import Ember from 'ember';
import Cookie from 'ember-cli-js-cookie';
import NodeJsonWebToken from 'npm:jsonwebtoken';
import ENV from 'bracco/config/environment';

export default Ember.Service.extend({
  store: Ember.inject.service(),
  flashMessages: Ember.inject.service(),

  isAuthenticated: false,
  isPermitted: false,
  isAdmin: false,
  isProvider: false,
  isClient: false,
  fromCookie: false,
  uid: null,
  jwt: null,
  name: null,
  email: null,
  role_id: null,
  roleName: null,
  provider_id: null,
  client_id: null,
  sandbox_id: null,
  home: null,
  area: 'DOI Fabrica Personal area',
  sandbox: null,

  init() {
    this._super(...arguments);

    if (1 === 2) {
      let payload = {
        uid: (ENV.USER_API_URL === "https://profiles.datacite.org/api") ? '0000-0002-1825-0097' : '0000-0001-5489-3594',
        name: 'Josiah Carberry',
        role_id: ENV.ROLE_ID
      }
      this.initUser(payload);
      this.setJwt();
    } else {
      // check for cookie containing jwt
      let jwt = Cookie.get('_datacite_jwt');
      this.set('jwt', jwt);

      // RSA public key
      let cert = ENV.JWT_PUBLIC_KEY ? ENV.JWT_PUBLIC_KEY.replace(/\\n/g, '\n') : null;

      // verify asymmetric token, using RSA with SHA-256 hash algorithm
      let self = this;
      NodeJsonWebToken.verify(jwt, cert, { algorithms: ['RS256'] }, function (error, payload) {
        if (payload) {
          this.set('fromCookie', true);
          self.initUser(payload);
        } else {
          Ember.Logger.assert(false, error);
        }
      });
    }
  },

  initUser(payload) {
    if (Ember.isPresent(payload)) {
      this.set('isAuthenticated', true);
      this.set('uid', payload.uid);
      this.set('name', payload.name);
      this.set('email', payload.email);
      this.set('provider_id', payload.provider_id);
      this.set('client_id', payload.client_id);

      this.setRole(payload.role_id);

      if (payload.sandbox_id) {
        this.set('sandbox_id', payload.sandbox_id);
        this.set('sandbox', '/clients/' + payload.sandbox_id);
      }
    }
  },

  setRole(role_id) {
    this.set('role_id', role_id);
    this.set('roleName', role_id.split('_').map(item => item.capitalize()).join(' '));

    if (['staff_admin', 'staff_user'].includes(role_id)) {
      this.set('isAdmin', true);
      this.set('home', '/');
      this.set('area', 'DataCite Administration area')
    } else if (['provider_admin', 'provider_user'].includes(role_id) && this.get('provider_id')) {
      this.set('isProvider', true);
      this.set('home', '/providers/' + this.get('provider_id'));
      this.set('area', 'Provider Administration area')
    } else if (['client_admin', 'client_user'].includes(role_id) && this.get('client_id')) {
      this.set('isClient', true);
      this.set('home', '/clients/' + this.get('client_id'));
      this.set('area', 'Client Administration area')
    } else {
      this.set('role_id', 'user');
      this.set('role_name', 'User');
      this.set('home', '/users/' + this.get('uid'));
    }

    this.get('flashMessages').info('Welcome ' + this.get('name') + ' to the ' + this.get('area') + '.');
  },

  setJwt() {
    let duration = (ENV.environment === 'test') ? 60 : (30 * 24 * 3600)
    let payload = {
      uid: this.get('uid'),
      name: this.get('name'),
      role_id: this.get('role_id'),
      exp: Math.floor(Date.now() / 1000) + duration
    };

    // RSA private key
    let cert = ENV.JWT_PRIVATE_KEY ? ENV.JWT_PRIVATE_KEY.replace(/\\n/g, '\n') : null;

    // sign asymmetric token, using RSA with SHA-256 hash algorithm
    NodeJsonWebToken.sign(payload, cert, { algorithm: 'RS256' }, function (error, jwt) {
      if (jwt) {
        self.set('jwt', jwt);
      } else {
        Ember.Logger.assert(false, error);
      }
    });
  }
});
<|endoftext|>


<commit_before>// Set global variables
		var dataView;
		var grid;

		var data = [];

// Set up SlickGrid display columns
		var columns = [
			{id:"linkedName", name:"Name", field:"linkedName", cssClass:"cell-title", width:150, sortable: true},
			{id:"gender", name:"Gender", field:"gender", width:45},
			{id:"birthDate", name:"Birth Date", field:"birthDate", sortable: true},
			{id:"birthPlace", name:"Birth Place", field:"birthPlace", width:150, sortable: false},
			{id:"deathDate", name:"Death Date", field:"deathDate", sortable: true},
			{id:"deathPlace", name:"Death Place", field:"deathPlace", width: 150, sortable: false}
		];

// Set SlickGrid options
		var options = {
			editable: false,
			enableAddRow: false,
			enableCellNavigation: true,
			asyncEditorLoading: false,
			forceFitColumns: true
		};

		var searchString = "";

// Define search filter (currently searches name, birth place, and death place)
		function myFilter(item) {

			var searchWords = getWords(searchString);
			var searchFields = ["name","birthPlace","deathPlace", "birthDate", "deathDate"];
			if (searchWords){
				// Go through each of the words in the search string
				for (j in searchWords){
					var itemFound = false;
					searchWord = searchWords[j].toUpperCase();
					// Make sure that the word is in at least one of the search fields.
					for (i in searchFields){
						if (item[searchFields[i]].toUpperCase().indexOf(searchWord) != -1){
							itemFound = true;
						}
					}
					if (itemFound === false){
						return false;
					}
			}
		}
			return true;
		}

// Get all of the words in a search string
		function getWords(wordString){
			pattern = /[^, ]+/g;
			wordArray = wordString.match(pattern);
			return wordArray;
		}

// This is my function to do a sort by name any time we change the data.

function initialSort(){
	sortcol = "linkedName";
	dataView.sort(comparer, 1);
}

// This is the comparer. Right now, it just sorts based on the name.
	function comparer(a,b) {
		if (sortcol === "linkedName"){
			var x = a["name"], y = b["name"];
	}
		else if (sortcol === "birthDate"){
			var x = a["birthDateKey"], y = b["birthDateKey"];
		}
		else if (sortcol === "deathDate"){
			var x = a["deathDateKey"], y = b["deathDateKey"];
		}
		else {
			var x = a[sortcol], y = b[sortcol];
		}
		return (x == y ? 0 : (x > y ? 1 : -1));
}

	// This function takes a user, and returns a list of their active trees.
	function getTreeList(user){
// need the www so we pick up the sign-in cookie
		var jsonURL = 'http://www.werelate.org/w/index.php?action=ajax&rs=wfGetTrees&user=' + user + '&callback=?';
		$.getJSON(jsonURL,function(json){
		// Set up the select menu
		$('#treeFilter').append('Select Tree: <select id="treeSelect"><option value="wfWatchlist" selected="selected">All Trees</option></select>');
// pick up user from the closure (because I removed the global user variable)
		$('#treeSelect').change(function() {
			loadNewTree(user, this.value);
		});
		$.each(json, function(key,text){
			// Create an option in the select menu for each tree
			$('#treeSelect').append('<option value="' + text + '">' + text + '</option>')
		});
	});
}

// This function loads a new tree from the dropdown list.
function loadNewTree(user, treeName){
	// Loading .gif while waiting for AJAX
	$("#myGrid").mask("Loading...");
	var newData = [];
	// Check if it's asking for a tree, or for the full watchlist
	if (treeName != "wfWatchlist"){
// need the www so we pick up the sign-in cookie
		var jsonURL = 'http://www.werelate.org/w/index.php?action=ajax&rs=wfGetTree&user=' + user + '&tree=' + treeName + '&callback=?';
		$.getJSON(jsonURL,function(json){
		var treePeople = [];
		// Go through each item and put it into the treePeople array
	  $.each(json, function(key,val) {
		  treePeople.push(val);
		 });
		// Compare the treePeople array with the current data. Add the people who are in the tree to newData
		for(var i=0; i<data.length; i++){
			if ($.inArray(data[i].title,treePeople) != -1){
				newData.push(data[i]);
			}
		}
		// Update the data in the grid, and then update the grid
		dataView.setItems(newData);
		grid.updateRowCount();
		grid.render();
		initialSort();
		$("#myGrid").unmask();
});
}
else { // If they want the whole watchlist, then reset to the original data.
	dataView.setItems(data);
	grid.updateRowCount();
	grid.render();
	initialSort();
}
}

	// This function takes a user name and tree name, loads the data, and initializes the grid. This has to be called before the grid shows up.
	function loadTree(user){
		// Masks the div, and puts up a loading image
		$("#myGrid").mask("Loading...");
// need the www so we pick up the sign-in cookie
		var jsonURL = 'http://www.werelate.org/w/index.php?action=ajax&rs=wfGetWatchlist&user=' + user + '&callback=?';
		$.getJSON(jsonURL,function(json){
	var items = [];
	// Go through each item and put it into the data object
  $.each(json, function(key, val) {
	  var d = (data[key] = {});

				d["id"] = "id_" + key;
				d["title"] = val.title;
				// This is used for searching, not display
// surname and given name may be missing; default to "" like other fields
				d["name"] = (val.surname||"") + ", " + (val.given||"");
				d["linkedName"] = '' + (val.surname||"") + ', ' + (val.given||"") + ''||"";
				d["gender"] = val.gender||"";
				d["birthDate"] = val.birthDate||"";
				d["birthDateKey"] = getDateKey(val.birthDate||"");
				d["birthPlace"] = val.birthPlace||"";
				d["deathDate"] = val.deathDate||"";
				d["deathDateKey"] = getDateKey(val.deathDate||"");
				d["deathPlace"] = val.deathPlace||"";
			});

// Everything below here is copied directly from the SlickGrid example

			// initialize the model
			dataView = new Slick.Data.DataView();
			dataView.beginUpdate();
			dataView.setItems(data);
			dataView.setFilter(myFilter);
			dataView.endUpdate();

			// initialize the grid
			grid = new Slick.Grid("#myGrid", dataView, columns, options);

// We don't need something like this until we allow people to click on a star to flag a row (like gmail)
//			grid.onClick.subscribe(function(e,args) {
//                if ($(e.target).hasClass("toggle")) {
//                    var item = dataView.getItem(args.row);
//                    if (item) {
//                        if (!item._collapsed)
//                            item._collapsed = true;
//                        else
//                            item._collapsed = false;
//
//                        dataView.updateItem(item.id, item);
//                    }
//                    e.stopImmediatePropagation();
//                }
//            });

         grid.onSort.subscribe(function(e, args) {
			sortdir = args.sortAsc ? 1 : -1;
			sortcol = args.sortCol.field;
			dataView.sort(comparer, args.sortAsc);
		});

			// wire up model events to drive the grid
			dataView.onRowCountChanged.subscribe(function(e,args) {
				grid.updateRowCount();
                grid.render();
			});

			dataView.onRowsChanged.subscribe(function(e,args) {
				grid.invalidateRows(args.rows);
				grid.render();
			});

			var h_runfilters = null;

			// wire up the search textbox to apply the filter to the model
			$("#txtSearch").keyup(function(e) {
                Slick.GlobalEditorLock.cancelCurrentEdit();

				// clear on Esc
				if (e.which == 27)
					this.value = "";

				searchString = this.value;
				dataView.refresh();
			})
		initialSort(); // Ok - this is mine, not from SlickGrid.
		$("#myGrid").unmask();

		})
		};

// Dallan's sortable date code.

var MONTHS = {
	'january': 1,
	'february': 2,
	'march': 3,
	'april': 4,
	'may': 5,
	'june': 6,
	'july': 7,
	'august': 8,
	'september': 9,
	'october': 10,
	'november': 11,
	'december': 12,
	'jan': 1,
	'feb': 2,
	'mar': 3,
	'apr': 4,
	'jun': 6,
	'jul': 7,
	'aug': 8,
	'sep': 9,
	'oct': 10,
	'nov': 11,
	'dec': 12,
	'febr': 2,
	'sept': 9
};

function isYear(y) {
	return (y >= 100 && y <= 3000);
}

function getAlphaMonth(mon) {
	return MONTHS[mon.toLowerCase()];
}

function isDay(d) {
	return (d >= 1 && d <= 31);
}

function isNumMonth(m) {
	return (m >= 1 && m <= 12);
}

function isNextYear(year, field) {
	if (field.length > 4) return
	false;
	var y = year.toString();
	if ((field === '00' && y.substr(2) === '99') || (field === '0' && y.substr(3) === '9')) return true;
	newYear = y.substr(0, 4 - field.length) + field;
	return (parseInt(newYear) - parseInt(year) === 1);
}

function getDateFields(date) {
	var fields = [];
	var field = '';
	var isNumericField; // split on number-letter transition, or non - alphanumeric
	for (var i = 0; i < date.length; i++) {
		var c = date.charAt(i);
		if (c >= '0' && c <= '9') {
			if (field.length > 0 && !isNumericField) {
				fields.push(field);
				field = '';
			}
			field += c;
			isNumericField = true;
		}
		// assume non-7bit-ascii characters are international
		// we'll eventually want to add international months to the MONTHS array
		else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c > '~') {
			if (field.length > 0 && isNumericField) {
				fields.push(field);
				field = '';
			}
			field += c;
			isNumericField = false;
		} else if (field.length > 0) {
			fields.push(field);
			field = '';
		}
	}
	if (field.length > 0) {
		fields.push(field);
	}
	return fields;
}

function getDateKey(date) {
	var year = 0;
	var month = 0;
	var day = 0;
	var result = '00000000';
	var fields = getDateFields(date);
	for (var i = 0; i < fields.length; i++) {
		var field = fields[i];
		var numField = parseInt(field);
		var m = getAlphaMonth(field);
		if (isYear(numField)) {
			if (year === 0) year = numField;
		} else if (m !== undefined) {
			if (month === 0) month = m;
		} else if (i > 0 && isYear(parseInt(fields[i - 1])) && isNextYear(year, field)) {
			year++; // 1963/4 or 1963/64
			}
			else if (isDay(numField) && (!isNumMonth(numField) || (i > 0 && getAlphaMonth(fields[i - 1]) !== undefined) || (i < fields.length - 1 && getAlphaMonth(fields[i + 1]) !== undefined))) {
				if (day === 0) day = numField;
			} else if (isNumMonth(numField)) {
				if (month === 0) month = numField;
			}
		}
		if (year !== 0) {
			result = year.toString();
			if (month !== 0) {
				if (month < 10) {
					result += '0';
				}
				result += month.toString();
				if (day !== 0) {
					if (day < 10) {
						result += '0';
					}
					result += day.toString();
				} else {
					result += '00';
				}
			} else {
				result += '0000';
			}
		}
		return parseInt(result);
	}

// Ready, set, go.
$(function()
		{
// Get user from url: user parameter for testing, or whatever follows Special:List/ for production
// default is empty, which returns logged-in user
			var user = '';
			var results = new RegExp('(Special:ListPages/|\\?user=)([^&#]*)').exec(window.location.href);
			if (results) {
				user = results[2];
			}
			getTreeList(user);
			loadTree(user);
		}
		);
<commit_msg>added tree column; fixed ie bug<commit_after>// Set global variables
		var dataView;
		var grid;

		var data = [];

// Set up SlickGrid display columns
		var columns = [
			{id:"linkedName", name:"Name", field:"linkedName", cssClass:"cell-title", width:150, sortable: true},
			{id:"gender", name:"Gender", field:"gender", width:45},
			{id:"birthDate", name:"Birth Date", field:"birthDate", sortable: true},
			{id:"birthPlace", name:"Birth Place", field:"birthPlace", width:120, sortable: true},
			{id:"deathDate", name:"Death Date", field:"deathDate", sortable: true},
			{id:"deathPlace", name:"Death Place", field:"deathPlace", width: 120, sortable: true},
         {id:"trees", name:"Tree(s)", field:"trees", width:60, sortable: true}
		];

// Set SlickGrid options
		var options = {
			editable: false,
			enableAddRow: false,
			enableCellNavigation: true,
			asyncEditorLoading: false,
			forceFitColumns: true
		};

		var searchString = "";

// Define search filter (currently searches name, birth place, and death place)
		function myFilter(item) {

			var searchWords = getWords(searchString);
			var searchFields = ["name","birthPlace","deathPlace", "birthDate", "deathDate"];
         var searchFieldsLength = searchFields.length;
			if (searchWords){
				// Go through each of the words in the search string
            var searchWordsLength = searchWords.length;
				for (var j = 0; j < searchWordsLength; j++){
					var itemFound = false;
					searchWord = searchWords[j].toUpperCase();
					// Make sure that the word is in at least one of the search fields.
					for (var i = 0; i < searchFieldsLength; i++) {
						if (item[searchFields[i]].toUpperCase().indexOf(searchWord) != -1){
							itemFound = true;
						}
					}
					if (itemFound === false){
						return false;
					}
			}
		}
			return true;
		}

// Get all of the words in a search string
		function getWords(wordString){
			pattern = /[^, ]+/g;
			wordArray = wordString.match(pattern);
			return wordArray;
		}

// This is my function to do a sort by name any time we change the data.

function initialSort(){
	sortcol = "linkedName";
	dataView.sort(comparer, 1);
}

// This is the comparer. Right now, it just sorts based on the name.
	function comparer(a,b) {
		if (sortcol === "linkedName"){
			var x = a["name"], y = b["name"];
	}
		else if (sortcol === "birthDate"){
			var x = a["birthDateKey"], y = b["birthDateKey"];
		}
		else if (sortcol === "deathDate"){
			var x = a["deathDateKey"], y = b["deathDateKey"];
		}
		else {
			var x = a[sortcol], y = b[sortcol];
		}
		return (x == y ? 0 : (x > y ? 1 : -1));
}

	// This function takes a user, and returns a list of their active trees.
	function getTreeList(user){
// need the www so we pick up the sign-in cookie
		var jsonURL = 'http://www.werelate.org/w/index.php?action=ajax&rs=wfGetTrees&user=' + user + '&callback=?';
		$.getJSON(jsonURL,function(json){
		// Set up the select menu
		$('#treeFilter').append('Tree: <select id="treeSelect"><option value="wfWatchlist" selected="selected">All Trees</option></select>');
// pick up user from the closure (because I removed the global user variable)
		$('#treeSelect').change(function() {
			loadNewTree(user, this.value);
		});
		$.each(json, function(key,text){
			// Create an option in the select menu for each tree
			$('#treeSelect').append('<option value="' + text + '">' + text + '</option>')
		});
	});
}

// This function loads a new tree from the dropdown list.
function loadNewTree(user, treeName){
	// Loading .gif while waiting for AJAX
	$("#myGrid").mask("Loading...");
	var newData = [];
	// Check if it's asking for a tree, or for the full watchlist
	if (treeName != "wfWatchlist"){
// need the www so we pick up the sign-in cookie
		var jsonURL = 'http://www.werelate.org/w/index.php?action=ajax&rs=wfGetTree&user=' + user + '&tree=' + treeName + '&callback=?';
		$.getJSON(jsonURL,function(json){
		var treePeople = [];
		// Go through each item and put it into the treePeople array
	  $.each(json, function(key,val) {
		  treePeople.push(val);
		 });
		// Compare the treePeople array with the current data. Add the people who are in the tree to newData
		for(var i=0; i<data.length; i++){
			if ($.inArray(data[i].title,treePeople) != -1){
				newData.push(data[i]);
			}
		}
		// Update the data in the grid, and then update the grid
		dataView.setItems(newData);
		grid.updateRowCount();
		grid.render();
		initialSort();
		$("#myGrid").unmask();
});
}
else { // If they want the whole watchlist, then reset to the original data.
	dataView.setItems(data);
	grid.updateRowCount();
	grid.render();
	initialSort();
}
}

	// This function takes a user name and tree name, loads the data, and initializes the grid. This has to be called before the grid shows up.
	function loadTree(user){
		// Masks the div, and puts up a loading image
		$("#myGrid").mask("Loading...");
// need the www so we pick up the sign-in cookie
		var jsonURL = 'http://www.werelate.org/w/index.php?action=ajax&rs=wfGetWatchlist&user=' + user + '&callback=?';
		$.getJSON(jsonURL,function(json){
	var items = [];
	// Go through each item and put it into the data object
  $.each(json, function(key, val) {
	  var d = (data[key] = {});

				d["id"] = "id_" + key;
				d["title"] = val.title;
				// This is used for searching, not display
// surname and given name may be missing; default to "" like other fields
				d["name"] = (val.surname||"") + ", " + (val.given||"");
				d["linkedName"] = '' + (val.surname||"") + ', ' + (val.given||"") + ''||"";
				d["gender"] = val.gender||"";
				d["birthDate"] = val.birthDate||"";
				d["birthDateKey"] = getDateKey(val.birthDate||"");
				d["birthPlace"] = val.birthPlace||"";
				d["deathDate"] = val.deathDate||"";
				d["deathDateKey"] = getDateKey(val.deathDate||"");
				d["deathPlace"] = val.deathPlace||"";
                d["trees"] = val.trees||"";
			});

// Everything below here is copied directly from the SlickGrid example

			// initialize the model
			dataView = new Slick.Data.DataView();
			dataView.beginUpdate();
			dataView.setItems(data);
			dataView.setFilter(myFilter);
			dataView.endUpdate();

			// initialize the grid
			grid = new Slick.Grid("#myGrid", dataView, columns, options);

// We don't need something like this until we allow people to click on a star to flag a row (like gmail)
//			grid.onClick.subscribe(function(e,args) {
//                if ($(e.target).hasClass("toggle")) {
//                    var item = dataView.getItem(args.row);
//                    if (item) {
//                        if (!item._collapsed)
//                            item._collapsed = true;
//                        else
//                            item._collapsed = false;
//
//                        dataView.updateItem(item.id, item);
//                    }
//                    e.stopImmediatePropagation();
//                }
//            });

         grid.onSort.subscribe(function(e, args) {
			sortdir = args.sortAsc ? 1 : -1;
			sortcol = args.sortCol.field;
			dataView.sort(comparer, args.sortAsc);
		});

			// wire up model events to drive the grid
			dataView.onRowCountChanged.subscribe(function(e,args) {
				grid.updateRowCount();
                grid.render();
			});

			dataView.onRowsChanged.subscribe(function(e,args) {
				grid.invalidateRows(args.rows);
				grid.render();
			});

			var h_runfilters = null;

			// wire up the search textbox to apply the filter to the model
			$("#txtSearch").keyup(function(e) {
                Slick.GlobalEditorLock.cancelCurrentEdit();

				// clear on Esc
				if (e.which == 27)
					this.value = "";

				searchString = this.value;
				dataView.refresh();
			})
		initialSort(); // Ok - this is mine, not from SlickGrid.
		$("#myGrid").unmask();

		})
		};

// Dallan's sortable date code.

var MONTHS = {
	'january': 1,
	'february': 2,
	'march': 3,
	'april': 4,
	'may': 5,
	'june': 6,
	'july': 7,
	'august': 8,
	'september': 9,
	'october': 10,
	'november': 11,
	'december': 12,
	'jan': 1,
	'feb': 2,
	'mar': 3,
	'apr': 4,
	'jun': 6,
	'jul': 7,
	'aug': 8,
	'sep': 9,
	'oct': 10,
	'nov': 11,
	'dec': 12,
	'febr': 2,
	'sept': 9
};

function isYear(y) {
	return (y >= 100 && y <= 3000);
}

function getAlphaMonth(mon) {
	return MONTHS[mon.toLowerCase()];
}

function isDay(d) {
	return (d >= 1 && d <= 31);
}

function isNumMonth(m) {
	return (m >= 1 && m <= 12);
}

function isNextYear(year, field) {
	if (field.length > 4) return
	false;
	var y = year.toString();
	if ((field === '00' && y.substr(2) === '99') || (field === '0' && y.substr(3) === '9')) return true;
	newYear = y.substr(0, 4 - field.length) + field;
	return (parseInt(newYear) - parseInt(year) === 1);
}

function getDateFields(date) {
	var fields = [];
	var field = '';
	var isNumericField; // split on number-letter transition, or non - alphanumeric
	for (var i = 0; i < date.length; i++) {
		var c = date.charAt(i);
		if (c >= '0' && c <= '9') {
			if (field.length > 0 && !isNumericField) {
				fields.push(field);
				field = '';
			}
			field += c;
			isNumericField = true;
		}
		// assume non-7bit-ascii characters are international
		// we'll eventually want to add international months to the MONTHS array
		else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || c > '~') {
			if (field.length > 0 && isNumericField) {
				fields.push(field);
				field = '';
			}
			field += c;
			isNumericField = false;
		} else if (field.length > 0) {
			fields.push(field);
			field = '';
		}
	}
	if (field.length > 0) {
		fields.push(field);
	}
	return fields;
}

function getDateKey(date) {
	var year = 0;
	var month = 0;
	var day = 0;
	var result = '00000000';
	var fields = getDateFields(date);
	for (var i = 0; i < fields.length; i++) {
		var field = fields[i];
		var numField = parseInt(field);
		var m = getAlphaMonth(field);
		if (isYear(numField)) {
			if (year === 0) year = numField;
		} else if (m !== undefined) {
			if (month === 0) month = m;
		} else if (i > 0 && isYear(parseInt(fields[i - 1])) && isNextYear(year, field)) {
			year++; // 1963/4 or 1963/64
			}
			else if (isDay(numField) && (!isNumMonth(numField) || (i > 0 && getAlphaMonth(fields[i - 1]) !== undefined) || (i < fields.length - 1 && getAlphaMonth(fields[i + 1]) !== undefined))) {
				if (day === 0) day = numField;
			} else if (isNumMonth(numField)) {
				if (month === 0) month = numField;
			}
		}
		if (year !== 0) {
			result = year.toString();
			if (month !== 0) {
				if (month < 10) {
					result += '0';
				}
				result += month.toString();
				if (day !== 0) {
					if (day < 10) {
						result += '0';
					}
					result += day.toString();
				} else {
					result += '00';
				}
			} else {
				result += '0000';
			}
		}
		return parseInt(result);
	}

// Ready, set, go.
$(function()
		{
// Get user from url: user parameter for testing, or whatever follows Special:List/ for production
// default is empty, which returns logged-in user
			var user = '';
			var results = new RegExp('(Special:ListPages/|\\?user=)([^&#]*)').exec(window.location.href);
			if (results) {
				user = results[2];
			}
			getTreeList(user);
			loadTree(user);
		}
		);
<|endoftext|>


<commit_before>var gCertificatesListbox = null;
var gServerCertsListbox = null;
var gCertOverridesListbox = null;
var gDevicesListbox = null;

function onCertificatesLoad() {
  gCertificatesListbox = document.getElementById("certificates-listbox");
  gServerCertsListbox = document.getElementById("servercerts-listbox");
  gCertOverridesListbox = document.getElementById("certoverrides-listbox");
  gDevicesListbox = document.getElementById("devices-listbox");
}
window.addEventListener("load", onCertificatesLoad, false);

function setCertificates(config) {
  if ("certs" in config) {
    if ("ca" in config.certs) {
      for (var i=0; i < config.certs.ca.length; i++) {
        var label = config.certs.ca[i].url;
        try {
          var certFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
          certFile.initWithPath(config.certs.ca[i].url);
          label = certFile.leafName;
        } catch (e) {}
        var listitem = gCertificatesListbox.appendItem(label, config.certs.ca[i].trust);
        listitem.setAttribute("tooltiptext", config.certs.ca[i].url);
        listitem.setAttribute("path", config.certs.ca[i].url);
        listitem.setAttribute("context", "certificate-contextmenu");
      }
    }
    if ("server" in config.certs) {
      for (var i=0; i < config.certs.server.length; i++) {
        var label = config.certs.server[i];
        try {
          var certFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
          certFile.initWithPath(config.certs.server[i]);
          label = certFile.leafName;
        } catch (e) {          }
        var listitem = gServerCertsListbox.appendItem(config.certs.server[i]);
        listitem.setAttribute("tooltiptext", config.certs.server[i]);
        listitem.setAttribute("path", config.certs.server[i]);
        listitem.setAttribute("context", "servercert-contextmenu");
      }
    }
    if ("override" in config.certs) {
      for (var i=0; i < config.certs.override.length; i++) {
        var listitem = gCertOverridesListbox.appendItem(config.certs.override[i]);
        listitem.setAttribute("context", "certoverride-contextmenu");
      }
    }
    if ("devices" in config.certs) {
      for (var i=0; i < config.certs.devices.length; i++) {
        var listitem = gDevicesListbox.appendItem(config.certs.devices[i].name, config.certs.devices[i].path);
        listitem.setAttribute("context", "devices-contextmenu");
      }
    }
  }
}

function getCertificates(config) {
  if (gCertificatesListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.ca = [];

    for (var i=0; i < gCertificatesListbox.itemCount; i++) {
      var cert = {};
      cert.url = gCertificatesListbox.getItemAtIndex(i).getAttribute("path");
      cert.trust = gCertificatesListbox.getItemAtIndex(i).getAttribute("value");
      config.certs.ca.push(cert);
    }
  }
  if (gServerCertsListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.server = [];

    for (var i=0; i < gServerCertsListbox.itemCount; i++) {
      config.certs.server.push(gServerCertsListbox.getItemAtIndex(i).getAttribute("path"));
    }
  }
  if (gCertOverridesListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.override = [];

    for (var i=0; i < gCertOverridesListbox.itemCount; i++) {
      config.certs.override.push(gCertOverridesListbox.getItemAtIndex(i).getAttribute("label"));
    }
  }
  if (gDevicesListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.devices = [];

    for (var i=0; i < gDevicesListbox.itemCount; i++) {
      var device = {};
      device.name = gDevicesListbox.getItemAtIndex(i).getAttribute("label");
      device.path = gDevicesListbox.getItemAtIndex(i).getAttribute("value");
      config.certs.devices.push(device);
    }
  }
  return config;
}

function resetCertificates() {
  while (gCertificatesListbox.itemCount > 0) {
    gCertificatesListbox.removeItemAt(0);
  }
  while (gServerCertsListbox.itemCount > 0) {
    gServerCertsListbox.removeItemAt(0);
  }
  while (gCertOverridesListbox.itemCount > 0) {
    gCertOverridesListbox.removeItemAt(0);
  }
}

function addCertificateFromURL() {
  var retVals = { url: null};
  window.openDialog("chrome://cck2wizard/content/url-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return;
  }
  var url = retVals.url;
  try {
    var uri = Services.io.newURI(url, null, null);
    if (uri.scheme != "https" && uri.scheme != "http") {
      showErrorMessage("invalidscheme");
      return;
    }
  } catch (ex) {
    showErrorMessage("invalidurl");
    return;
  }
  var certString = getCertString();
  if (certString) {
    var listitem = gCertificatesListbox.appendItem(url, certString);
    listitem.setAttribute("context", "certificate-contextmenu");
  }
}

function addServerCertificateFromURL() {
  var retVals = { url: null};
  window.openDialog("chrome://cck2wizard/content/url-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return;
  }
  var url = retVals.url;
  try {
    var uri = Services.io.newURI(url, null, null);
    if (uri.scheme != "https" && uri.scheme != "http") {
      showErrorMessage("invalidscheme");
      return;
    }
  } catch (ex) {
    showErrorMessage("invalidurl");
    return;
  }
  var listitem = gServerCertsListbox.appendItem(url);
  listitem.setAttribute("context", "servercert-contextmenu");
}

function addCertificateOverride() {
  var retVals = { url: null};
  window.openDialog("chrome://cck2wizard/content/url-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return;
  }
  var url = retVals.url;
  var listitem = gCertOverridesListbox.appendItem(url);
  listitem.setAttribute("context", "certoverride-contextmenu");
}

function getCertString() {
  var retVals = { certString: null};
  window.openDialog("chrome://cck2wizard/content/cert-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return null;
  } else {
    return retVals.certString;
  }
}

function addCertificateFromFile() {
  var certFile = chooseFile(window);
  if (certFile) {
    var certString = getCertString();
    if (certString) {
      var listitem = gCertificatesListbox.appendItem(certFile.leafName, certString);
      lisitem.setAttribute("path", certFile.path);
      listitem.setAttribute("context", "certificate-contextmenu");
    }
  }
}

function addServerCertificateFromFile() {
  var certFile = chooseFile(window);
  if (certFile) {
    var listitem = gServerCertsListbox.appendItem(certFile.leafName, "C,C,C");
    lisitem.setAttribute("path", certFile.path);
    listitem.setAttribute("context", "servercert-contextmenu");
  }
}

function addDevice() {
  var retVals = { deviceName: null, devicePath: null};
  window.openDialog("chrome://cck2wizard/content/device-dialog.xul", "cck2wizard-device", "modal,centerscreen", retVals);
  if (!retVals.cancel) {
    var listitem = gDevicesListbox.appendItem(retVals.deviceName, retVals.devicePath);
    listitem.setAttribute("context", "devices-contextmenu");
  }
}

function onEditDevice() {
  if (gDevicesListbox.selectedIndex == -1) {
    return;
  }
  var retVals = { deviceName: gDevicesListbox.selectedItem.label, devicePath: gDevicesListbox.selectedItem.value};
  window.openDialog("chrome://cck2wizard/content/device-dialog.xul", "cck2wizard-device", "modal,centerscreen", retVals);
  if (!retVals.cancel) {
    gDevicesListbox.selectedItem.label = retVals.deviceName;
    gDevicesListbox.selectedItem.value = retVals.devicePath;
  }
}

function onDeleteCertificate() {
  if (gCertificatesListbox.selectedIndex == -1) {
    return;
  }
  gCertificatesListbox.removeChild(gCertificatesListbox.selectedItem);
}

function onDeleteDevice() {
  if (gDevicesListbox.selectedIndex == -1) {
    return;
  }
  gDevicesListbox.removeChild(gDevicesListbox.selectedItem);
}

function onDeleteServerCertificate() {
  if (gServerCertsListbox.selectedIndex == -1) {
    return;
  }
  gServerCertsListbox.removeChild(gServerCertsListbox.selectedItem);
}

function onKeyPressCertificate(event) {
  if (event.target.selectedIndex == -1) {
    return;
  }
  if (event.keyCode == event.DOM_VK_DELETE ||
      event.keyCode == event.DOM_VK_BACK_SPACE) {
    event.target.removeChild(event.target.selectedItem);
  }
}
<commit_msg>Dumb mistakes<commit_after>var gCertificatesListbox = null;
var gServerCertsListbox = null;
var gCertOverridesListbox = null;
var gDevicesListbox = null;

function onCertificatesLoad() {
  gCertificatesListbox = document.getElementById("certificates-listbox");
  gServerCertsListbox = document.getElementById("servercerts-listbox");
  gCertOverridesListbox = document.getElementById("certoverrides-listbox");
  gDevicesListbox = document.getElementById("devices-listbox");
}
window.addEventListener("load", onCertificatesLoad, false);

function setCertificates(config) {
  if ("certs" in config) {
    if ("ca" in config.certs) {
      for (var i=0; i < config.certs.ca.length; i++) {
        var label = config.certs.ca[i].url;
        try {
          var certFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
          certFile.initWithPath(config.certs.ca[i].url);
          label = certFile.leafName;
        } catch (e) {}
        var listitem = gCertificatesListbox.appendItem(label, config.certs.ca[i].trust);
        listitem.setAttribute("tooltiptext", config.certs.ca[i].url);
        listitem.setAttribute("path", config.certs.ca[i].url);
        listitem.setAttribute("context", "certificate-contextmenu");
      }
    }
    if ("server" in config.certs) {
      for (var i=0; i < config.certs.server.length; i++) {
        var label = config.certs.server[i];
        try {
          var certFile = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsILocalFile);
          certFile.initWithPath(config.certs.server[i]);
          label = certFile.leafName;
        } catch (e) {          }
        var listitem = gServerCertsListbox.appendItem(config.certs.server[i]);
        listitem.setAttribute("tooltiptext", config.certs.server[i]);
        listitem.setAttribute("path", config.certs.server[i]);
        listitem.setAttribute("context", "servercert-contextmenu");
      }
    }
    if ("override" in config.certs) {
      for (var i=0; i < config.certs.override.length; i++) {
        var listitem = gCertOverridesListbox.appendItem(config.certs.override[i]);
        listitem.setAttribute("context", "certoverride-contextmenu");
      }
    }
    if ("devices" in config.certs) {
      for (var i=0; i < config.certs.devices.length; i++) {
        var listitem = gDevicesListbox.appendItem(config.certs.devices[i].name, config.certs.devices[i].path);
        listitem.setAttribute("context", "devices-contextmenu");
      }
    }
  }
}

function getCertificates(config) {
  if (gCertificatesListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.ca = [];

    for (var i=0; i < gCertificatesListbox.itemCount; i++) {
      var cert = {};
      cert.url = gCertificatesListbox.getItemAtIndex(i).getAttribute("path");
      cert.trust = gCertificatesListbox.getItemAtIndex(i).getAttribute("value");
      config.certs.ca.push(cert);
    }
  }
  if (gServerCertsListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.server = [];

    for (var i=0; i < gServerCertsListbox.itemCount; i++) {
      config.certs.server.push(gServerCertsListbox.getItemAtIndex(i).getAttribute("path"));
    }
  }
  if (gCertOverridesListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.override = [];

    for (var i=0; i < gCertOverridesListbox.itemCount; i++) {
      config.certs.override.push(gCertOverridesListbox.getItemAtIndex(i).getAttribute("label"));
    }
  }
  if (gDevicesListbox.itemCount > 0) {
    if (!("certs" in config)) {
      config.certs = {};
    }
    config.certs.devices = [];

    for (var i=0; i < gDevicesListbox.itemCount; i++) {
      var device = {};
      device.name = gDevicesListbox.getItemAtIndex(i).getAttribute("label");
      device.path = gDevicesListbox.getItemAtIndex(i).getAttribute("value");
      config.certs.devices.push(device);
    }
  }
  return config;
}

function resetCertificates() {
  while (gCertificatesListbox.itemCount > 0) {
    gCertificatesListbox.removeItemAt(0);
  }
  while (gServerCertsListbox.itemCount > 0) {
    gServerCertsListbox.removeItemAt(0);
  }
  while (gCertOverridesListbox.itemCount > 0) {
    gCertOverridesListbox.removeItemAt(0);
  }
}

function addCertificateFromURL() {
  var retVals = { url: null};
  window.openDialog("chrome://cck2wizard/content/url-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return;
  }
  var url = retVals.url;
  try {
    var uri = Services.io.newURI(url, null, null);
    if (uri.scheme != "https" && uri.scheme != "http") {
      showErrorMessage("invalidscheme");
      return;
    }
  } catch (ex) {
    showErrorMessage("invalidurl");
    return;
  }
  var certString = getCertString();
  if (certString) {
    var listitem = gCertificatesListbox.appendItem(url, certString);
    listitem.setAttribute("path", url);
    listitem.setAttribute("context", "certificate-contextmenu");
  }
}

function addServerCertificateFromURL() {
  var retVals = { url: null};
  window.openDialog("chrome://cck2wizard/content/url-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return;
  }
  var url = retVals.url;
  try {
    var uri = Services.io.newURI(url, null, null);
    if (uri.scheme != "https" && uri.scheme != "http") {
      showErrorMessage("invalidscheme");
      return;
    }
  } catch (ex) {
    showErrorMessage("invalidurl");
    return;
  }
  var listitem = gServerCertsListbox.appendItem(url);
  listitem.setAttribute("path", url);
  listitem.setAttribute("context", "servercert-contextmenu");
}

function addCertificateOverride() {
  var retVals = { url: null};
  window.openDialog("chrome://cck2wizard/content/url-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return;
  }
  var url = retVals.url;
  var listitem = gCertOverridesListbox.appendItem(url);
  listitem.setAttribute("context", "certoverride-contextmenu");
}

function getCertString() {
  var retVals = { certString: null};
  window.openDialog("chrome://cck2wizard/content/cert-dialog.xul", "cck2wizard-certificate", "modal,centerscreen", retVals);
  if (retVals.cancel) {
    return null;
  } else {
    return retVals.certString;
  }
}

function addCertificateFromFile() {
  var certFile = chooseFile(window);
  if (certFile) {
    var certString = getCertString();
    if (certString) {
      var listitem = gCertificatesListbox.appendItem(certFile.leafName, certString);
      listitem.setAttribute("path", certFile.path);
      listitem.setAttribute("tooltiptext", certFile.path);
      listitem.setAttribute("context", "certificate-contextmenu");
    }
  }
}

function addServerCertificateFromFile() {
  var certFile = chooseFile(window);
  if (certFile) {
    var listitem = gServerCertsListbox.appendItem(certFile.leafName, "C,C,C");
    listitem.setAttribute("path", certFile.path);
    listitem.setAttribute("tooltiptext", certFile.path);
    listitem.setAttribute("context", "servercert-contextmenu");
  }
}

function addDevice() {
  var retVals = { deviceName: null, devicePath: null};
  window.openDialog("chrome://cck2wizard/content/device-dialog.xul", "cck2wizard-device", "modal,centerscreen", retVals);
  if (!retVals.cancel) {
    var listitem = gDevicesListbox.appendItem(retVals.deviceName, retVals.devicePath);
    listitem.setAttribute("context", "devices-contextmenu");
  }
}

function onEditDevice() {
  if (gDevicesListbox.selectedIndex == -1) {
    return;
  }
  var retVals = { deviceName: gDevicesListbox.selectedItem.label, devicePath: gDevicesListbox.selectedItem.value};
  window.openDialog("chrome://cck2wizard/content/device-dialog.xul", "cck2wizard-device", "modal,centerscreen", retVals);
  if (!retVals.cancel) {
    gDevicesListbox.selectedItem.label = retVals.deviceName;
    gDevicesListbox.selectedItem.value = retVals.devicePath;
  }
}

function onDeleteCertificate() {
  if (gCertificatesListbox.selectedIndex == -1) {
    return;
  }
  gCertificatesListbox.removeChild(gCertificatesListbox.selectedItem);
}

function onDeleteDevice() {
  if (gDevicesListbox.selectedIndex == -1) {
    return;
  }
  gDevicesListbox.removeChild(gDevicesListbox.selectedItem);
}

function onDeleteServerCertificate() {
  if (gServerCertsListbox.selectedIndex == -1) {
    return;
  }
  gServerCertsListbox.removeChild(gServerCertsListbox.selectedItem);
}

function onKeyPressCertificate(event) {
  if (event.target.selectedIndex == -1) {
    return;
  }
  if (event.keyCode == event.DOM_VK_DELETE ||
      event.keyCode == event.DOM_VK_BACK_SPACE) {
    event.target.removeChild(event.target.selectedItem);
  }
}
<|endoftext|>


<commit_before>'use strict';
/* global require, module, exports, process */

// #############################################################################
// CONFIGURATION
var b2s = require('browserslist-saucelabs');

module.exports = {
    formatTaskName: function formatTaskName(browserName) {
        return [
            'Test', browserName, 'for',
            process.env.TRAVIS_REPO_SLUG,
            // eslint-disable-next-line no-negated-condition
            process.env.TRAVIS_PULL_REQUEST !== 'false' ?
                'pull request #' + process.env.TRAVIS_PULL_REQUEST : '',
            'build #' + process.env.TRAVIS_JOB_NUMBER
        ].join(' ');
    },

    sauceLabsBrowsers: b2s({ browsers: ['chrome 48'] })
};
<commit_msg>Testing Chrome 50 to run on Sauce Labs<commit_after>'use strict';
/* global require, module, exports, process */

// #############################################################################
// CONFIGURATION
var b2s = require('browserslist-saucelabs');

module.exports = {
    formatTaskName: function formatTaskName(browserName) {
        return [
            'Test', browserName, 'for',
            process.env.TRAVIS_REPO_SLUG,
            // eslint-disable-next-line no-negated-condition
            process.env.TRAVIS_PULL_REQUEST !== 'false' ?
                'pull request #' + process.env.TRAVIS_PULL_REQUEST : '',
            'build #' + process.env.TRAVIS_JOB_NUMBER
        ].join(' ');
    },

    sauceLabsBrowsers: b2s({ browsers: ['chrome 50'] })
};
<|endoftext|>


<commit_before>
// set up form
// initiate search
$('.search input').keyup(function(e) {
  if(e.keyCode == 13) doSearch();
});
$('#searchForm').click(function(event) {
  doSearch();
});

var queryRefresher;

$('#fromDate').datepicker();
$('#toDate').datepicker();
$('#refreshQueries').click(function(e) {
  if ($(e.target).prop('checked')) {
    queryRefresher = setInterval(doSearch, 5000);
  } else {
    if (queryRefresher) {
      clearInterval(queryRefresher);
    }
  }
});

// input element
var spinner = $(".spinner").spinner({
  spin: function( event, ui ) {
    if ( ui.value < 0 ) {
      $( this ).spinner( "value", 'once only' );
      return false;
    }
  }
});

var ULEN = 70;
function shortenURI(u) {
  return (!u || u.length < ULEN) ? u : (u.substring(0, ULEN - 3) + '…' + u.substring(u.length - 3));
}

function doSearch() {
  var search = { terms : $('#termSearch').val(), annotations : $('#annoSearch').val(),
    from: $('#fromDate').val(), to: $('#toDate').val(),
    member: $('#searchMember').val() }
  fayeClient.publish('/search', search);
  $('.search.button').animate({opacity: 0.2}, 200, 'linear');
}

fayeClient.subscribe('/searchResults', function(results) {
  console.log('/searchResults', results);
  updateResults(results);
});

// delete an item
fayeClient.subscribe('/deletedItem', function(item) {
  console.log('/deletedItem', item, lastResults);
  if (lastResults.hits) {
    var i = 0, l = lastResults.hits.hits.length;
    for (i; i < l; i++) {
      console.log('>>',lastResults.hits.hits[i], item._id);
      if (lastResults.hits.hits[i]._id === item._id) {
        lastResults.hits.hits.splice(i, 1);
        updateResults(lastResults);
        return;
      }
    }
    console.log('deletedItem not found', item);
  }
});

// add a new or updated item
fayeClient.subscribe('/updateItem', function(result) {
  console.log('/updateItem', result, lastResults);
  if (!lastResults.hits) {
    lastResults = { hits: { total : 0, hits: [] } };
  } else {
    var i = 0, l = lastResults.hits.hits.length;
    for (i; i < l; i++) {
      if (lastResults.hits.hits[i]._source.uri === result._source.uri) {
        lastResults.hits.hits.splice(i, 1);
        break;
      }
    }
  }
  lastResults.hits.hits.unshift(result);
  updateResults(lastResults);
});

// for updating
var lastResults;

function updateResults(results) {
  lastResults = results;
  $('.search.button').animate({opacity: 1}, 500, 'linear');
  $('#holder').html('

' +
    'Rank	Document	Visitors	Annotations

');
  if (results.hits) {
    var count = 0;
    results.hits.hits.forEach(function(r) {
      var v = r.fields || r._source;
      var rankVal = r._score ? r._score : ++count;
      var row = '
<input class="selectItem" type="checkbox" name="cb_' + encID(v.uri) + '" />' + rankVal + '	' +
        '
' + (v.title ? v.title : '(no title)') + '
' +
        '' + shortenURI(v.uri) + '
'+
	'	';
      // roll up visitors
      if (v.visitors) {
        var vv = '', va = {};
        v.visitors.forEach(function(visitor) {
          var a = va[visitor.member] || { visits: []};
          a.visits.push(visitor['@timestamp']);
          va[visitor.member] = a;
        });
        for (var a in va) {
          vv += '
' + a + ' ' + va[a].visits.length + '

' + JSON.stringify(va[a].visits) + '
';
        }
        row += '' + vv;
      }
      row += '	';
      if (v.annotationSummary !== undefined) {
        if (v.annotationSummary.validated > 0) {
          row += '
 ' + v.annotationSummary.validated + '

';
        }
        if (v.annotationSummary.unvalidated > 0) {
          row += '
 ' + v.annotationSummary.unvalidated + '

';
        }
      }
      row += '	';
      $('#resultsTable tbody').append(row);
    });

    $('#searchCount').html(results.hits.hits.length);
    $('.sortable.table').tablesort();

  } else {
    $('#results').html('No items.');
    $('#searchCount').html('0');
  }
  setupTable();
  $('table').on('tablesort:complete', function(event, tablesort) {
    setupTable();
  });
}

function setupTable() {
  $('.selectURI').click(selectedURI);
  $('.annotations.button').click(selectedURI);
  $('.showa').click(function() {
    $(this).next().toggle();
  });
  $('.selectItem').click(checkSelected);
}

function checkSelected() {
  var hasSelected = 0;
  $('.selectItem').each(function() {
    if ($(this).is(':checked')) {
      hasSelected++;
    }
  });
  $('.selected.menu').toggle(hasSelected > 0);
  $('.selected.label').html(hasSelected);
}

var curURI;
// display or close uri controls and frame (for link)
function selectedURI(ev) {
  updateOptions.call($('#watch'));
  updateOptions.call($('#filter'));

  var $el = $(this);
  var uri = decodeURIComponent(deEncID($el.parents('tr').attr('id')));

// item options
  $('#itemContext').html(
    '
New window
' +
    '
More like this
' +
    '
Delete
' +
    '
Debug
'
    );
  $('.context.dropdown').dropdown();

  if (curURI == uri) {
    var shown = $('.details.sidebar').sidebar('toggle').hasClass('active');
    if ($el.hasClass('selectURI')) {
      $('#preview').toggle(shown);
    }
  } else {
    fayeClient.publish('/annotate', { uri: uri });
    curURI = uri;
    $('#startingPage').val(uri);
    annotateCurrentURI(uri);
    if ($el.hasClass('selectURI')) {
      $('#preview').remove();
      $el.parent().after('');
    }
    $('.details.sidebar').sidebar('show');
  }
  return false;
}

<commit_msg>highlight selected item<commit_after>
// set up form
// initiate search
$('.search input').keyup(function(e) {
  if(e.keyCode == 13) doSearch();
});
$('#searchForm').click(function(event) {
  doSearch();
});

var queryRefresher;

$('#fromDate').datepicker();
$('#toDate').datepicker();
$('#refreshQueries').click(function(e) {
  if ($(e.target).prop('checked')) {
    queryRefresher = setInterval(doSearch, 5000);
  } else {
    if (queryRefresher) {
      clearInterval(queryRefresher);
    }
  }
});

// input element
var spinner = $(".spinner").spinner({
  spin: function( event, ui ) {
    if ( ui.value < 0 ) {
      $( this ).spinner( "value", 'once only' );
      return false;
    }
  }
});

var ULEN = 70;
function shortenURI(u) {
  return (!u || u.length < ULEN) ? u : (u.substring(0, ULEN - 3) + '…' + u.substring(u.length - 3));
}

function doSearch() {
  var search = { terms : $('#termSearch').val(), annotations : $('#annoSearch').val(),
    from: $('#fromDate').val(), to: $('#toDate').val(),
    member: $('#searchMember').val() }
  fayeClient.publish('/search', search);
  $('.search.button').animate({opacity: 0.2}, 200, 'linear');
}

fayeClient.subscribe('/searchResults', function(results) {
  console.log('/searchResults', results);
  updateResults(results);
});

// delete an item
fayeClient.subscribe('/deletedItem', function(item) {
  console.log('/deletedItem', item, lastResults);
  if (lastResults.hits) {
    var i = 0, l = lastResults.hits.hits.length;
    for (i; i < l; i++) {
      console.log('>>',lastResults.hits.hits[i], item._id);
      if (lastResults.hits.hits[i]._id === item._id) {
        lastResults.hits.hits.splice(i, 1);
        updateResults(lastResults);
        return;
      }
    }
    console.log('deletedItem not found', item);
  }
});

// add a new or updated item
fayeClient.subscribe('/updateItem', function(result) {
  console.log('/updateItem', result, lastResults);
  if (!lastResults.hits) {
    lastResults = { hits: { total : 0, hits: [] } };
  } else {
    var i = 0, l = lastResults.hits.hits.length;
    for (i; i < l; i++) {
      if (lastResults.hits.hits[i]._source.uri === result._source.uri) {
        lastResults.hits.hits.splice(i, 1);
        break;
      }
    }
  }
  lastResults.hits.hits.unshift(result);
  updateResults(lastResults);
});

// for updating
var lastResults;

function updateResults(results) {
  lastResults = results;
  $('.search.button').animate({opacity: 1}, 500, 'linear');
  $('#holder').html('

' +
    'Rank	Document	Visitors	Annotations

');
  if (results.hits) {
    var count = 0;
    results.hits.hits.forEach(function(r) {
      var v = r.fields || r._source;
      var rankVal = r._score ? r._score : ++count;
      var row = '
<input class="selectItem" type="checkbox" name="cb_' + encID(v.uri) + '" />' + rankVal + '	' +
        '
' + (v.title ? v.title : '(no title)') + '
' +
        '' + shortenURI(v.uri) + '
'+
	'	';
      // roll up visitors
      if (v.visitors) {
        var vv = '', va = {};
        v.visitors.forEach(function(visitor) {
          var a = va[visitor.member] || { visits: []};
          a.visits.push(visitor['@timestamp']);
          va[visitor.member] = a;
        });
        for (var a in va) {
          vv += '
' + a + ' ' + va[a].visits.length + '

' + JSON.stringify(va[a].visits) + '
';
        }
        row += '' + vv;
      }
      row += '	';
      if (v.annotationSummary !== undefined) {
        if (v.annotationSummary.validated > 0) {
          row += '
 ' + v.annotationSummary.validated + '

';
        }
        if (v.annotationSummary.unvalidated > 0) {
          row += '
 ' + v.annotationSummary.unvalidated + '

';
        }
      }
      row += '	';
      $('#resultsTable tbody').append(row);
    });

    $('#searchCount').html(results.hits.hits.length);
    $('.sortable.table').tablesort();

  } else {
    $('#results').html('No items.');
    $('#searchCount').html('0');
  }
  setupTable();
  $('table').on('tablesort:complete', function(event, tablesort) {
    setupTable();
  });
}

function setupTable() {
  $('.selectURI').click(selectedURI);
  $('.annotations.button').click(selectedURI);
  $('.showa').click(function() {
    $(this).next().toggle();
  });
  $('.selectItem').click(checkSelected);
}

function checkSelected() {
  var hasSelected = 0;
  $('.selectItem').each(function() {
    if ($(this).is(':checked')) {
      hasSelected++;
    }
  });
  $('.selected.menu').toggle(hasSelected > 0);
  $('.selected.label').html(hasSelected);
}

var curURI;
// display or close uri controls and frame (for link)
function selectedURI(ev) {
  updateOptions.call($('#watch'));
  updateOptions.call($('#filter'));

  var $el = $(this);
  var uri = decodeURIComponent(deEncID($el.parents('tr').attr('id')));

// item options
  $('#itemContext').html(
    '
New window
' +
    '
More like this
' +
    '
Delete
' +
    '
Debug
'
    );
  $('.context.dropdown').dropdown();

  var shown = false;
  if (curURI == uri) {
    shown = $('.details.sidebar').sidebar('toggle').hasClass('active');
    if ($el.hasClass('selectURI')) {
      $('#preview').toggle(shown);
    }
  } else {
    shown = true;
    fayeClient.publish('/annotate', { uri: uri });
    curURI = uri;
    $('#startingPage').val(uri);
    annotateCurrentURI(uri);
    if ($el.hasClass('selectURI')) {
      $('#preview').remove();
      $el.parent().after('');
    }
    $('.details.sidebar').sidebar('show');
  }
  $el.parent().parent().toggleClass('active', shown);
  return false;
}

<|endoftext|>


<commit_before>/*
 * PAGES: Downloads rendered pages from a Bolt server
 */
module.exports = function (grunt) {
    grunt.registerTask('pages', 'Downloads rendered pages from a Bolt server', function () {
        var done = this.async(),
            outpath,
            outfile,
            baseurl,
            pages,
            options,
            queue = [];

        // Require config variables.
        grunt.config.requires(
            'path.tmp',
            'pages.baseurl',
            'pages.requests'
        );

        // Create output directory inside tmp folder.
        outpath = grunt.config('path.tmp') + '/pages';
        grunt.file.mkdir(outpath);

        // Request all required pages.
        pages = grunt.config('pages.requests');
        for (var dest in pages) {
            // Set request options.
            if (typeof pages[dest] === 'object') {
                options = pages[dest];
            } else {
                options = {
                    url: pages[dest] !== '' ? pages[dest] : dest
                };
            }
            options.baseUrl = options.baseUrl || grunt.config('pages.baseurl');

            // Path, where to put the file. Make it always end with ".html"
            outfile = outpath + '/' + dest.replace(/^(.+)\.html$/, '$1') + '.html';

            // Some verbose output.
            grunt.verbose.writeln('Get page "' + outfile + '":');
            grunt.verbose.writeln(require('util').inspect(options, false, 2, true));

            // Build a request queue.
            queue.push({
                opt: options,
                out: outfile
            });
        }

        getNextPage();

        function getNextPage() {
            var next = queue.shift();

            if (next) {
                getNextPage();
            } else {
                done();
            }
        }
    });
};
<commit_msg>Download files<commit_after>/*
 * PAGES: Downloads rendered pages from a Bolt server
 */
module.exports = function (grunt) {
    grunt.registerTask('pages', 'Downloads rendered pages from a Bolt server', function () {
        var request = require('request'),
            done = this.async(),
            outpath,
            outfile,
            baseurl,
            pages,
            options,
            queue = [];

        // Require config variables.
        grunt.config.requires(
            'path.tmp',
            'pages.baseurl',
            'pages.requests'
        );

        // Create output directory inside tmp folder.
        outpath = grunt.config('path.tmp') + '/pages';
        grunt.file.mkdir(outpath);

        // Request all required pages.
        pages = grunt.config('pages.requests');
        for (var dest in pages) {
            // Set request options.
            if (typeof pages[dest] === 'object') {
                options = pages[dest];
            } else {
                options = {
                    url: pages[dest] !== '' ? pages[dest] : dest
                };
            }
            options.baseUrl = options.baseUrl || grunt.config('pages.baseurl');
            options.followAllRedirects = true; // "followRedirect" doesn't seem to work with 302.
            options.jar = true;

            // Path, where to put the file. Make it always end with ".html"
            outfile = outpath + '/' + dest.replace(/^(.+)\.html$/, '$1') + '.html';

            // Build a request queue.
            queue.push({
                opt: options,
                out: outfile
            });
        }

        getNextPage();

        function getNextPage() {
            var next = queue.shift();

            if (next) {
                grunt.log.writeln('Get page "' + next.out + '"');
                grunt.verbose.writeln(require('util').inspect(next.opt, false, 2, true));

                request(
                    next.opt,
                    function (error, response, body) {
                        if (!error && (response.statusCode < 200 || response.statusCode >= 300)) {
                            error = 'Status code: ' + response.statusCode;
                        }
                        if (error) {
                            grunt.fail.warn(error);
                            return done(false);
                        }
                        // Write response body to file.
                        grunt.file.write(next.out, body);
                        // Go on with next request.
                        getNextPage();
                    }
                );
            } else {
                done();
            }
        }
    });
};
<|endoftext|>


<commit_before>YUI().use('event', 'event-focus', function(Y) {Y.on("domready", function() {
    var theApp = new Themer.appView();

    //Stop right click outside of the LIs
    //LI contextmenu listener setup in view.js
    Y.one('body').on('contextmenu', function(e) {
        e.preventDefault();
        //Remove contextual right click options
        // var emptyMenu = Ti.UI.createMenu();
        // Ti.UI.setContextMenu(emptyMenu);
    });

    //Spin up watchers...
    Themer.Watcher.init(theApp);
});});

<commit_msg>Listen for Send Asset event<commit_after>YUI().use('event', 'event-focus','event-custom', function(Y) {Y.on("domready", function() {
    var theApp = new Themer.appView();

    //Stop right click outside of the LIs
    //LI contextmenu listener setup in view.js
    Y.one('body').on('contextmenu', function(e) {
        e.preventDefault();
        //Remove contextual right click options
        // var emptyMenu = Ti.UI.createMenu();
        // Ti.UI.setContextMenu(emptyMenu);
    });

    //Spin up watchers...
    Themer.Watcher.init(theApp);

    Y.Global.on('asset:send', function(e) {
        console.log('asset:send listener');
        //@todo allowed list?
        var key = e.relative,
            path = e.base.concat(Ti.Filesystem.getSeparator(), e.relative);

        Themer.IO.sendAsset(e.shop, e.theme, key, path);
    });
});});

<|endoftext|>


<commit_before>requirejs.config({
  base_url: "/static",
  paths: {
    jquery: "jquery.min",
    marked: "marked.min"
  }
});

require(["jquery"], function($) {
  can_submit = {};
  $("form").each(function(index) {
    can_submit[index] = true;
    $(this).on("submit", function() {
      if (!can_submit[index]) {
        return false;
      }
      can_submit[index] = false;
      return true;
    });
  });
});
<commit_msg>Restore chat link support for .chat_message<commit_after>requirejs.config({
  base_url: "/static",
  paths: {
    jquery: "jquery.min",
    marked: "marked.min"
  }
});

require(["jquery"], function($) {
  can_submit = {};
  $("form").each(function(index) {
    can_submit[index] = true;
    $(this).on("submit", function() {
      if (!can_submit[index]) {
        return false;
      }
      can_submit[index] = false;
      return true;
    });
  });

  $(".chat_message").each(function(index) {
      $(this).html($(this).html().replace(/\"chat:\/\/([0-9a-zA-Z\-]+)\"/g, "\"javascript:OpenChat('$1');\""));
  });
});
<|endoftext|>


<commit_before>/* https://github.com/DiemenDesign/summernote-cleaner */
/* Version: 1.0.6 */
(function(factory) {
  if (typeof define === 'function' && define.amd) {
    define(['jquery'], factory);
  } else if (typeof module === 'object'&&module.exports) {
    module.exports = factory(require('jquery'));
  } else {
    factory(window.jQuery);
  }
}
(function ($) {
  $.extend(true, $.summernote.lang, {
    'en-US': {
      cleaner: {
        tooltip: 'Cleaner',
        not: 'Text has been cleaned!',
        limitText: 'Text',
        limitHTML: 'HTML'
      }
    },
    'de-DE': {
      cleaner: {
        tooltip: 'Reinigungskraft',
        not: 'Inhalt wurde bereinigt!',
        limitText: 'Text',
        limitHTML: 'HTML'
      }
    },
  });
  $.extend( $.summernote.options, {
    cleaner: {
      action: 'both', // both|button|paste 'button' only cleans via toolbar button, 'paste' only clean when pasting content, both does both options.
      icon: '<svg xmlns="http://www.w3.org/2000/svg" id="libre-paintbrush" viewBox="0 0 14 14" width="14" height="14"><path d="m 11.821425,1 q 0.46875,0 0.82031,0.311384 0.35157,0.311384 0.35157,0.780134 0,0.421875 -0.30134,1.01116 -2.22322,4.212054 -3.11384,5.035715 -0.64956,0.609375 -1.45982,0.609375 -0.84375,0 -1.44978,-0.61942 -0.60603,-0.61942 -0.60603,-1.469866 0,-0.857143 0.61608,-1.419643 l 4.27232,-3.877232 Q 11.345985,1 11.821425,1 z m -6.08705,6.924107 q 0.26116,0.508928 0.71317,0.870536 0.45201,0.361607 1.00781,0.508928 l 0.007,0.475447 q 0.0268,1.426339 -0.86719,2.32366 Q 5.700895,13 4.261155,13 q -0.82366,0 -1.45982,-0.311384 -0.63616,-0.311384 -1.0212,-0.853795 -0.38505,-0.54241 -0.57924,-1.225446 -0.1942,-0.683036 -0.1942,-1.473214 0.0469,0.03348 0.27455,0.200893 0.22768,0.16741 0.41518,0.29799 0.1875,0.130581 0.39509,0.24442 0.20759,0.113839 0.30804,0.113839 0.27455,0 0.3683,-0.247767 0.16741,-0.441965 0.38505,-0.753349 0.21763,-0.311383 0.4654,-0.508928 0.24776,-0.197545 0.58928,-0.31808 0.34152,-0.120536 0.68974,-0.170759 0.34821,-0.05022 0.83705,-0.07031 z"/></svg>',
      keepHtml: true,
      keepTagContents: ['span'], //Remove tags and keep the contents
      badTags: ['applet', 'col', 'colgroup', 'embed', 'noframes', 'noscript', 'script', 'style', 'title', 'meta', 'link', 'head'], //Remove full tags with contents
      badAttributes: ['bgcolor', 'border', 'height', 'cellpadding', 'cellspacing', 'lang', 'start', 'style', 'valign', 'width', 'data-(.*?)'], //Remove attributes from remaining tags
      limitChars: 0, // 0|# 0 disables option
      limitDisplay: 'both', // none|text|html|both
      limitStop: false, // true/false
      notTimeOut: 850, //time before status message is hidden in miliseconds
      imagePlaceholder: 'https://via.placeholder.com/200'
    }
  });
  $.extend( $.summernote.plugins, {
    'cleaner': function (context) {
      var self = this,
            ui = $.summernote.ui,
         $note = context.layoutInfo.note,
       $editor = context.layoutInfo.editor,
       options = context.options,
          lang = options.langInfo;
      if (options.cleaner.action == 'both' || options.cleaner.action == 'button') {
        context.memo('button.cleaner', function () {
          var button = ui.button({
            contents: options.cleaner.icon,
            container: options.container,
            tooltip: lang.cleaner.tooltip,
            placement: options.placement,
            click: function () {
              if ($note.summernote('createRange').toString())
                $note.summernote('pasteHTML', $note.summernote('createRange').toString());
              else
                $note.summernote('code', cleanPaste($note.summernote('code'), options.cleaner.badTags, options.cleaner.keepTagContents, options.cleaner.badAttributes, options.cleaner.imagePlaceholder), true);
              if ($editor.find('.note-status-output').length > 0)
                $editor.find('.note-status-output').html(lang.cleaner.not);
            }
          });
          return button.render();
        });
      }
      this.events = {
        'summernote.init': function () {
          if (options.cleaner.limitChars != 0 || options.cleaner.limitDisplay != 'none'){
            var textLength = $editor.find(".note-editable").text().replace(/(<([^>]+)>)/ig, "").replace(/( )/," ");
            var codeLength = $editor.find('.note-editable').html();
            var lengthStatus = '';
            if (textLength.length > options.cleaner.limitChars&&options.cleaner.limitChars > 0)
              lengthStatus += 'note-text-danger">';
            else
              lengthStatus += '">';
            if (options.cleaner.limitDisplay == 'text' || options.cleaner.limitDisplay == 'both')
              lengthStatus += lang.cleaner.limitText + ': ' + textLength.length;
            if (options.cleaner.limitDisplay == 'both')
              lengthStatus += ' / ';
            if (options.cleaner.limitDisplay == 'html' || options.cleaner.limitDisplay == 'both')
              lengthStatus += lang.cleaner.limitHTML + ': ' + codeLength.length;
            $editor.find('.note-status-output').html('<small class="note-pull-right ' + lengthStatus + ' ');
          }
        },
        'summernote.keydown': function (we, event) {
          if (options.cleaner.limitChars != 0 || options.cleaner.limitDisplay != 'none') {
            var textLength = $editor.find(".note-editable").text().replace(/(<([^>]+)>)/ig, "").replace(/( )/, " ");
            var codeLength = $editor.find('.note-editable').html();
            var lengthStatus = '';
            if (options.cleaner.limitStop == true && textLength.length >= options.cleaner.limitChars) {
              var key = event.keyCode;
              allowed_keys = [8, 37, 38, 39, 40, 46];
              if ($.inArray(key,allowed_keys) != -1){
                $editor.find('.cleanerLimit').removeClass('note-text-danger');
                return true;
              } else {
                $editor.find('.cleanerLimit').addClass('note-text-danger');
                event.preventDefault();
                event.stopPropagation();
              }
            } else {
              if (textLength.length > options.cleaner.limitChars && options.cleaner.limitChars > 0)
                lengthStatus += 'note-text-danger">';
              else
                lengthStatus += '">';
              if (options.cleaner.limitDisplay == 'text' || options.cleaner.limitDisplay == 'both')
                lengthStatus += lang.cleaner.limitText + ': '+textLength.length;
              if (options.cleaner.limitDisplay == 'both')
                lengthStatus += ' / ';
              if (options.cleaner.limitDisplay == 'html' || options.cleaner.limitDisplay == 'both')
                lengthStatus += lang.cleaner.limitHTML + ': ' + codeLength.length;
              $editor.find('.note-status-output').html('<small class="cleanerLimit note-pull-right ' + lengthStatus + ' ');
            }
          }
        },
        'summernote.paste': function(we, event) {
          if (options.cleaner.action=='both' || options.cleaner.action == 'paste') {
            event.preventDefault();
            var ua = window.navigator.userAgent;
            var msie = ua.indexOf("MSIE ");
                msie = msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./);
            var ffox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
            var text; var isHtmlData = false;
            if (msie)
              text = window.clipboardData.getData("Text");
            else
            {
              var dataType = 'text/plain';
              /*only get the html data if its avaialble else use plain text*/
              if (options.cleaner.keepHtml && event.originalEvent.clipboardData.types.indexOf('text/html') > -1) {
                  dataType = 'text/html';
                  isHtmlData = true;
              }
              text = event.originalEvent.clipboardData.getData(dataType);
            }
            if (text) {
              if (msie || ffox) {
                setTimeout(function () {
                  $note.summernote('pasteHTML', cleanPaste(text, options.cleaner.badTags, options.cleaner.keepTagContents, options.cleaner.badAttributes, options.cleaner.imagePlaceholder, isHtmlData));
                }, 1);
              } else
                $note.summernote('pasteHTML', cleanPaste(text, options.cleaner.badTags, options.cleaner.keepTagContents, options.cleaner.badAttributes, options.cleaner.imagePlaceholder, isHtmlData));
              if ($editor.find('.note-status-output').length > 0) {
                $editor.find('.note-status-output').html(lang.cleaner.not);
                /*now set a timeout to clear out the message */
                setTimeout(function(){
                  if($editor.find('.note-status-output').html() == lang.cleaner.not){
                    /*lets fade out the text, then clear it and show the control ready for next time */
                    $editor.find('.note-status-output').fadeOut(function(){
                      $(this).html("");
                      $(this).fadeIn();
                    });
                  }
                }, options.cleaner.notTimeOut)
              }
            }
          }
        }
      }
      var cleanPaste = function(input, badTags, keepTagContents, badAttributes, imagePlaceholder, isHtmlData) {
        if(isHtmlData) {
          return cleanHtmlPaste(input, badTags, keepTagContents, badAttributes, imagePlaceholder);
        } else {
          return cleanTextPaste(input);
        }
      };

      var cleanTextPaste = function(input) {
        var newLines = /(\r\n|\r|\n)/g;
        var parsedInput = input.split(newLines);
        if(parsedInput.length === 1) { return input; }
        var output = "";
        /*for larger blocks of text (such as multiple paragraphs) match summernote markup */
        for (let contentIndex = 0; contentIndex < parsedInput.length; contentIndex++) {
          const element = parsedInput[contentIndex];
          if(!newLines.test(element)) {
            var line = element == '' ? '
' : element;
            output += '
' + line + '
'
          }
        }
        return output;
      }

      var cleanHtmlPaste = function(input, badTags, keepTagContents, badAttributes, imagePlaceholder) {
        var stringStripper = /( class=(")?Mso[a-zA-Z]+(")?)/gmi;
        /*remove MS office class crud*/
        var output = input.replace(stringStripper, '');
        var commentStripper = new RegExp('', 'gmi');
        output = output.replace(commentStripper, '');
        /*remove MS office comment if else crud */
        var commentIfStripper = new RegExp('<![^>\v]*>', 'gmi');
        output = output.replace(commentIfStripper, '');
        var tagStripper = new RegExp('<(/)*(\\?xml:|st1:|o:|v:)[^>\v]*>', 'gmi');
        output = output.replace(/ src="(.*?)"/gmi, ' src="' + imagePlaceholder + '"');
        output = output.replace(/ name="(.*?)"/gmi, ' data-title="$1" alt="$1"');
        /*remove MS office tag crud*/
        output = output.replace(tagStripper, '');
        for (var i = 0; i < badTags.length; i++) {
          const badTag = badTags[i];
          /*remove the tag and its contents*/
          tagStripper = new RegExp('<' + badTag + '(.|\r|\n)*</' + badTag + '[^>\v]*>', 'gmi');
          output = output.replace(tagStripper, '');
          /*remove tags with no ending tag or rogue ending tags*/
          var singletonTagStripper = new RegExp('</?' + badTag + '[^>\v]*>', 'gmi');
          output = output.replace(singletonTagStripper, '');
        }
        for (var i = 0; i < keepTagContents.length; i++) {
          /*remove tags only*/
          tagStripper = new RegExp('</?' + keepTagContents[i] + '[^>\v]*>', 'gmi');
          output = output.replace(tagStripper, ' ');
        }
        for (var i = 0; i < badAttributes.length; i++) {
          const badAttribute = badAttributes[i];
          /*for attribute matching ensure we match a new line or some kind of space to prevents partial matching for attributes
          (e.g. color would modify bgcolor tag to be just bg) */
          var attributeWithSpeechMarksStripper = new RegExp('(\s|\r\n|\r|\n| )' + badAttribute + '="[^"\v]*"', 'gmi');
          output = output.replace(attributeWithSpeechMarksStripper, '');
          var attributeWithApostropheStripper = new RegExp('(\s|\r\n|\r|\n| )' + badAttribute + "='[^'\v]*'", 'gmi');
          output = output.replace(attributeWithApostropheStripper, '');
        }
        output = output.replace(/ align="(.*?)"/gi, ' class="text-$1"');
        output = output.replace(/ class="western"/gi, '');
        output = output.replace(/ class=""/gi, '');
        output = output.replace(/(.*?)<\/b>/gi, '$1');
        output = output.replace(/(.*?)<\/i>/gi, '$1');
        output = output.replace(/\s{2,}/g, ' ').trim();
        return output;
      }
    }
  });
}));
<commit_msg>bug\codeview not in synch<commit_after>/* https://github.com/DiemenDesign/summernote-cleaner */
/* Version: 1.0.7 */
(function(factory) {
  if (typeof define === 'function' && define.amd) {
    define(['jquery'], factory);
  } else if (typeof module === 'object'&&module.exports) {
    module.exports = factory(require('jquery'));
  } else {
    factory(window.jQuery);
  }
}
(function ($) {
  $.extend(true, $.summernote.lang, {
    'en-US': {
      cleaner: {
        tooltip: 'Cleaner',
        not: 'Text has been cleaned!',
        limitText: 'Text',
        limitHTML: 'HTML'
      }
    },
    'de-DE': {
      cleaner: {
        tooltip: 'Reinigungskraft',
        not: 'Inhalt wurde bereinigt!',
        limitText: 'Text',
        limitHTML: 'HTML'
      }
    },
  });
  $.extend( $.summernote.options, {
    cleaner: {
      action: 'both', // both|button|paste 'button' only cleans via toolbar button, 'paste' only clean when pasting content, both does both options.
      icon: '<svg xmlns="http://www.w3.org/2000/svg" id="libre-paintbrush" viewBox="0 0 14 14" width="14" height="14"><path d="m 11.821425,1 q 0.46875,0 0.82031,0.311384 0.35157,0.311384 0.35157,0.780134 0,0.421875 -0.30134,1.01116 -2.22322,4.212054 -3.11384,5.035715 -0.64956,0.609375 -1.45982,0.609375 -0.84375,0 -1.44978,-0.61942 -0.60603,-0.61942 -0.60603,-1.469866 0,-0.857143 0.61608,-1.419643 l 4.27232,-3.877232 Q 11.345985,1 11.821425,1 z m -6.08705,6.924107 q 0.26116,0.508928 0.71317,0.870536 0.45201,0.361607 1.00781,0.508928 l 0.007,0.475447 q 0.0268,1.426339 -0.86719,2.32366 Q 5.700895,13 4.261155,13 q -0.82366,0 -1.45982,-0.311384 -0.63616,-0.311384 -1.0212,-0.853795 -0.38505,-0.54241 -0.57924,-1.225446 -0.1942,-0.683036 -0.1942,-1.473214 0.0469,0.03348 0.27455,0.200893 0.22768,0.16741 0.41518,0.29799 0.1875,0.130581 0.39509,0.24442 0.20759,0.113839 0.30804,0.113839 0.27455,0 0.3683,-0.247767 0.16741,-0.441965 0.38505,-0.753349 0.21763,-0.311383 0.4654,-0.508928 0.24776,-0.197545 0.58928,-0.31808 0.34152,-0.120536 0.68974,-0.170759 0.34821,-0.05022 0.83705,-0.07031 z"/></svg>',
      keepHtml: true,
      keepTagContents: ['span'], //Remove tags and keep the contents
      badTags: ['applet', 'col', 'colgroup', 'embed', 'noframes', 'noscript', 'script', 'style', 'title', 'meta', 'link', 'head'], //Remove full tags with contents
      badAttributes: ['bgcolor', 'border', 'height', 'cellpadding', 'cellspacing', 'lang', 'start', 'style', 'valign', 'width', 'data-(.*?)'], //Remove attributes from remaining tags
      limitChars: 0, // 0|# 0 disables option
      limitDisplay: 'both', // none|text|html|both
      limitStop: false, // true/false
      notTimeOut: 850, //time before status message is hidden in miliseconds
      imagePlaceholder: 'https://via.placeholder.com/200'
    }
  });
  $.extend( $.summernote.plugins, {
    'cleaner': function (context) {
      var self = this,
            ui = $.summernote.ui,
         $note = context.layoutInfo.note,
       $editor = context.layoutInfo.editor,
       options = context.options,
          lang = options.langInfo;
      if (options.cleaner.action == 'both' || options.cleaner.action == 'button') {
        context.memo('button.cleaner', function () {
          var button = ui.button({
            contents: options.cleaner.icon,
            container: options.container,
            tooltip: lang.cleaner.tooltip,
            placement: options.placement,
            click: function () {
              if ($note.summernote('createRange').toString())
                $note.summernote('pasteHTML', $note.summernote('createRange').toString());
              else
                $note.summernote('code', cleanPaste($note.summernote('code'), options.cleaner.badTags, options.cleaner.keepTagContents, options.cleaner.badAttributes, options.cleaner.imagePlaceholder), true);
              if ($editor.find('.note-status-output').length > 0)
                $editor.find('.note-status-output').html(lang.cleaner.not);
            }
          });
          return button.render();
        });
      }
      this.events = {
        'summernote.init': function () {
          if (options.cleaner.limitChars != 0 || options.cleaner.limitDisplay != 'none'){
            var textLength = $editor.find(".note-editable").text().replace(/(<([^>]+)>)/ig, "").replace(/( )/," ");
            var codeLength = $editor.find('.note-editable').html();
            var lengthStatus = '';
            if (textLength.length > options.cleaner.limitChars&&options.cleaner.limitChars > 0)
              lengthStatus += 'note-text-danger">';
            else
              lengthStatus += '">';
            if (options.cleaner.limitDisplay == 'text' || options.cleaner.limitDisplay == 'both')
              lengthStatus += lang.cleaner.limitText + ': ' + textLength.length;
            if (options.cleaner.limitDisplay == 'both')
              lengthStatus += ' / ';
            if (options.cleaner.limitDisplay == 'html' || options.cleaner.limitDisplay == 'both')
              lengthStatus += lang.cleaner.limitHTML + ': ' + codeLength.length;
            $editor.find('.note-status-output').html('<small class="note-pull-right ' + lengthStatus + ' ');
          }
        },
        'summernote.keydown': function (we, event) {
          if (options.cleaner.limitChars != 0 || options.cleaner.limitDisplay != 'none') {
            var textLength = $editor.find(".note-editable").text().replace(/(<([^>]+)>)/ig, "").replace(/( )/, " ");
            var codeLength = $editor.find('.note-editable').html();
            var lengthStatus = '';
            if (options.cleaner.limitStop == true && textLength.length >= options.cleaner.limitChars) {
              var key = event.keyCode;
              allowed_keys = [8, 37, 38, 39, 40, 46];
              if ($.inArray(key,allowed_keys) != -1){
                $editor.find('.cleanerLimit').removeClass('note-text-danger');
                return true;
              } else {
                $editor.find('.cleanerLimit').addClass('note-text-danger');
                event.preventDefault();
                event.stopPropagation();
              }
            } else {
              if (textLength.length > options.cleaner.limitChars && options.cleaner.limitChars > 0)
                lengthStatus += 'note-text-danger">';
              else
                lengthStatus += '">';
              if (options.cleaner.limitDisplay == 'text' || options.cleaner.limitDisplay == 'both')
                lengthStatus += lang.cleaner.limitText + ': '+textLength.length;
              if (options.cleaner.limitDisplay == 'both')
                lengthStatus += ' / ';
              if (options.cleaner.limitDisplay == 'html' || options.cleaner.limitDisplay == 'both')
                lengthStatus += lang.cleaner.limitHTML + ': ' + codeLength.length;
              $editor.find('.note-status-output').html('<small class="cleanerLimit note-pull-right ' + lengthStatus + ' ');
            }
          }
        },
        'summernote.paste': function(we, event) {
          if (options.cleaner.action=='both' || options.cleaner.action == 'paste') {
            event.preventDefault();
            var ua = window.navigator.userAgent;
            var msie = ua.indexOf("MSIE ");
                msie = msie > 0 || !!navigator.userAgent.match(/Trident.*rv\:11\./);
            var ffox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
            var text; var isHtmlData = false;
            if (msie)
              text = window.clipboardData.getData("Text");
            else
            {
              var dataType = 'text/plain';
              /*only get the html data if its avaialble else use plain text*/
              if (options.cleaner.keepHtml && event.originalEvent.clipboardData.types.indexOf('text/html') > -1) {
                  dataType = 'text/html';
                  isHtmlData = true;
              }
              text = event.originalEvent.clipboardData.getData(dataType);
            }
            if (text) {
              /*clean the text first to prevent issues where code view wasn't updating correctly*/
              var cleanedContent = cleanPaste(text, options.cleaner.badTags, options.cleaner.keepTagContents, options.cleaner.badAttributes, options.cleaner.imagePlaceholder, isHtmlData);
              if (msie || ffox) {
                setTimeout(function () {
                  $note.summernote('pasteHTML', cleanedContent);
                }, 1);
              } else {
                $note.summernote('pasteHTML', cleanedContent);
              }

              if ($editor.find('.note-status-output').length > 0) {
                $editor.find('.note-status-output').html(lang.cleaner.not);
                /*now set a timeout to clear out the message */
                setTimeout(function(){
                  if($editor.find('.note-status-output').html() == lang.cleaner.not){
                    /*lets fade out the text, then clear it and show the control ready for next time */
                    $editor.find('.note-status-output').fadeOut(function(){
                      $(this).html("");
                      $(this).fadeIn();
                    });
                  }
                }, options.cleaner.notTimeOut)
              }
            }
          }
        }
      }
      var cleanPaste = function(input, badTags, keepTagContents, badAttributes, imagePlaceholder, isHtmlData) {
        if(isHtmlData) {
          return cleanHtmlPaste(input, badTags, keepTagContents, badAttributes, imagePlaceholder);
        } else {
          return cleanTextPaste(input);
        }
      };

      var cleanTextPaste = function(input) {
        var newLines = /(\r\n|\r|\n)/g;
        var parsedInput = input.split(newLines);
        if(parsedInput.length === 1) { return input; }
        var output = "";
        /*for larger blocks of text (such as multiple paragraphs) match summernote markup */
        for (let contentIndex = 0; contentIndex < parsedInput.length; contentIndex++) {
          const element = parsedInput[contentIndex];
          if(!newLines.test(element)) {
            var line = element == '' ? '
' : element;
            output += '
' + line + '
'
          }
        }
        return output;
      }

      var cleanHtmlPaste = function(input, badTags, keepTagContents, badAttributes, imagePlaceholder) {
        var stringStripper = /( class=(")?Mso[a-zA-Z]+(")?)/gmi;
        /*remove MS office class crud*/
        var output = input.replace(stringStripper, '');
        var commentStripper = new RegExp('', 'gmi');
        output = output.replace(commentStripper, '');
        /*remove MS office comment if else crud */
        var commentIfStripper = new RegExp('<![^>\v]*>', 'gmi');
        output = output.replace(commentIfStripper, '');
        var tagStripper = new RegExp('<(/)*(\\?xml:|st1:|o:|v:)[^>\v]*>', 'gmi');
        output = output.replace(/ src="(.*?)"/gmi, ' src="' + imagePlaceholder + '"');
        output = output.replace(/ name="(.*?)"/gmi, ' data-title="$1" alt="$1"');
        /*remove MS office tag crud*/
        output = output.replace(tagStripper, '');
        for (var i = 0; i < badTags.length; i++) {
          const badTag = badTags[i];
          /*remove the tag and its contents*/
          tagStripper = new RegExp('<' + badTag + '(.|\r|\n)*</' + badTag + '[^>\v]*>', 'gmi');
          output = output.replace(tagStripper, '');
          /*remove tags with no ending tag or rogue ending tags*/
          var singletonTagStripper = new RegExp('</?' + badTag + '[^>\v]*>', 'gmi');
          output = output.replace(singletonTagStripper, '');
        }
        for (var i = 0; i < keepTagContents.length; i++) {
          /*remove tags only*/
          tagStripper = new RegExp('</?' + keepTagContents[i] + '[^>\v]*>', 'gmi');
          output = output.replace(tagStripper, ' ');
        }
        for (var i = 0; i < badAttributes.length; i++) {
          const badAttribute = badAttributes[i];
          /*for attribute matching ensure we match a new line or some kind of space to prevents partial matching for attributes
          (e.g. color would modify bgcolor tag to be just bg) */
          var attributeWithSpeechMarksStripper = new RegExp('(\s|\r\n|\r|\n| )' + badAttribute + '="[^"\v]*"', 'gmi');
          output = output.replace(attributeWithSpeechMarksStripper, '');
          var attributeWithApostropheStripper = new RegExp('(\s|\r\n|\r|\n| )' + badAttribute + "='[^'\v]*'", 'gmi');
          output = output.replace(attributeWithApostropheStripper, '');
        }
        output = output.replace(/ align="(.*?)"/gi, ' class="text-$1"');
        output = output.replace(/ class="western"/gi, '');
        output = output.replace(/ class=""/gi, '');
        output = output.replace(/(.*?)<\/b>/gi, '$1');
        output = output.replace(/(.*?)<\/i>/gi, '$1');
        output = output.replace(/\s{2,}/g, ' ').trim();
        return output;
      }
    }
  });
}));
<|endoftext|>