<commit_before>// INSTALL SUB TASK
// install is called at the create task time, but you can also call it in an already
// created project if you want to reinstall things:
// - installScript method looks if there are no such global bin/install.sh script to be executed
// - installKubernetes checks if your kubernetes config is okay for a potential deploy via this platform
// - teleport have some python scripts therefore installAppRequirements makes sure that they
// are installed in the bound venv
// - installSecrets install empty json config file put in the server config folders
// - replace is an important sub task that you need to see specifically in the replace.js script
// - finally installServers parse all the servers to do their own specific install process by executing
// their scripts/install.sh file

import childProcess from 'child_process'
import fs from 'fs'
import path from 'path'

export function install () {
  const { backend, app, program, project } = this
  if (!backend) return
  // normally the install commands run themselves,
  // but when using a shell like concurrently we collect the commands
  // in an array in order to call them at once
  if (program.shell === 'concurrently') {
    this.concurrentlyInstallCommands = []
  }
  this.consoleInfo(`Let\'s install this project !`)
  // NOTE: this.concurrentlyInstallCommands is populated by the following commands
  this.installScript()
  this.installKubernetes()
  this.installAppRequirements()
  this.installSecrets()
  this.write(this.project)
  this.replace()
  this.installServers()
  // now execute the collected commands if shell is concurrently
  if (program.shell === 'concurrently') {
    const concurrentlyInstallCommandsString = this.concurrentlyInstallCommands
      .map(concurrentlyCommand => `\"${concurrentlyCommand}\"`)
      .join(' ')
    const command = `${app.concurrentlyDir} ${concurrentlyInstallCommandsString}`
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  }
  this.consoleInfo(`install was successful !`)
}

export function installScript () {
  const { app, program } = this
  // check if exists
  if (!fs.existsSync(path.join(this.project.dir, 'bin/install.sh'))) return
  let command = `cd ${this.project.dir} && sh bin/install.sh`
  // if the shell is concurrently, we don't want actually to execute
  // the code directly but put it in the temp commands array
  if (program.shell !== 'concurrently') {
    this.consoleInfo('Let\'s install the project')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  } else {
    this.concurrentlyInstallCommands.push(command)
  }
}

export function installKubernetes () {
  const { project } = this
  if (!project.config.backend || !project.config.backend.kubernetes) {
    return
  }
  this.consoleInfo('Let\'s install kubernetes configs')
  const command = this.getInstallKubernetesCommand()
  this.consoleLog(command)
  childProcess.execSync(command, { stdio: [0, 1, 2] })
  this.consoleInfo('kubernetes configs are installed !')
}

export function getInstallKubernetesCommand () {
  this.checkProject()
  const { kubernetes, project: { dir } } = this
  if (typeof kubernetes === 'undefined') {
    this.consoleError('You must define a kubernetes config')
    process.exit(1)
  }
  let commands = [`cd ${path.join(dir, 'bin')}`]
  commands.push(`kubectl config set-cluster master --server=http://${kubernetes.host}:${kubernetes.port}`)
  commands.push('kubectl config set-context master --cluster=master')
  commands.push('kubectl config use-context master')
  commands.push('kubectl get nodes')
  return commands.join(' && ')
}

export function installDocker () {
  const { docker } = this
  const dockerVersionDigit = parseInt(childProcess
    .execSync('docker version --format \'{{.Client.Version}}\'')
    .toString('utf-8')
    .replace(/(\.+)/g, ''))
  const projectDockerVersion = docker.version
  const projectDockerVersionDigit = parseInt(projectDockerVersion
    .replace(/(\.+)/g, ''))
  if (dockerVersionDigit > projectDockerVersionDigit) {
    const dockerFile = `docker-${project.dockerVersion}`
    const command = [
      `exec wget https://get.docker.com/builds/Darwin/x86_64/${projectDockerVersion}`,
      `cp ${dockerFile} $(which docker)`,
      `rm ${dockerFile}`
    ].join(' && ')
    this.consoleInfo(`Let\'s install a good docker version, that one : ${projectDockerVersion}`)
    this.consoleLog(command)
    childProcess.execSync(command)
  }
}

export function installAppRequirements () {
  const { app, program } = this
  this.consoleInfo('Let \'s install in the venv the tpt requirements')
  let command = `pip install ${app.requirements.join(' ')}`
  // if the shell is concurrently, we don't want actually to execute
  // the code directly but put it in the temp commands array
  if (program.shell !== 'concurrently') {
    this.consoleInfo('Let\'s install the project')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  } else {
    this.concurrentlyInstallCommands.push(command)
  }
}

export function installServers () {
  const { program } = this
  program.image = undefined
  program.method = 'installServer'
  program.methods = null
  program.type = 'localhost'
  this.setTypeEnvironment()
  this.mapInServers()
}

export function installServer () {
  const { app, program, server } = this
  const commands = []
  let fileName = 'install.sh'
  fileName = `localhost_${fileName}`
  let fileDir = path.join(server.dir, 'scripts', fileName)
  if (!fs.existsSync(fileDir)) {
    fileName = 'install.sh'
  }
  this.consoleInfo(`Let\'s launch the ${fileName} needed in the server... it can\'t take a long time`)
  // for now for settings like Xcode8 with ElCaptain uwsgi in venv install breaks, and only solution is
  // to do that with sudo
  commands.push(`cd ${server.dir}`)
  commands.push(`${program.permission} sh scripts/${fileName}`)
  let command = commands.join(' && ')
  // if the shell is concurrently, we don't want actually to execute
  // the code directly but put it in the temp commands array
  if (program.shell !== 'concurrently') {
    this.consoleInfo('Let\'s install the project')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  } else {
    this.concurrentlyInstallCommands.push(command)
  }
}

export function installSecrets () {
  const { program } = this
  program.base = null
  program.method = 'installSecret'
  program.methods = null
  this.mapInServers()
}

export function installSecret () {
  const { server } = this
  // configure maybe an empty secret
  const secretDir = path.join(server.dir, 'config/secret.json')
  if (!fs.existsSync(secretDir)) {
    fs.writeFileSync(secretDir, '{}')
  }
}
<commit_msg>improve formatting and add missing radix for parseInt call<commit_after>// INSTALL SUB TASK
// install is called at the create task time, but you can also call it in an already
// created project if you want to reinstall things:
// - installScript method looks if there are no such global bin/install.sh script to be executed
// - installKubernetes checks if your kubernetes config is okay for a potential deploy via this platform
// - teleport have some python scripts therefore installAppRequirements makes sure that they
// are installed in the bound venv
// - installSecrets install empty json config file put in the server config folders
// - replace is an important sub task that you need to see specifically in the replace.js script
// - finally installServers parse all the servers to do their own specific install process by executing
// their scripts/install.sh file

import childProcess from 'child_process'
import fs from 'fs'
import path from 'path'

export function install () {
  const { backend, app, program, project } = this
  if (!backend) return
  // normally the install commands run themselves,
  // but when using a shell like concurrently we collect the commands
  // in an array in order to call them at once
  if (program.shell === 'concurrently') {
    this.concurrentlyInstallCommands = []
  }
  this.consoleInfo(`Let\'s install this project !`)
  // NOTE: this.concurrentlyInstallCommands is populated by the following commands
  this.installScript()
  this.installKubernetes()
  this.installAppRequirements()
  this.installSecrets()
  this.write(this.project)
  this.replace()
  this.installServers()
  // now execute the collected commands if shell is concurrently
  if (program.shell === 'concurrently') {
    const concurrentlyInstallCommandsString = this.concurrentlyInstallCommands
      .map(concurrentlyCommand => `\"${concurrentlyCommand}\"`)
      .join(' ')
    const command = `${app.concurrentlyDir} ${concurrentlyInstallCommandsString}`
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  }
  this.consoleInfo(`install was successful !`)
}

export function installScript () {
  const { app, program } = this
  // check if exists
  if (!fs.existsSync(path.join(this.project.dir, 'bin/install.sh'))) return
  let command = `cd ${this.project.dir} && sh bin/install.sh`
  // if the shell is concurrently, we don't want actually to execute
  // the code directly but put it in the temp commands array
  if (program.shell !== 'concurrently') {
    this.consoleInfo('Let\'s install the project')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  } else {
    this.concurrentlyInstallCommands.push(command)
  }
}

export function installKubernetes () {
  const { project } = this
  if (!project.config.backend || !project.config.backend.kubernetes) {
    return
  }
  this.consoleInfo('Let\'s install kubernetes configs')
  const command = this.getInstallKubernetesCommand()
  this.consoleLog(command)
  childProcess.execSync(command, { stdio: [0, 1, 2] })
  this.consoleInfo('kubernetes configs are installed !')
}

export function getInstallKubernetesCommand () {
  this.checkProject()
  const { kubernetes, project: { dir } } = this
  if (typeof kubernetes === 'undefined') {
    this.consoleError('You must define a kubernetes config')
    process.exit(1)
  }
  let commands = [`cd ${path.join(dir, 'bin')}`]
  commands.push(`kubectl config set-cluster master --server=http://${kubernetes.host}:${kubernetes.port}`)
  commands.push('kubectl config set-context master --cluster=master')
  commands.push('kubectl config use-context master')
  commands.push('kubectl get nodes')
  return commands.join(' && ')
}

export function installDocker () {
  const { docker } = this
  const dockerVersionDigit = parseInt(
    childProcess
      .execSync('docker version --format \'{{.Client.Version}}\'')
      .toString('utf-8')
      .replace(/(\.+)/g, '')
    , 10
  )
  const projectDockerVersion = docker.version
  const projectDockerVersionDigit = parseInt(
    projectDockerVersion.replace(/(\.+)/g, ''),
    10
  )
  if (dockerVersionDigit > projectDockerVersionDigit) {
    const dockerFile = `docker-${project.dockerVersion}`
    const command = [
      `exec wget https://get.docker.com/builds/Darwin/x86_64/${projectDockerVersion}`,
      `cp ${dockerFile} $(which docker)`,
      `rm ${dockerFile}`
    ].join(' && ')
    this.consoleInfo(`Let\'s install a good docker version, that one : ${projectDockerVersion}`)
    this.consoleLog(command)
    childProcess.execSync(command)
  }
}

export function installAppRequirements () {
  const { app, program } = this
  this.consoleInfo('Let \'s install in the venv the tpt requirements')
  let command = `pip install ${app.requirements.join(' ')}`
  // if the shell is concurrently, we don't want actually to execute
  // the code directly but put it in the temp commands array
  if (program.shell !== 'concurrently') {
    this.consoleInfo('Let\'s install the project')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  } else {
    this.concurrentlyInstallCommands.push(command)
  }
}

export function installServers () {
  const { program } = this
  program.image = undefined
  program.method = 'installServer'
  program.methods = null
  program.type = 'localhost'
  this.setTypeEnvironment()
  this.mapInServers()
}

export function installServer () {
  const { app, program, server } = this
  const commands = []
  let fileName = 'install.sh'
  fileName = `localhost_${fileName}`
  let fileDir = path.join(server.dir, 'scripts', fileName)
  if (!fs.existsSync(fileDir)) {
    fileName = 'install.sh'
  }
  this.consoleInfo(`Let\'s launch the ${fileName} needed in the server... it can\'t take a long time`)
  // for now for settings like Xcode8 with ElCaptain uwsgi in venv install breaks, and only solution is
  // to do that with sudo
  commands.push(`cd ${server.dir}`)
  commands.push(`${program.permission} sh scripts/${fileName}`)
  let command = commands.join(' && ')
  // if the shell is concurrently, we don't want actually to execute
  // the code directly but put it in the temp commands array
  if (program.shell !== 'concurrently') {
    this.consoleInfo('Let\'s install the project')
    this.consoleLog(command)
    childProcess.execSync(command, { stdio: [0, 1, 2] })
  } else {
    this.concurrentlyInstallCommands.push(command)
  }
}

export function installSecrets () {
  const { program } = this
  program.base = null
  program.method = 'installSecret'
  program.methods = null
  this.mapInServers()
}

export function installSecret () {
  const { server } = this
  // configure maybe an empty secret
  const secretDir = path.join(server.dir, 'config/secret.json')
  if (!fs.existsSync(secretDir)) {
    fs.writeFileSync(secretDir, '{}')
  }
}
<|endoftext|>


<commit_before>(function() {
var ext = {
	nextChange: 0,

	scripts: {
		'www.funbeat.se': function() {
			ext.changeLayout();
		},
		'www.facebook.com': function() {
			ext.changeLayout();
		},
		'mail.google.com': function(doc) {
			setTimeout(function() {
				var t = doc.title;
				if (t.indexOf('@gmail.com') !== -1 && t.indexOf('simon.lindholm10') === -1)
					ext.changeLayout();
			}, 4000);
		},
	},

	init: function() {
		var appcontent = document.getElementById('appcontent');
		if (appcontent)
			appcontent.addEventListener('DOMContentLoaded', ext.onPageLoad, true);
	},

	onPageLoad: function(ev) {
		var doc = ev.originalTarget, win = doc && doc.defaultView;
		if (!win || win.parent !== win)
			return;

		var host = win.location.host;
		if (ext.scripts.hasOwnProperty(host))
			ext.scripts[host](doc);
	},

	changeLayout: function() {
		if (Date.now() < ext.nextChange && !window.kbdSkipTimeout) return;
		ext.nextChange = Date.now() + 1000 * 60 * 3;

		var file = Components.classes["@mozilla.org/file/local;1"]
		                     .createInstance(Components.interfaces.nsILocalFile);
		file.initWithPath('/usr/local/bin/xkb-switch');

		var process = Components.classes["@mozilla.org/process/util;1"]
		                        .createInstance(Components.interfaces.nsIProcess);
		process.init(file);
		var args = ["-s", "se"];
		process.run(false, args, args.length);
	},
};

window.addEventListener('load', function() { ext.init(); }, false);
})();
<commit_msg>Fix whitespace<commit_after>(function() {
var ext = {
	nextChange: 0,

	scripts: {
		'www.funbeat.se': function() {
			ext.changeLayout();
		},
		'www.facebook.com': function() {
			ext.changeLayout();
		},
		'mail.google.com': function(doc) {
			setTimeout(function() {
				var t = doc.title;
				if (t.indexOf('@gmail.com') !== -1 && t.indexOf('simon.lindholm10') === -1)
					ext.changeLayout();
			}, 4000);
		},
	},

	init: function() {
		var appcontent = document.getElementById('appcontent');
		if (appcontent)
			appcontent.addEventListener('DOMContentLoaded', ext.onPageLoad, true);
	},

	onPageLoad: function(ev) {
		var doc = ev.originalTarget, win = doc && doc.defaultView;
		if (!win || win.parent !== win)
			return;

		var host = win.location.host;
		if (ext.scripts.hasOwnProperty(host))
			ext.scripts[host](doc);
	},

	changeLayout: function() {
		if (Date.now() < ext.nextChange && !window.kbdSkipTimeout) return;
		ext.nextChange = Date.now() + 1000 * 60 * 3;

		var file = Components.classes["@mozilla.org/file/local;1"]
		                     .createInstance(Components.interfaces.nsILocalFile);
		file.initWithPath('/usr/local/bin/xkb-switch');

		var process = Components.classes["@mozilla.org/process/util;1"]
		                        .createInstance(Components.interfaces.nsIProcess);
		process.init(file);
		var args = ["-s", "se"];
		process.run(false, args, args.length);
	},
};

window.addEventListener('load', function() { ext.init(); }, false);
})();
<|endoftext|>


<commit_before>var screenplay;
var saveInLocalStorage = true;

SPapp.controller("mainController",

	["$scope", "$http", "$timeout",

	function($scope, $http, $timeout) {

	function load() {
		var old_revision,
			new_revision;

		$http.get("json/revision.json").success(function(data) {
	        new_revision = data.revision;
    	}).then(function() {
			old_revision = localStorage.getItem("screenplay.revision") || 0;

			if(old_revision != new_revision) {
				if(confirm("Há novo conteúdo disponível, deseja manter seus dados ou sobreescreve-los? \nSua revisão: " + old_revision + "\nNova revisão: " + new_revision)) {
					saveInLocalStorage = false;
					location.reload();
	    			localStorage.setItem("screenplay.revision", new_revision);
				}
			}
		});

		if(localStorage.getItem("screenplay")) {
			$scope.screenplay = JSON.parse(localStorage.getItem("screenplay"));
			screenplay = $scope.screenplay;
		}
	    else {
	    	$http.get("json/screenplay.json").success(function(data) {
		        $scope.screenplay = data;
		        localStorage.setItem("screenplay", JSON.stringify(data));
		        screenplay = data;
	    	});
	    }
	}
	load();

    $scope.template = {};

	$scope.template.children = function(sub) {
		return sub.sub ? "templates/subs.html" : "";
	}
	$scope.template.edit = function(sub) {
		return sub.edit ? "templates/edit-sub.html" : "templates/sub.html";
	}

	$scope.toggle = function(sub) {
		if(sub.sub && sub.sub[0])
			sub.hideSubs = !sub.hideSubs;
	}

	$scope.toggleref = function($this) {
		var activeReference = $this.$parent.activeReference;
		if(activeReference)
			activeReference.show = "reference-content-container-false";

		$this.$parent.opened = false;
		$this.reference.search = false;
		$this.reference.referenceClass = "reference-title";

		if(activeReference == $this.reference) {
			delete $this.$parent.activeReference;
			return;
		}

		$this.$parent.activeReference = $this.reference;

		$this.reference.referenceClass = "reference-title-true";
		$this.$parent.opened = true;
		$this.reference.search = true;

		$scope.collapseAll($this.reference.sub);
		$this.reference.show = "reference-content-container-true";
	}
	$scope.collapseAll = function(subs) {
		for(index in subs) {
			if(subs[index].sub && subs[index].sub[0]) {
				subs[index].hideSubs = true;
				$scope.collapseAll(subs[index].sub);
			}
		}
	}

	$scope.getPercentChildrenComplete = function(sub) {
		var checked = 0;
		var length = sub.sub.length;
		var rate;

		for(index in sub.sub) {
			if(sub.sub[index].rate)
				checked += sub.sub[index].rate;

			else if(sub.sub[index].studied)
				checked++;
		}

		rate = checked/length;
		sub.rate = rate;
		return Math.floor(rate*10);

	}

	$scope.subClass = function(sub) {
		var stringClass = " opened_" + sub.hideSubs;

		stringClass += " sub-li";
		stringClass += " complete-" + $scope.getPercentChildrenComplete(sub);
		stringClass += sub.edited ? " sub-li-edited" : "";
		stringClass += sub.studied ? " sub-li-studied" : "";

		return stringClass;
	}

	$scope.init = function(sub) {
		$scope.toggle(sub.sub);

		if(!sub.sub.studied)
			sub.sub.studied = false;

		if(!sub.sub.sub)
			sub.sub.sub = [];

		$timeout(function() {
			$scope.bindEventToPolymer(sub);
		},50);
	}

	$scope.bindEventToPolymer = function(sub) {
		var element = $("." + sub.$id);

		element[0].bind('checked', new PathObserver(sub.sub, 'studied'));

		sub.sub.element = element;
	}

	$scope.defineToggle = function(sub) {
		if(sub.sub && sub.sub[0])
			sub.hideSubs = false;
		else
			delete sub.hideSubs;
	}

	$scope.add = function(sub) {
		if(!sub.sub || !sub.sub[0])
			sub.sub = [];

		var newSub = {
			edit:true,
			studied:false
		}
		sub.sub.unshift(newSub);

		sub.hideSubs = true;
		sub.studied = false;
	}

	$scope.remove = function(parent, index) {
		parent.sub.splice(index, 1);

		$scope.studied.selfUpdate(parent);

		$scope.defineToggle(parent);

	}

	$scope.teste = function(sub) {
		console.log(1);
	}

	$scope.studied = {};

	$scope.studied.selfUpdate = function(sub) {
		var studied = sub.sub.length > 0;

		for(index in sub.sub) {
			if(!sub.sub[index].studied) {
				studied = false;
				break;
			}
		}

		sub.studied = studied;
	}

	$scope.studied.update = function($this, event) {
		var timer;
		sub = $this.sub;

		sub.studied = !sub.studied;

		$scope.studied.updateParents($this.$parent);
		$scope.studied.updateChildren(sub);

		sub.studied = !sub.studied;

		timer = $timeout(function() {
			sub.studied = sub.element.prop("checked");
		}, 200);
	}
	$scope.studied.updateChildren = function(sub) {
		for(index in sub.sub) {
			sub.sub[index].studied = sub.studied;

			$scope.studied.updateChildren(sub.sub[index]);
		}
	}
	$scope.studied.updateParents = function($this) {
		var studied = true;

		if(!$this || !$this.sub)
			return;

		for(index in $this.sub.sub) {
			if(!$this.sub.sub[index].studied) {
				studied = false;
				break;
			}
		}
		$this.sub.studied = studied;

		$scope.studied.updateParents($this.$parent.$parent);
	}

	$scope.validate = function(sub) {
		sub.edit = !sub.desc;

		sub.edited = sub.edited == undefined ? false : sub.edited || sub.desc != sub.old_desc;
	}
	$scope.initInput = function($this) {
		console.log();
		$this.sub.old_desc = $this.sub.desc;
		$timeout(function() {
			$("input."+$this.$id).focus();
		},250);
	}
}]);

window.onbeforeunload = function() {
	removeProp(screenplay, "element");
	removeProp(screenplay, "hideSubs");
	removeProp(screenplay, "search");
	desactivateReferences(screenplay);

	if(saveInLocalStorage)
		localStorage.setItem("screenplay", JSON.stringify(screenplay));
}

desactivateReferences = function() {
	for(index in screenplay.references) {
		delete screenplay.references[index].referenceClass;
		delete screenplay.references[index].opened;
		delete screenplay.references[index].show;
	}
}

removeProp = function(obj, prop, notRecursive) {
	delete obj[prop];

	if(notRecursive)
		return;

	for(index in obj) {
		if(typeof obj[index] == "object")
			removeProp(obj[index], prop, notRecursive);
	}
}<commit_msg>last improvments<commit_after>var screenplay;
var saveInLocalStorage = true;

SPapp.controller("mainController",

	["$scope", "$http", "$timeout",

	function($scope, $http, $timeout) {

	function load() {
		var old_revision,
			new_revision;

		$http.get("json/revision.json").success(function(data) {
	        new_revision = data.revision;
    	}).then(function() {
			old_revision = localStorage.getItem("screenplay.revision") || 0;

			if(old_revision != new_revision) {
				if(confirm("Há novo conteúdo disponível, deseja sobreescrever seus dados? \nSua revisão: " + old_revision + "\nNova revisão: " + new_revision)) {
					saveInLocalStorage = false;
					location.reload();
	    			localStorage.setItem("screenplay.revision", new_revision);
				}
			}
		});

		if(localStorage.getItem("screenplay")) {
			$scope.screenplay = JSON.parse(localStorage.getItem("screenplay"));
			screenplay = $scope.screenplay;
		}
	    else {
	    	$http.get("json/screenplay.json").success(function(data) {
		        $scope.screenplay = data;
		        localStorage.setItem("screenplay", JSON.stringify(data));
		        screenplay = data;
	    	});
	    }
	}
	load();

    $scope.template = {};

	$scope.template.children = function(sub) {
		return sub.sub ? "templates/subs.html" : "";
	}
	$scope.template.edit = function(sub) {
		return sub.edit ? "templates/edit-sub.html" : "templates/sub.html";
	}

	$scope.toggle = function(sub) {
		if(sub.sub && sub.sub[0])
			sub.hideSubs = !sub.hideSubs;
	}

	$scope.toggleref = function($this) {
		var activeReference = $this.$parent.activeReference;
		if(activeReference)
			activeReference.show = "reference-content-container-false";

		$this.$parent.opened = false;
		$this.reference.search = false;
		$this.reference.referenceClass = "reference-title";

		if(activeReference == $this.reference) {
			delete $this.$parent.activeReference;
			return;
		}

		$this.$parent.activeReference = $this.reference;

		$this.reference.referenceClass = "reference-title-true";
		$this.$parent.opened = true;
		$this.reference.search = true;

		$scope.collapseAll($this.reference.sub);
		$this.reference.show = "reference-content-container-true";
	}
	$scope.collapseAll = function(subs) {
		for(index in subs) {
			if(subs[index].sub && subs[index].sub[0]) {
				subs[index].hideSubs = true;
				$scope.collapseAll(subs[index].sub);
			}
		}
	}

	$scope.getPercentChildrenComplete = function(sub) {
		var checked = 0;
		var length = sub.sub.length;
		var rate;

		for(index in sub.sub) {
			if(sub.sub[index].rate)
				checked += sub.sub[index].rate;

			else if(sub.sub[index].studied)
				checked++;
		}

		rate = checked/length;
		sub.rate = rate;
		return Math.floor(rate*10);

	}

	$scope.subClass = function(sub) {
		var stringClass = " opened_" + sub.hideSubs;

		stringClass += " sub-li";
		stringClass += " complete-" + $scope.getPercentChildrenComplete(sub);
		stringClass += sub.edited ? " sub-li-edited" : "";
		stringClass += sub.studied ? " sub-li-studied" : "";

		return stringClass;
	}

	$scope.init = function(sub) {
		$scope.toggle(sub.sub);

		if(!sub.sub.studied)
			sub.sub.studied = false;

		if(!sub.sub.sub)
			sub.sub.sub = [];

		$timeout(function() {
			$scope.bindEventToPolymer(sub);
		},50);
	}

	$scope.bindEventToPolymer = function(sub) {
		var element = $("." + sub.$id);

		element[0].bind('checked', new PathObserver(sub.sub, 'studied'));

		sub.sub.element = element;
	}

	$scope.defineToggle = function(sub) {
		if(sub.sub && sub.sub[0])
			sub.hideSubs = false;
		else
			delete sub.hideSubs;
	}

	$scope.add = function(sub) {
		if(!sub.sub || !sub.sub[0])
			sub.sub = [];

		var newSub = {
			edit:true,
			studied:false
		}
		sub.sub.unshift(newSub);

		sub.hideSubs = true;
		sub.studied = false;
	}

	$scope.remove = function(parent, index) {
		parent.sub.splice(index, 1);

		$scope.studied.selfUpdate(parent);

		$scope.defineToggle(parent);

	}

	$scope.teste = function(sub) {
		console.log(1);
	}

	$scope.studied = {};

	$scope.studied.selfUpdate = function(sub) {
		var studied = sub.sub.length > 0;

		for(index in sub.sub) {
			if(!sub.sub[index].studied) {
				studied = false;
				break;
			}
		}

		sub.studied = studied;
	}

	$scope.studied.update = function($this, event) {
		var timer;
		sub = $this.sub;

		sub.studied = !sub.studied;

		$scope.studied.updateParents($this.$parent);
		$scope.studied.updateChildren(sub);

		sub.studied = !sub.studied;

		timer = $timeout(function() {
			sub.studied = sub.element.prop("checked");
		}, 200);
	}
	$scope.studied.updateChildren = function(sub) {
		for(index in sub.sub) {
			sub.sub[index].studied = sub.studied;

			$scope.studied.updateChildren(sub.sub[index]);
		}
	}
	$scope.studied.updateParents = function($this) {
		var studied = true;

		if(!$this || !$this.sub)
			return;

		for(index in $this.sub.sub) {
			if(!$this.sub.sub[index].studied) {
				studied = false;
				break;
			}
		}
		$this.sub.studied = studied;

		$scope.studied.updateParents($this.$parent.$parent);
	}

	$scope.validate = function(sub) {
		sub.edit = !sub.desc;

		sub.edited = sub.edited == undefined ? false : sub.edited || sub.desc != sub.old_desc;
	}
	$scope.initInput = function($this) {
		console.log();
		$this.sub.old_desc = $this.sub.desc;
		$timeout(function() {
			$("input."+$this.$id).focus();
		},250);
	}
}]);

window.onbeforeunload = function() {
	removeProp(screenplay, "element");
	removeProp(screenplay, "hideSubs");
	removeProp(screenplay, "search");
	desactivateReferences(screenplay);

	if(saveInLocalStorage)
		localStorage.setItem("screenplay", JSON.stringify(screenplay));
}

desactivateReferences = function() {
	for(index in screenplay.references) {
		delete screenplay.references[index].referenceClass;
		delete screenplay.references[index].opened;
		delete screenplay.references[index].show;
	}
}

removeProp = function(obj, prop, notRecursive) {
	delete obj[prop];

	if(notRecursive)
		return;

	for(index in obj) {
		if(typeof obj[index] == "object")
			removeProp(obj[index], prop, notRecursive);
	}
}<|endoftext|>


<commit_before>/* global describe, it, beforeEach */

import React from 'react'
import { expect } from 'chai'
import { mount } from 'enzyme'
import Switch from '../../src/js/components/switch'
import td from 'testdouble'

describe('<Switch />', () => {
  const defaultProps = {
    inputHtml: { type: 'switch' },
    valueLink: {
      value: true,
      requireChange: () => {},
    },
  }

  const renderWrapper = (
    props = defaultProps,
    findClass = '.bootstrap-switch'
  ) => {
    const wrapper = mount(<Switch {...props} />)
    return wrapper.find(findClass)
  }

  describe('Default Props', () => {
    it('has width-switch=undefined', () => {
      const switchContainer = renderWrapper()

      expect(switchContainer.prop('width-switch')).to.be.undefined()
    })

    it('has style=marginLeft=0;width=undefined', () => {
      const switchComponent = renderWrapper(
        defaultProps,
        '.bootstrap-switch-container'
      )
      const switchComponentStyle = switchComponent.prop('style')

      expect(switchComponentStyle).to.have.property('marginLeft', '0')
      expect(switchComponentStyle).to.have.property('width', undefined)
    })
  })

  describe('prop.disable=true', () => {
    it('renders disable class', () => {
      const props = Object.assign({}, defaultProps, { disabled: true })
      const switchContainer = renderWrapper(props)

      expect(switchContainer.hasClass('bootstrap-switch-disabled')).to.be.true()
    })
  })

  describe('prop.handleWidth=50', () => {
    const handleWidth = 50

    it('outer switch has offset width of 102 (handleWidth * 2 + 2)', () => {
      const props = Object.assign({}, defaultProps, { handleWidth })
      const switchContainer = renderWrapper(props)
      const switchComponentStyle = switchContainer.prop('style')

      expect(switchComponentStyle).to.have.property('width', '102px')
    })

    describe('inner switch container', () => {
      it('offset marginLeft becomes 50 on valueLink.value=false', () => {
        const props = Object.assign({}, defaultProps, {
          handleWidth,
          valueLink: {
            value: false,
          },
        })
        const switchComponent = renderWrapper(props, '.bootstrap-switch-container')
        const switchComponentStyle = switchComponent.prop('style')

        expect(switchComponentStyle).to.have.property('marginLeft', '-50px')
      })

      it('offset width becomes 150 (handleWidth * 3)', () => {
        const props = Object.assign({}, defaultProps, { handleWidth })
        const switchComponent = renderWrapper(props, '.bootstrap-switch-container')
        const switchComponentStyle = switchComponent.prop('style')

        expect(switchComponentStyle).to.have.property('width', 150)
      })
    })
  })

  describe('on & off color', () => {
    it('renders class bootstrap-switch-onColour', () => {
      const props = Object.assign({}, defaultProps, { onColor: 'onColour' })
      const switchComponent = renderWrapper(props, '.bootstrap-switch-handle-on')

      expect(switchComponent.hasClass('bootstrap-switch-onColour')).to.be.true()
    })

    it('renders class bootstrap-switch-offColour', () => {
      const props = Object.assign({}, defaultProps, { offColor: 'offColour' })
      const switchComponent = renderWrapper(props, '.bootstrap-switch-handle-off')

      expect(switchComponent.hasClass('bootstrap-switch-offColour')).to.be.true()
    })
  })

  describe('private functions', () => {
    describe('_onClick()', () => {
      it('return false when disabled', () => {
        const props = Object.assign({}, defaultProps, { disabled: true })
        const booleanHOC = mount(<Switch {...props} />)
        const switchComponent = mount(booleanHOC.instance().render())
        const instance = switchComponent.instance()

        expect(instance._onClick()).to.be.false()
      })

      it('return true after updading valueLink.value', () => {
        const requestChange = td.function.call()
        const props = Object.assign({}, defaultProps, {
          valueLink: {
            value: true,
            requestChange,
          },
        })

        const booleanHOC = mount(<Switch {...props} />)
        const switchComponent = mount(booleanHOC.instance().render())
        const instance = switchComponent.instance()

        instance._onClick()

        td.verify(requestChange(false))
      })
    })
  })
})
<commit_msg>Add Common Test To Switch Component<commit_after>/* global describe, it, beforeEach */

import React from 'react'
import { expect } from 'chai'
import { mount } from 'enzyme'
import Switch from '../../src/js/components/switch'
import td from 'testdouble'

import * as common from './_common.test'

describe('<Switch />', () => {
  const defaultProps = {
    inputHtml: { type: 'switch' },
    valueLink: {
      value: true,
      requireChange: () => {},
    },
  }

  describe('common Bootstrap tests', () => {
    common.runInputErrorListTest(Switch, defaultProps)
    common.runSavedTest(Switch, defaultProps)
    common.runLabelTest(Switch, defaultProps)
    common.runInputHtmlTest(Switch, defaultProps, 'boolean')
  })

  const renderWrapper = (
    props = defaultProps,
    findClass = '.bootstrap-switch'
  ) => {
    const wrapper = mount(<Switch {...props} />)
    return wrapper.find(findClass)
  }

  describe('Default Props', () => {
    it('has width-switch=undefined', () => {
      const switchContainer = renderWrapper()

      expect(switchContainer.prop('width-switch')).to.be.undefined()
    })

    it('has style=marginLeft=0;width=undefined', () => {
      const switchComponent = renderWrapper(
        defaultProps,
        '.bootstrap-switch-container'
      )
      const switchComponentStyle = switchComponent.prop('style')

      expect(switchComponentStyle).to.have.property('marginLeft', '0')
      expect(switchComponentStyle).to.have.property('width', undefined)
    })
  })

  describe('prop.disable=true', () => {
    it('renders disable class', () => {
      const props = Object.assign({}, defaultProps, { disabled: true })
      const switchContainer = renderWrapper(props)

      expect(switchContainer.hasClass('bootstrap-switch-disabled')).to.be.true()
    })
  })

  describe('prop.handleWidth=50', () => {
    const handleWidth = 50

    it('outer switch has offset width of 102 (handleWidth * 2 + 2)', () => {
      const props = Object.assign({}, defaultProps, { handleWidth })
      const switchContainer = renderWrapper(props)
      const switchComponentStyle = switchContainer.prop('style')

      expect(switchComponentStyle).to.have.property('width', '102px')
    })

    describe('inner switch container', () => {
      it('offset marginLeft becomes 50 on valueLink.value=false', () => {
        const props = Object.assign({}, defaultProps, {
          handleWidth,
          valueLink: {
            value: false,
          },
        })
        const switchComponent = renderWrapper(props, '.bootstrap-switch-container')
        const switchComponentStyle = switchComponent.prop('style')

        expect(switchComponentStyle).to.have.property('marginLeft', '-50px')
      })

      it('offset width becomes 150 (handleWidth * 3)', () => {
        const props = Object.assign({}, defaultProps, { handleWidth })
        const switchComponent = renderWrapper(props, '.bootstrap-switch-container')
        const switchComponentStyle = switchComponent.prop('style')

        expect(switchComponentStyle).to.have.property('width', 150)
      })
    })
  })

  describe('on & off color', () => {
    it('renders class bootstrap-switch-onColour', () => {
      const props = Object.assign({}, defaultProps, { onColor: 'onColour' })
      const switchComponent = renderWrapper(props, '.bootstrap-switch-handle-on')

      expect(switchComponent.hasClass('bootstrap-switch-onColour')).to.be.true()
    })

    it('renders class bootstrap-switch-offColour', () => {
      const props = Object.assign({}, defaultProps, { offColor: 'offColour' })
      const switchComponent = renderWrapper(props, '.bootstrap-switch-handle-off')

      expect(switchComponent.hasClass('bootstrap-switch-offColour')).to.be.true()
    })
  })

  describe('private functions', () => {
    describe('_onClick()', () => {
      it('return false when disabled', () => {
        const props = Object.assign({}, defaultProps, { disabled: true })
        const booleanHOC = mount(<Switch {...props} />)
        const switchComponent = mount(booleanHOC.instance().render())
        const instance = switchComponent.instance()

        expect(instance._onClick()).to.be.false()
      })

      it('return true after updading valueLink.value', () => {
        const requestChange = td.function.call()
        const props = Object.assign({}, defaultProps, {
          valueLink: {
            value: true,
            requestChange,
          },
        })

        const booleanHOC = mount(<Switch {...props} />)
        const switchComponent = mount(booleanHOC.instance().render())
        const instance = switchComponent.instance()

        instance._onClick()

        td.verify(requestChange(false))
      })
    })
  })
})
<|endoftext|>


<commit_before>#! /usr/bin/env node

console.log('node-async-test command is deprecated.\nSee http://github.com/bentomas/node-async-testing for how to run tests\n');

try {
  // always check for a local copy of async_testing first
  var testing = require('../lib/async_testing');
}
catch(err) {
  if( err.message == "Cannot find module './async_testing'" ) {
    // look in the path for async_testing
    var testing = require('async_testing');
  }
  else {
    throw err;
  }
}

testing.run(null, process.ARGV, done);

function done(allResults) {
  // we want to have our exit status be the number of problems

  var problems = 0;

  for(var i = 0; i < allResults.length; i++) {
    if (allResults[i].tests.length > 0) {
      problems += allResults[i].numErrors;
      problems += allResults[i].numFailures;
    }
  }

  process.exit(problems);
}
<commit_msg>Remove bin/node-async-test.js -- it was deprecated like last week<commit_after><|endoftext|>


<commit_before>import React, { Component } from 'react';
import Relay from 'react-relay/classic';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import Favicon from 'react-favicon';
import isEqual from 'lodash.isequal';
import styled, { createGlobalStyle } from 'styled-components';
import Intercom from 'react-intercom';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import MomentUtils from '@date-io/moment';
import config from 'config'; // eslint-disable-line require-path-exists/exists
import Header from './Header';
import LoginContainer from './LoginContainer';
import BrowserSupport from './BrowserSupport';
import CheckContext from '../CheckContext';
import DrawerNavigation from './DrawerNavigation';
import { FlashMessageContext, FlashMessage, withSetFlashMessage } from './FlashMessage';
import UserTos from './UserTos';
import { withClientSessionId } from '../ClientSessionId';
import { layout, typography, localeAr, removeYellowAutocomplete } from '../styles/js/global';
import { stringHelper } from '../customHelpers';
import { bemClass } from '../helpers';
import { FormattedGlobalMessage } from './MappedMessage';
import MeRoute from '../relay/MeRoute';

// Global styles
const GlobalStyle = createGlobalStyle([`
  ${layout}
  ${typography}
  ${localeAr}
  ${removeYellowAutocomplete}
`]);

const Wrapper = styled.div`
  display: flex;
`;

const Main = styled.main`
  flex: 1 1 auto;
`;

const StyledContent = styled.div`
  background-color: white;
`;

function buildLoginContainerMessage(flashMessage, error, childRoute, queryString) {
  let message = null;
  if (error) {
    message = flashMessage;

    // TODO Don't parse error messages because they may be l10n'd - use error codes instead.
    if (!message && /^[^/]+\/join$/.test(childRoute.path)) {
      message = (
        <FormattedMessage
          id="home.needRegister"
          defaultMessage="First you need to register. Once registered, you can request to join the workspace."
        />
      );
    }

    // TODO Don't parse error messages because they may be l10n'd - use error codes instead.
    if (
      error &&
      message &&
      message.match && // Test `message` is a String, not a <FormattedMessage>
      message.match(/\{ \[Error: Request has been terminated/)
    ) {
      message = (
        <FormattedMessage
          id="home.somethingWrong"
          defaultMessage="Sorry, an error occurred. Please refresh your browser and contact {supportEmail} if the condition persists."
          values={{ supportEmail: stringHelper('SUPPORT_EMAIL') }}
        />
      );
    }
  }

  if ('invitation_response' in queryString) {
    if (queryString.invitation_response === 'success') {
      if (queryString.msg === 'yes') {
        message = (
          <FormattedGlobalMessage messageKey="appNameHuman">
            {appName => (
              <FormattedMessage
                id="home.successInvitation"
                defaultMessage="Welcome to {appName}. Please login with the password that you received in the welcome email."
                values={{ appName }}
              />
            )}
          </FormattedGlobalMessage>
        );
      }
    } else {
      const values = { supportEmail: stringHelper('SUPPORT_EMAIL') };
      switch (queryString.invitation_response) {
      case 'invalidTeamInvitation': return (
        <FormattedMessage
          id="home.invalidTeamInvitation"
          defaultMessage="Sorry, the workspace to which you were invited was not found. Please contact {supportEmail} if you think this is an error."
          values={values}
        />
      );
      case 'invalidNoInvitation': return (
        <FormattedMessage
          id="home.invalidNoInvitation"
          defaultMessage="Sorry, the invitation you received was not found. Please contact {supportEmail} if you think this is an error."
          values={values}
        />
      );
      case 'invalidExpiredInvitation': return (
        <FormattedMessage
          id="home.invalidExpiredInvitation"
          defaultMessage="Sorry, the invitation you received was expired. Please contact {supportEmail} if you think this is an error."
          values={values}
        />
      );
      default: return (
        <FormattedMessage
          id="home.invalidInvitation"
          defaultMessage="Sorry, an error occurred while processing your invitation. Please contact {supportEmail}."
          values={values}
        />
      );
      }
    }
  }
  return message;
}

class HomeComponent extends Component {
  static routeSlug(children) {
    if (!(children && children.props.route)) {
      return null;
    }
    if (/\/media\/:mediaId/.test(children.props.route.path)) {
      return 'media';
    }
    if (/\/source\/:sourceId/.test(children.props.route.path)) {
      return 'source';
    }
    if (/^:team$/.test(children.props.route.path)) {
      return 'team';
    }
    if (/^check\/me\(\/:tab\)/.test(children.props.route.path)) {
      return 'me';
    }
    if (/^:team\/project\/:projectId\(\/:query\)/.test(children.props.route.path)) {
      return 'project';
    }
    return null;
  }

  constructor(props) {
    super(props);

    this.state = {
      token: null,
      error: false,
      sessionStarted: false,
      path: window.location.pathname,
    };
  }

  componentWillMount() {
    this.setContext();
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !isEqual(this.state, nextState) ||
    !isEqual(this.props, nextProps);
  }

  componentWillUpdate() {
    this.setContext();
  }

  setContext() {
    const { clientSessionId, setFlashMessage } = this.props;
    const context = new CheckContext(this);
    if (!this.state.token && !this.state.error) {
      context.startSession(this.props.user, clientSessionId, setFlashMessage);
    }
    context.setContext();
    context.startNetwork(this.state.token, clientSessionId, setFlashMessage);
  }

  getContext() {
    return new CheckContext(this).getContextStore();
  }

  loginCallback() {
    if (this.state.path !== '/check/user/password-change' &&
      this.state.path !== '/check/user/confirmed') {
      window.location.assign(this.state.path);
    } else {
      window.location.assign('/');
    }
    this.setState({ error: false, path: null });
  }

  render() {
    if (!this.state.sessionStarted) {
      return null;
    }

    const { children, location } = this.props;
    const routeSlug = HomeComponent.routeSlug(children);

    const routeIsPublic = children && children.props.route.public;
    if (!routeIsPublic && !this.state.token) {
      if (this.state.error) {
        return (
          <FlashMessageContext.Consumer>
            {flashMessage => (
              <LoginContainer
                loginCallback={this.loginCallback.bind(this)}
                message={buildLoginContainerMessage(
                  flashMessage,
                  this.state.error,
                  children.props.route,
                  location.query,
                )}
              />
            )}
          </FlashMessageContext.Consumer>
        );
      }
      return null;
    }

    const user = this.props.user || {};
    const loggedIn = !!this.state.token;
    const teamSlugFromUrl = window.location.pathname.match(/^\/([^/]+)/);
    const userTeamSlug = ((user.current_team && user.current_team.slug) ?
      user.current_team.slug : null);
    const teamSlug = (teamSlugFromUrl && teamSlugFromUrl[1] !== 'check' ? teamSlugFromUrl[1] : null) || userTeamSlug;
    const inTeamContext = Boolean(teamSlug);

    const currentUserIsMember = (() => {
      if (inTeamContext && loggedIn) {
        if (user.is_admin) {
          return true;
        }
        const teams = JSON.parse(user.user_teams);
        const team = teams[teamSlug] || {};
        return team.status === 'member';
      }
      return false;
    })();

    const showDrawer = !/\/media\/[0-9]+/.test(window.location.pathname);

    return (
      <React.Fragment>
        <GlobalStyle />
        <MuiPickersUtilsProvider utils={MomentUtils}>
          {config.intercomAppId && user.dbid && window.parent === window ?
            <Intercom
              appID={config.intercomAppId}
              user_id={user.dbid}
              email={user.email}
              name={user.name}
            /> : null
          }
          <Favicon url={`/images/logo/${config.appName}.ico`} animated={false} />
          <BrowserSupport />
          <UserTos user={user} />
          <Wrapper className={bemClass('home', routeSlug, `--${routeSlug}`)}>
            {showDrawer ? (
              <DrawerNavigation
                loggedIn={loggedIn}
                teamSlug={teamSlug}
                inTeamContext={inTeamContext}
                currentUserIsMember={currentUserIsMember}
                {...this.props}
              />
            ) : null}
            <Main>
              <Header
                loggedIn={loggedIn}
                pageType={routeSlug}
                inTeamContext={inTeamContext}
                currentUserIsMember={currentUserIsMember}
                {...this.props}
              />
              <FlashMessage />
              <StyledContent className="content-wrapper">
                {children}
              </StyledContent>
            </Main>
          </Wrapper>
        </MuiPickersUtilsProvider>
      </React.Fragment>
    );
  }
}

HomeComponent.propTypes = {
  // https://github.com/yannickcr/eslint-plugin-react/issues/1389
  // eslint-disable-next-line react/no-typos
  clientSessionId: PropTypes.string.isRequired,
  setFlashMessage: PropTypes.func.isRequired,
};

HomeComponent.contextTypes = {
  store: PropTypes.object,
};

const ConnectedHomeComponent = withSetFlashMessage(withClientSessionId(HomeComponent));

const HomeContainer = Relay.createContainer(ConnectedHomeComponent, {
  fragments: {
    user: () => Relay.QL`
      fragment on User {
        id
        dbid
        name
        token
        email
        is_admin
        accepted_terms
        last_accepted_terms_at
        name
        login
        permissions
        profile_image
        settings
        source_id
        team_ids
        user_teams
        current_project {
          dbid
          id
          title
          team {
            id
            dbid
            avatar
            name
            slug
          }
        }
        current_team {
          id
          dbid
          avatar
          name
          slug
          projects(first: 10000) {
            edges {
              node {
                id
                dbid
                title
                team {
                  id
                  dbid
                  avatar
                  name
                  slug
                }
              }
            }
          }
        }
      }
    `,
  },
});

// eslint-disable-next-line react/no-multi-comp
class Home extends Component {
  componentWillMount() {
    const context = new CheckContext(this);
    const { clientSessionId, setFlashMessage } = this.props;
    context.startNetwork(null, clientSessionId, setFlashMessage);
  }

  // eslint-disable-next-line class-methods-use-this
  render() {
    const route = new MeRoute();

    return (
      <Relay.RootContainer
        Component={HomeContainer}
        route={route}
        renderFetched={data => (
          <HomeContainer
            location={this.props.location}
            params={this.props.params}
            {...data}
          >
            {this.props.children}
          </HomeContainer>
        )}
      />
    );
  }
}

Home.propTypes = {
  clientSessionId: PropTypes.string.isRequired,
  setFlashMessage: PropTypes.func.isRequired,
};

Home.contextTypes = {
  store: PropTypes.object,
};

export default withSetFlashMessage(withClientSessionId(Home));
<commit_msg>Ticket CHECK-165: Pass user's Check workspace to Intercom<commit_after>import React, { Component } from 'react';
import Relay from 'react-relay/classic';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import Favicon from 'react-favicon';
import isEqual from 'lodash.isequal';
import styled, { createGlobalStyle } from 'styled-components';
import Intercom from 'react-intercom';
import { MuiPickersUtilsProvider } from '@material-ui/pickers';
import MomentUtils from '@date-io/moment';
import config from 'config'; // eslint-disable-line require-path-exists/exists
import Header from './Header';
import LoginContainer from './LoginContainer';
import BrowserSupport from './BrowserSupport';
import CheckContext from '../CheckContext';
import DrawerNavigation from './DrawerNavigation';
import { FlashMessageContext, FlashMessage, withSetFlashMessage } from './FlashMessage';
import UserTos from './UserTos';
import { withClientSessionId } from '../ClientSessionId';
import { layout, typography, localeAr, removeYellowAutocomplete } from '../styles/js/global';
import { stringHelper } from '../customHelpers';
import { bemClass } from '../helpers';
import { FormattedGlobalMessage } from './MappedMessage';
import MeRoute from '../relay/MeRoute';

// Global styles
const GlobalStyle = createGlobalStyle([`
  ${layout}
  ${typography}
  ${localeAr}
  ${removeYellowAutocomplete}
`]);

const Wrapper = styled.div`
  display: flex;
`;

const Main = styled.main`
  flex: 1 1 auto;
`;

const StyledContent = styled.div`
  background-color: white;
`;

function buildLoginContainerMessage(flashMessage, error, childRoute, queryString) {
  let message = null;
  if (error) {
    message = flashMessage;

    // TODO Don't parse error messages because they may be l10n'd - use error codes instead.
    if (!message && /^[^/]+\/join$/.test(childRoute.path)) {
      message = (
        <FormattedMessage
          id="home.needRegister"
          defaultMessage="First you need to register. Once registered, you can request to join the workspace."
        />
      );
    }

    // TODO Don't parse error messages because they may be l10n'd - use error codes instead.
    if (
      error &&
      message &&
      message.match && // Test `message` is a String, not a <FormattedMessage>
      message.match(/\{ \[Error: Request has been terminated/)
    ) {
      message = (
        <FormattedMessage
          id="home.somethingWrong"
          defaultMessage="Sorry, an error occurred. Please refresh your browser and contact {supportEmail} if the condition persists."
          values={{ supportEmail: stringHelper('SUPPORT_EMAIL') }}
        />
      );
    }
  }

  if ('invitation_response' in queryString) {
    if (queryString.invitation_response === 'success') {
      if (queryString.msg === 'yes') {
        message = (
          <FormattedGlobalMessage messageKey="appNameHuman">
            {appName => (
              <FormattedMessage
                id="home.successInvitation"
                defaultMessage="Welcome to {appName}. Please login with the password that you received in the welcome email."
                values={{ appName }}
              />
            )}
          </FormattedGlobalMessage>
        );
      }
    } else {
      const values = { supportEmail: stringHelper('SUPPORT_EMAIL') };
      switch (queryString.invitation_response) {
      case 'invalidTeamInvitation': return (
        <FormattedMessage
          id="home.invalidTeamInvitation"
          defaultMessage="Sorry, the workspace to which you were invited was not found. Please contact {supportEmail} if you think this is an error."
          values={values}
        />
      );
      case 'invalidNoInvitation': return (
        <FormattedMessage
          id="home.invalidNoInvitation"
          defaultMessage="Sorry, the invitation you received was not found. Please contact {supportEmail} if you think this is an error."
          values={values}
        />
      );
      case 'invalidExpiredInvitation': return (
        <FormattedMessage
          id="home.invalidExpiredInvitation"
          defaultMessage="Sorry, the invitation you received was expired. Please contact {supportEmail} if you think this is an error."
          values={values}
        />
      );
      default: return (
        <FormattedMessage
          id="home.invalidInvitation"
          defaultMessage="Sorry, an error occurred while processing your invitation. Please contact {supportEmail}."
          values={values}
        />
      );
      }
    }
  }
  return message;
}

class HomeComponent extends Component {
  static routeSlug(children) {
    if (!(children && children.props.route)) {
      return null;
    }
    if (/\/media\/:mediaId/.test(children.props.route.path)) {
      return 'media';
    }
    if (/\/source\/:sourceId/.test(children.props.route.path)) {
      return 'source';
    }
    if (/^:team$/.test(children.props.route.path)) {
      return 'team';
    }
    if (/^check\/me\(\/:tab\)/.test(children.props.route.path)) {
      return 'me';
    }
    if (/^:team\/project\/:projectId\(\/:query\)/.test(children.props.route.path)) {
      return 'project';
    }
    return null;
  }

  constructor(props) {
    super(props);

    this.state = {
      token: null,
      error: false,
      sessionStarted: false,
      path: window.location.pathname,
    };
  }

  componentWillMount() {
    this.setContext();
  }

  shouldComponentUpdate(nextProps, nextState) {
    return !isEqual(this.state, nextState) ||
    !isEqual(this.props, nextProps);
  }

  componentWillUpdate() {
    this.setContext();
  }

  setContext() {
    const { clientSessionId, setFlashMessage } = this.props;
    const context = new CheckContext(this);
    if (!this.state.token && !this.state.error) {
      context.startSession(this.props.user, clientSessionId, setFlashMessage);
    }
    context.setContext();
    context.startNetwork(this.state.token, clientSessionId, setFlashMessage);
  }

  getContext() {
    return new CheckContext(this).getContextStore();
  }

  loginCallback() {
    if (this.state.path !== '/check/user/password-change' &&
      this.state.path !== '/check/user/confirmed') {
      window.location.assign(this.state.path);
    } else {
      window.location.assign('/');
    }
    this.setState({ error: false, path: null });
  }

  render() {
    if (!this.state.sessionStarted) {
      return null;
    }

    const { children, location } = this.props;
    const routeSlug = HomeComponent.routeSlug(children);

    const routeIsPublic = children && children.props.route.public;
    if (!routeIsPublic && !this.state.token) {
      if (this.state.error) {
        return (
          <FlashMessageContext.Consumer>
            {flashMessage => (
              <LoginContainer
                loginCallback={this.loginCallback.bind(this)}
                message={buildLoginContainerMessage(
                  flashMessage,
                  this.state.error,
                  children.props.route,
                  location.query,
                )}
              />
            )}
          </FlashMessageContext.Consumer>
        );
      }
      return null;
    }

    const user = this.props.user || {};
    const loggedIn = !!this.state.token;
    const teamSlugFromUrl = window.location.pathname.match(/^\/([^/]+)/);
    const userTeamSlug = ((user.current_team && user.current_team.slug) ?
      user.current_team.slug : null);
    const teamSlug = (teamSlugFromUrl && teamSlugFromUrl[1] !== 'check' ? teamSlugFromUrl[1] : null) || userTeamSlug;
    const inTeamContext = Boolean(teamSlug);

    const currentUserIsMember = (() => {
      if (inTeamContext && loggedIn) {
        if (user.is_admin) {
          return true;
        }
        const teams = JSON.parse(user.user_teams);
        const team = teams[teamSlug] || {};
        return team.status === 'member';
      }
      return false;
    })();

    const showDrawer = !/\/media\/[0-9]+/.test(window.location.pathname);

    return (
      <React.Fragment>
        <GlobalStyle />
        <MuiPickersUtilsProvider utils={MomentUtils}>
          {config.intercomAppId && user.dbid && window.parent === window ?
            <Intercom
              appID={config.intercomAppId}
              user_id={user.dbid}
              email={user.email}
              name={user.name}
              check_workspace={teamSlug}
            /> : null
          }
          <Favicon url={`/images/logo/${config.appName}.ico`} animated={false} />
          <BrowserSupport />
          <UserTos user={user} />
          <Wrapper className={bemClass('home', routeSlug, `--${routeSlug}`)}>
            {showDrawer ? (
              <DrawerNavigation
                loggedIn={loggedIn}
                teamSlug={teamSlug}
                inTeamContext={inTeamContext}
                currentUserIsMember={currentUserIsMember}
                {...this.props}
              />
            ) : null}
            <Main>
              <Header
                loggedIn={loggedIn}
                pageType={routeSlug}
                inTeamContext={inTeamContext}
                currentUserIsMember={currentUserIsMember}
                {...this.props}
              />
              <FlashMessage />
              <StyledContent className="content-wrapper">
                {children}
              </StyledContent>
            </Main>
          </Wrapper>
        </MuiPickersUtilsProvider>
      </React.Fragment>
    );
  }
}

HomeComponent.propTypes = {
  // https://github.com/yannickcr/eslint-plugin-react/issues/1389
  // eslint-disable-next-line react/no-typos
  clientSessionId: PropTypes.string.isRequired,
  setFlashMessage: PropTypes.func.isRequired,
};

HomeComponent.contextTypes = {
  store: PropTypes.object,
};

const ConnectedHomeComponent = withSetFlashMessage(withClientSessionId(HomeComponent));

const HomeContainer = Relay.createContainer(ConnectedHomeComponent, {
  fragments: {
    user: () => Relay.QL`
      fragment on User {
        id
        dbid
        name
        token
        email
        is_admin
        accepted_terms
        last_accepted_terms_at
        name
        login
        permissions
        profile_image
        settings
        source_id
        team_ids
        user_teams
        current_project {
          dbid
          id
          title
          team {
            id
            dbid
            avatar
            name
            slug
          }
        }
        current_team {
          id
          dbid
          avatar
          name
          slug
          projects(first: 10000) {
            edges {
              node {
                id
                dbid
                title
                team {
                  id
                  dbid
                  avatar
                  name
                  slug
                }
              }
            }
          }
        }
      }
    `,
  },
});

// eslint-disable-next-line react/no-multi-comp
class Home extends Component {
  componentWillMount() {
    const context = new CheckContext(this);
    const { clientSessionId, setFlashMessage } = this.props;
    context.startNetwork(null, clientSessionId, setFlashMessage);
  }

  // eslint-disable-next-line class-methods-use-this
  render() {
    const route = new MeRoute();

    return (
      <Relay.RootContainer
        Component={HomeContainer}
        route={route}
        renderFetched={data => (
          <HomeContainer
            location={this.props.location}
            params={this.props.params}
            {...data}
          >
            {this.props.children}
          </HomeContainer>
        )}
      />
    );
  }
}

Home.propTypes = {
  clientSessionId: PropTypes.string.isRequired,
  setFlashMessage: PropTypes.func.isRequired,
};

Home.contextTypes = {
  store: PropTypes.object,
};

export default withSetFlashMessage(withClientSessionId(Home));
<|endoftext|>


<commit_before>import {customElement, bindable, useView} from 'aurelia-templating';
import {bindingMode} from 'aurelia-binding';
import {inject} from 'aurelia-dependency-injection';
import {PLATFORM} from 'aurelia-pal';

import {Options, GLOBAL_OPTIONS} from './options';
import {Dragula} from './dragula';

@bindable({ name: 'moves', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'accepts', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'invalid', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'containers', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'isContainer', attribute: 'is-container', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'copy', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'copySortSource', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'revertOnSpill', attribute: 'revert-on-spill', defaultBindingMode: bindingMode.oneTime, defaultValue: true })
@bindable({ name: 'removeOnSpill', attribute: 'remove-on-spill', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'direction', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'ignoreInputTextSelection', attribute: 'ingore-input-text-selection', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'mirrorContainer', attribute: 'mirror-container', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'targetClass', attribute: 'target-class', defaultBindingMode: bindingMode.oneTime, defaultValue: 'drop-target' })
@bindable({ name: 'sourceClass', attribute: 'source-class', defaultBindingMode: bindingMode.oneTime, defaultValue: 'drag-source' })
@bindable({ name: 'dragFn', attribute: 'drag-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'dropFn', attribute: 'drop-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'dragEndFn', attribute: 'drag-end-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'clonedFn', attribute: 'cloned-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'overFn', attribute: 'over-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'outFn', attribute: 'out-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'shadowFn', attribute: 'shadow-fn', defaultBindingMode: bindingMode.oneTime })
@customElement('dragula-and-drop')
@useView('./dragula-and-drop.html')
@inject(GLOBAL_OPTIONS)
export class DragulaAndDrop {

  constructor(globalOptions) {
    this.dragula = {};
    this.globalOptions = globalOptions;
  }

  bind() {
    let boundOptions = this._setupOptions();

    let aureliaOptions = {
      isContainer: this._isContainer.bind(this),
      moves: this._moves.bind(this),
      accepts: this._accepts.bind(this),
      invalid: this._invalid.bind(this)
    };

    let options = Object.assign(aureliaOptions, boundOptions);
    this.dragula = new Dragula(options);

    this.dragula.on('drop', this._dropFunction.bind(this));

    this.dragula.on('drag', (item, source, itemVM) => {
      if (typeof this.dragFn === 'function')
        this.dragFn({ item, source, itemVM });
    });

    this.dragula.on('dragend', (item, itemVM) => {
      if (typeof this.dragEndFn === 'function')
        this.dragEndFn({ item, itemVM });
    });

    this.dragula.on('cloned', (copy, item, type, itemVM) => {
      if (typeof this.clonedFn === 'function')
        this.clonedFn({ copy, item, type, itemVM });
    });

    this.dragula.on('over', (item, target, source, itemVM) => {
      if (typeof this.overFn === 'function')
        this.overFn({ item, target, source, itemVM });
    });

    this.dragula.on('out', (item, target, source, itemVM) => {
      if (typeof this.outFn === 'function')
        this.outFn({ item, target, source, itemVM });
    });

    this.dragula.on('shadow', (item, target, source, itemVM) => {
      if (typeof this.shadowFn === 'function')
        this.shadowFn({ item, target, source, itemVM });
    });
  }

  unbind() {
    this.dragula.destroy();
  }

  _dropFunction(item, target, source, sibling, itemVM, siblingVM) {
    this.dragula.cancel();
    if (typeof this.dropFn === 'function')
      this.dropFn({ item, target, source, sibling, itemVM, siblingVM });
  }

  _isContainer(el) {
    if (!el) {
      return false;
    }
    if (typeof this.isContainer === 'function') {
      return this.isContainer({ item: el });
    }

    if (this.dragula.dragging) {
      return el.classList.contains(this.targetClass);
    }
    return el.classList.contains(this.sourceClass);
  }

  _moves(item, source, handle, sibling) {
    if (typeof this.moves === 'function') {
      return this.moves({ item, source, handle, sibling });
    }
    else {
      return this.globalOptions.moves(item, source, handle, sibling);
    }
  }

  _accepts(item, target, source, sibling) {
    if (typeof this.accepts === 'function') {
      return this.accepts({ item, target, source, sibling });
    }
    else {
      return this.globalOptions.accepts(item, target, source, sibling);
    }
  }

  _invalid(item, handle) {
    if (typeof this.invalid === 'function') {
      return this.invalid({ item, handle });
    }
    else {
      return this.globalOptions.invalid(item, handle);
    }
  }

  _setupOptions() {
    let result = {
      containers: this._getOption('containers'),
      copy: this._convertToBooleanIfRequired(this._getOption('copy')),
      copySortSource: this._convertToBooleanIfRequired(this._getOption('copySortSource')),
      revertOnSpill: this._convertToBooleanIfRequired(this._getOption('revertOnSpill')),
      removeOnSpill: this._convertToBooleanIfRequired(this._getOption('removeOnSpill')),
      direction: this._getOption('direction'),
      ignoreInputTextSelection: this._convertToBooleanIfRequired(this._getOption('ignoreInputTextSelection')),
      mirrorContainer: this._getOption('mirrorContainer')
    };

    return result;
  }

  _getOption(option) {
    if (this[option] == null) {
      return this.globalOptions[option];
    }
    return this[option];
  }

  _convertToBooleanIfRequired(option) {
    if (typeof option === 'function') {
      return option;
    }
    if (typeof option === 'string') {
      return option.toLowerCase() === 'true';
    }
    return new Boolean(option).valueOf();
  }
}
<commit_msg>remove the flicker on drop<commit_after>import {customElement, bindable, useView} from 'aurelia-templating';
import {bindingMode} from 'aurelia-binding';
import {inject} from 'aurelia-dependency-injection';
import {PLATFORM} from 'aurelia-pal';

import {Options, GLOBAL_OPTIONS} from './options';
import {Dragula} from './dragula';

@bindable({ name: 'moves', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'accepts', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'invalid', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'containers', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'isContainer', attribute: 'is-container', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'copy', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'copySortSource', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'revertOnSpill', attribute: 'revert-on-spill', defaultBindingMode: bindingMode.oneTime, defaultValue: true })
@bindable({ name: 'removeOnSpill', attribute: 'remove-on-spill', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'direction', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'ignoreInputTextSelection', attribute: 'ingore-input-text-selection', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'mirrorContainer', attribute: 'mirror-container', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'targetClass', attribute: 'target-class', defaultBindingMode: bindingMode.oneTime, defaultValue: 'drop-target' })
@bindable({ name: 'sourceClass', attribute: 'source-class', defaultBindingMode: bindingMode.oneTime, defaultValue: 'drag-source' })
@bindable({ name: 'dragFn', attribute: 'drag-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'dropFn', attribute: 'drop-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'dragEndFn', attribute: 'drag-end-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'clonedFn', attribute: 'cloned-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'overFn', attribute: 'over-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'outFn', attribute: 'out-fn', defaultBindingMode: bindingMode.oneTime })
@bindable({ name: 'shadowFn', attribute: 'shadow-fn', defaultBindingMode: bindingMode.oneTime })
@customElement('dragula-and-drop')
@useView('./dragula-and-drop.html')
@inject(GLOBAL_OPTIONS)
export class DragulaAndDrop {

  constructor(globalOptions) {
    this.dragula = {};
    this.globalOptions = globalOptions;
  }

  bind() {
    let boundOptions = this._setupOptions();

    let aureliaOptions = {
      isContainer: this._isContainer.bind(this),
      moves: this._moves.bind(this),
      accepts: this._accepts.bind(this),
      invalid: this._invalid.bind(this)
    };

    this.options = Object.assign(aureliaOptions, boundOptions);
    this.dragula = new Dragula(this.options);

    this.dragula.on('drop', this._dropFunction.bind(this));

    this.dragula.on('drag', (item, source, itemVM) => {
      if (typeof this.dragFn === 'function')
        this.dragFn({ item, source, itemVM });
    });

    this.dragula.on('dragend', (item, itemVM) => {
      if (typeof this.dragEndFn === 'function')
        this.dragEndFn({ item, itemVM });
    });

    this.dragula.on('cloned', (copy, item, type, itemVM) => {
      if (typeof this.clonedFn === 'function')
        this.clonedFn({ copy, item, type, itemVM });
    });

    this.dragula.on('over', (item, target, source, itemVM) => {
      if (typeof this.overFn === 'function')
        this.overFn({ item, target, source, itemVM });
    });

    this.dragula.on('out', (item, target, source, itemVM) => {
      if (typeof this.outFn === 'function')
        this.outFn({ item, target, source, itemVM });
    });

    this.dragula.on('shadow', (item, target, source, itemVM) => {
      if (typeof this.shadowFn === 'function')
        this.shadowFn({ item, target, source, itemVM });
    });
  }

  unbind() {
    this.dragula.destroy();
  }

  _dropFunction(item, target, source, sibling, itemVM, siblingVM) {
    this.dragula.cancel(this.options.revertOnSpill, true);
    if (typeof this.dropFn === 'function')
      this.dropFn({ item, target, source, sibling, itemVM, siblingVM });
  }

  _isContainer(el) {
    if (!el) {
      return false;
    }
    if (typeof this.isContainer === 'function') {
      return this.isContainer({ item: el });
    }

    if (this.dragula.dragging) {
      return el.classList.contains(this.targetClass);
    }
    return el.classList.contains(this.sourceClass);
  }

  _moves(item, source, handle, sibling) {
    if (typeof this.moves === 'function') {
      return this.moves({ item, source, handle, sibling });
    }
    else {
      return this.globalOptions.moves(item, source, handle, sibling);
    }
  }

  _accepts(item, target, source, sibling) {
    if (typeof this.accepts === 'function') {
      return this.accepts({ item, target, source, sibling });
    }
    else {
      return this.globalOptions.accepts(item, target, source, sibling);
    }
  }

  _invalid(item, handle) {
    if (typeof this.invalid === 'function') {
      return this.invalid({ item, handle });
    }
    else {
      return this.globalOptions.invalid(item, handle);
    }
  }

  _setupOptions() {
    let result = {
      containers: this._getOption('containers'),
      copy: this._convertToBooleanIfRequired(this._getOption('copy')),
      copySortSource: this._convertToBooleanIfRequired(this._getOption('copySortSource')),
      revertOnSpill: this._convertToBooleanIfRequired(this._getOption('revertOnSpill')),
      removeOnSpill: this._convertToBooleanIfRequired(this._getOption('removeOnSpill')),
      direction: this._getOption('direction'),
      ignoreInputTextSelection: this._convertToBooleanIfRequired(this._getOption('ignoreInputTextSelection')),
      mirrorContainer: this._getOption('mirrorContainer')
    };

    return result;
  }

  _getOption(option) {
    if (this[option] == null) {
      return this.globalOptions[option];
    }
    return this[option];
  }

  _convertToBooleanIfRequired(option) {
    if (typeof option === 'function') {
      return option;
    }
    if (typeof option === 'string') {
      return option.toLowerCase() === 'true';
    }
    return new Boolean(option).valueOf();
  }
}
<|endoftext|>