<commit_before>(function() {
	/**
	 * Load the list of files asynchronously. This uses recursion in
	 * order to create a queue of files that will be loaded serially.
	 * Each layer, starting at the bottom, loads a file and then loads
	 * the layer on top of it. The very top file on the stack will have
	 * zero files to load, so instead it will be the one to call the
	 * callback to notify the caller that all the content is loaded.
	 *
	 * @param {Object} context function to call this method in the context of
	 * @param {Array.<string>} paths array of strings containing relative paths for required locale data files
	 * @param {Array} results empty array in which to place the resulting json when it is loaded from a file
	 * @param {Object} params An object full of parameters that the caller is passing to this function to help load the files
	 * @param {function(Array.<Object>)} callback callback to call when this function is finished attempting
	 * to load all the files that exist and can be loaded
	 */
	function loadFiles(context, paths, results, params, callback) {
		var root = "resources/";
		if (params && typeof(params.root) !== "undefined") {
			root = params.root + '/';
		}
		if (paths.length > 0) {
			var path = paths.shift();
			var ajax = new enyo.Ajax({url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path)});
			//console.log("moondemo2: browser/async: attempting to load lib/enyo-ilib/ilib/locale/" + path);
			var resultFunc = function(inSender, json) {
                // console.log("moondemo2: " + (!inSender.failed && json ? "success" : "failed"));
				results.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				if (paths.length > 0) {
					loadFiles(context, paths, results, params, callback);
				} else {
					// only the bottom item on the stack will call
					// the callback
					callback.call(context, results);
				}
			};
			ajax.response(this, resultFunc);
			ajax.error(this, function(inSender, json) {
				// not there? Try the standard place instead
				var file = root + path;
				// console.log("moondemo2: browser/async: attempting to load " + file);
				var ajax2 = new enyo.Ajax({url: file});

				ajax2.response(this, resultFunc);
				ajax2.error(this, resultFunc);
				ajax2.go();
			});
			ajax.go();
		}
	}

	ilib.setLoaderCallback(enyo.bind(this, function(paths, sync, params, callback) {
		if (sync) {
			var ret = [];
			var root = "resources/";
			if (params && typeof(params.root) !== "undefined") {
				root = params.root + '/';
			}
			// synchronous
			paths.forEach(function (path) {
				// console.log("browser/sync: attempting to load lib/enyo-ilib/ilib/locale/" + path);
				var ajax = new enyo.Ajax({
					url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path),
					sync: true
				});

				var handler = function(inSender, json) {
                    // console.log((!inSender.failed && json ? "success" : "failed"));
					ret.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				};
				ajax.response(this, handler);
				ajax.error(this, function(inSender, json) {
					// console.log("browser/sync: Now attempting to load " + root + path);
					var ajax2 = new enyo.Ajax({
						url: root + path,
						sync: true
					});
					ajax2.response(this, handler);
					ajax2.error(this, handler);
					ajax2.go();
				});
				ajax.go();
			});

			if (typeof(callback) === 'function') {
				callback.call(this, ret);
			}
			return ret;
		}

		// asynchronous
		var results = [];
		loadFiles(this, paths, results, params, callback);
	}));

	if (typeof(window.UILocale) !== 'undefined') {
		// this is a hack until GF-1581 is fixed
		ilib.setLocale(window.UILocale);
	}

	// enyo.updateI18NClasses should be called after every setLocale, but there isn't such a callback in current version
    enyo.updateI18NClasses = function updateBodyClasses() {
        var li = new ilib.LocaleInfo(); // for the current locale
        var locale = li.getLocale();
		var base = "enyo-locale-";

        // Remove old style definitions (hack style becouse enyo.dom doesn't have methods like enyo.dom.getBodyClasses, enyo.dom.removeBodyClass)
        if (document && document.body && document.body.className && document.body.className) {
            document.body.className = document.body.className.replace(new RegExp('(^|\\s)'+ base +'[^\\s]*', 'g'), '');
        }

		var scriptName = li.getScript();
		if (scriptName !== "Latn" || locale.getLanguage() === "vi") {
			// allow enyo to define other fonts for non-Latin languages, or Vietnamese which
			// is Latin-based, but the characters with multiple accents don't appear in the
			// regular fonts, creating a strange "ransom note" look with a mix of fonts in the
			// same word. So, treat it like a non-Latin language in order to get all the characters
			// to display with the same font.
			enyo.dom.addBodyClass(base + "non-latin");
		}
		if (scriptName !== 'Latn' && scriptName !== 'Cyrl' && scriptName !== 'Grek') {
			// GF-45884: allow enyo to avoid setting italic fonts for those scripts that do not
			// commonly use italics
			enyo.dom.addBodyClass(base + "non-italic");
		}

		// allow enyo to apply right-to-left styles to the app and widgets if necessary
		var script = new ilib.ScriptInfo(scriptName);
		if (script.getScriptDirection() === "rtl") {
			enyo.dom.addBodyClass(base + "right-to-left");
			if (enyo.Control) {
				enyo.Control.prototype.rtl = true;
			}
		}

		// allow enyo or the apps to give CSS classes that are specific to the language, country, or script
		if (locale.getLanguage()) {
			enyo.dom.addBodyClass(base + locale.getLanguage());
			if (locale.getScript()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript());
				if (locale.getRegion()) {
					enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript() + "-" + locale.getRegion());
				}
			} else if (locale.getRegion()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getRegion());
			}
		}
		if (locale.getScript()) {
			enyo.dom.addBodyClass(base + locale.getScript());
		}
		if (locale.getRegion()) {
			enyo.dom.addBodyClass(base + locale.getRegion());
		}
    };
})();

/*
 * Reset the $L function to use ilib instead of the dummy function that enyo
 * comes with by default.
 */
$L = function (string) {
	var str;
	if (!$L.rb) {
		$L.setLocale();
	}
	if (typeof(string) === 'string') {
		if (!$L.rb) {
			return string;
		}
		str = $L.rb.getString(string);
	} else if (typeof(string) === 'object') {
		if (typeof(string.key) !== 'undefined' && typeof(string.value) !== 'undefined') {
			if (!$L.rb) {
				return string.value;
			}
			str = $L.rb.getString(string.value, string.key);
		} else {
			str = "";
		}
	} else {
		str = string;
	}
	return str.toString();
};

/**
 * Set the locale for the strings that $L loads. This may reload the
 * string resources if necessary.
 * @param {string} spec the locale specifier
 */
$L.setLocale = function (spec) {
	var locale = new ilib.Locale(spec);
	if (!$L.rb || spec !== $L.rb.getLocale().getSpec()) {
		$L.rb = new ilib.ResBundle({
			locale: locale,
			type: "html",
			name: "strings",
			sync: true,
			lengthen: true		// if pseudo-localizing, this tells it to lengthen strings
		});
	}
};

/**
 * This Enyo hook lets us know that the system locale has changed and gives
 * us a chance to update the iLib locale before Enyo broadcasts its
 * `onlocalechange` signal.
 */
enyo.updateLocale = function() {
	ilib.setLocale(navigator.language);
	$L.setLocale(navigator.language);
	enyo.updateI18NClasses();
};

// we go ahead and run this once during loading of iLib settings are valid
// during the loads of later libraries.
enyo.updateLocale();
<commit_msg>GF-54530: avoid "ransome note" fonts<commit_after>(function() {
	/**
	 * Load the list of files asynchronously. This uses recursion in
	 * order to create a queue of files that will be loaded serially.
	 * Each layer, starting at the bottom, loads a file and then loads
	 * the layer on top of it. The very top file on the stack will have
	 * zero files to load, so instead it will be the one to call the
	 * callback to notify the caller that all the content is loaded.
	 *
	 * @param {Object} context function to call this method in the context of
	 * @param {Array.<string>} paths array of strings containing relative paths for required locale data files
	 * @param {Array} results empty array in which to place the resulting json when it is loaded from a file
	 * @param {Object} params An object full of parameters that the caller is passing to this function to help load the files
	 * @param {function(Array.<Object>)} callback callback to call when this function is finished attempting
	 * to load all the files that exist and can be loaded
	 */
	function loadFiles(context, paths, results, params, callback) {
		var root = "resources/";
		if (params && typeof(params.root) !== "undefined") {
			root = params.root + '/';
		}
		if (paths.length > 0) {
			var path = paths.shift();
			var ajax = new enyo.Ajax({url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path)});
			//console.log("moondemo2: browser/async: attempting to load lib/enyo-ilib/ilib/locale/" + path);
			var resultFunc = function(inSender, json) {
                // console.log("moondemo2: " + (!inSender.failed && json ? "success" : "failed"));
				results.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				if (paths.length > 0) {
					loadFiles(context, paths, results, params, callback);
				} else {
					// only the bottom item on the stack will call
					// the callback
					callback.call(context, results);
				}
			};
			ajax.response(this, resultFunc);
			ajax.error(this, function(inSender, json) {
				// not there? Try the standard place instead
				var file = root + path;
				// console.log("moondemo2: browser/async: attempting to load " + file);
				var ajax2 = new enyo.Ajax({url: file});

				ajax2.response(this, resultFunc);
				ajax2.error(this, resultFunc);
				ajax2.go();
			});
			ajax.go();
		}
	}

	ilib.setLoaderCallback(enyo.bind(this, function(paths, sync, params, callback) {
		if (sync) {
			var ret = [];
			var root = "resources/";
			if (params && typeof(params.root) !== "undefined") {
				root = params.root + '/';
			}
			// synchronous
			paths.forEach(function (path) {
				// console.log("browser/sync: attempting to load lib/enyo-ilib/ilib/locale/" + path);
				var ajax = new enyo.Ajax({
					url: enyo.path.rewrite("$lib/enyo-ilib/ilib/locale/" + path),
					sync: true
				});

				var handler = function(inSender, json) {
                    // console.log((!inSender.failed && json ? "success" : "failed"));
					ret.push(!inSender.failed && (typeof(json) === 'object') ? json : undefined);
				};
				ajax.response(this, handler);
				ajax.error(this, function(inSender, json) {
					// console.log("browser/sync: Now attempting to load " + root + path);
					var ajax2 = new enyo.Ajax({
						url: root + path,
						sync: true
					});
					ajax2.response(this, handler);
					ajax2.error(this, handler);
					ajax2.go();
				});
				ajax.go();
			});

			if (typeof(callback) === 'function') {
				callback.call(this, ret);
			}
			return ret;
		}

		// asynchronous
		var results = [];
		loadFiles(this, paths, results, params, callback);
	}));

	if (typeof(window.UILocale) !== 'undefined') {
		// this is a hack until GF-1581 is fixed
		ilib.setLocale(window.UILocale);
	}

	// enyo.updateI18NClasses should be called after every setLocale, but there isn't such a callback in current version
    enyo.updateI18NClasses = function updateBodyClasses() {
        var li = new ilib.LocaleInfo(); // for the current locale
        var locale = li.getLocale();
		var base = "enyo-locale-";

        // Remove old style definitions (hack style becouse enyo.dom doesn't have methods like enyo.dom.getBodyClasses, enyo.dom.removeBodyClass)
        if (document && document.body && document.body.className && document.body.className) {
            document.body.className = document.body.className.replace(new RegExp('(^|\\s)'+ base +'[^\\s]*', 'g'), '');
        }

        var nonLatinLanguages = ["cs", "hu", "lv", "lt", "po", "ro", "sr", "sl", "tr", "vi"];
		var scriptName = li.getScript();
		if (scriptName !== "Latn" || nonLatinLanguages.indexOf(locale.getLanguage()) !== -1) {
			// allow enyo to define other fonts for non-Latin languages, or for certain
			// Latin-based languages where the characters with some accents don't appear in the
			// regular fonts, creating a strange "ransom note" look with a mix of fonts in the
			// same word. So, treat it like a non-Latin language in order to get all the characters
			// to display with the same font.
			enyo.dom.addBodyClass(base + "non-latin");
		}
		if (scriptName !== 'Latn' && scriptName !== 'Cyrl' && scriptName !== 'Grek') {
			// GF-45884: allow enyo to avoid setting italic fonts for those scripts that do not
			// commonly use italics
			enyo.dom.addBodyClass(base + "non-italic");
		}

		// allow enyo to apply right-to-left styles to the app and widgets if necessary
		var script = new ilib.ScriptInfo(scriptName);
		if (script.getScriptDirection() === "rtl") {
			enyo.dom.addBodyClass(base + "right-to-left");
			if (enyo.Control) {
				enyo.Control.prototype.rtl = true;
			}
		}

		// allow enyo or the apps to give CSS classes that are specific to the language, country, or script
		if (locale.getLanguage()) {
			enyo.dom.addBodyClass(base + locale.getLanguage());
			if (locale.getScript()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript());
				if (locale.getRegion()) {
					enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getScript() + "-" + locale.getRegion());
				}
			} else if (locale.getRegion()) {
				enyo.dom.addBodyClass(base + locale.getLanguage() + "-" + locale.getRegion());
			}
		}
		if (locale.getScript()) {
			enyo.dom.addBodyClass(base + locale.getScript());
		}
		if (locale.getRegion()) {
			enyo.dom.addBodyClass(base + locale.getRegion());
		}
    };
})();

/*
 * Reset the $L function to use ilib instead of the dummy function that enyo
 * comes with by default.
 */
$L = function (string) {
	var str;
	if (!$L.rb) {
		$L.setLocale();
	}
	if (typeof(string) === 'string') {
		if (!$L.rb) {
			return string;
		}
		str = $L.rb.getString(string);
	} else if (typeof(string) === 'object') {
		if (typeof(string.key) !== 'undefined' && typeof(string.value) !== 'undefined') {
			if (!$L.rb) {
				return string.value;
			}
			str = $L.rb.getString(string.value, string.key);
		} else {
			str = "";
		}
	} else {
		str = string;
	}
	return str.toString();
};

/**
 * Set the locale for the strings that $L loads. This may reload the
 * string resources if necessary.
 * @param {string} spec the locale specifier
 */
$L.setLocale = function (spec) {
	var locale = new ilib.Locale(spec);
	if (!$L.rb || spec !== $L.rb.getLocale().getSpec()) {
		$L.rb = new ilib.ResBundle({
			locale: locale,
			type: "html",
			name: "strings",
			sync: true,
			lengthen: true		// if pseudo-localizing, this tells it to lengthen strings
		});
	}
};

/**
 * This Enyo hook lets us know that the system locale has changed and gives
 * us a chance to update the iLib locale before Enyo broadcasts its
 * `onlocalechange` signal.
 */
enyo.updateLocale = function() {
	ilib.setLocale(navigator.language);
	$L.setLocale(navigator.language);
	enyo.updateI18NClasses();
};

// we go ahead and run this once during loading of iLib settings are valid
// during the loads of later libraries.
enyo.updateLocale();
<|endoftext|>


<commit_before>var CACHE_NAME = 'MTGStats-cache-v1.3.0'
var urlsToCache = [
  './css/history.css',
  './css/index.css',
  './css/master.css',
  './css/stats.css',
  './img/bg1.webp',
  './img/check.png',
  './img/crown.png',
  './img/favicon.ico',
  './img/infect.png',
  './img/MTG-512x512.png',
  './img/MTG.png',
  './img/undo.png',
  './js/accordion-component.js',
  './js/draw.js',
  './js/history.js',
  './js/popup-component.js',
  './js/slider-component.js',
  './js/stat-component.js',
  './js/stat-scroller-component.js',
  './js/stats.js',
  './mp3/click.mp3',
  './2player.html',
  './4player.html',
  './history.html',
  '.',
]

self.addEventListener('install', function (event) {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME).then(function (cache) {
      console.log('Opened cache')
      return cache.addAll(urlsToCache)
    })
  )
})

self.addEventListener('fetch', function (event) {
  event.respondWith(
    caches.match(event.request).then(function (response) {
      // Cache hit - return response
      if (response) {
        return response
      }

      var fetchRequest = event.request.clone()

      return fetch(fetchRequest).then(function (response) {
        if (!response || response.status !== 200 || response.type !== 'basic') {
          return response
        }

        var responseToCache = response.clone()

        caches.open(CACHE_NAME).then(function (cache) {
          cache.put(event.request, responseToCache)
        })

        return response
      })
    })
  )
})

self.addEventListener('activate', function (event) {
  var cacheWhitelist = [CACHE_NAME]

  event.waitUntil(
    caches.keys().then(function (cacheNames) {
      return Promise.all(
        cacheNames.map(function (cacheName) {
          if (cacheWhitelist.indexOf(cacheName) === -1) {
            return caches.delete(cacheName)
          }
        })
      )
    })
  )
})
<commit_msg>Serviceworker cleanup<commit_after>var CACHE_NAME = 'MTGStats-cache-v1.3.0'
var urlsToCache = [
  './css/history.css',
  './css/index.css',
  './css/master.css',
  './css/stats.css',
  './img/bg1.webp',
  './img/check.png',
  './img/crown.png',
  './img/favicon.ico',
  './img/infect.png',
  './img/MTG-512x512.png',
  './img/MTG.png',
  './img/undo.png',
  './js/accordion-component.js',
  './js/draw.js',
  './js/history.js',
  './js/popup-component.js',
  './js/slider-component.js',
  './js/stat-component.js',
  './js/stat-scroller-component.js',
  './js/stats.js',
  './mp3/click.mp3',
  './2player.html',
  './4player.html',
  './history.html',
  '.',
]

self.addEventListener('install', (event) => {
  // Perform install steps
  event.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      console.log('Opened cache')
      return cache.addAll(urlsToCache)
    })
  )
})

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      // Cache hit - return response
      if (response) return response

      const fetchRequest = event.request.clone()

      return fetch(fetchRequest).then((response) => {
        if (!response || response.status !== 200 || response.type !== 'basic') {
          return response
        }

        const responseToCache = response.clone()

        caches.open(CACHE_NAME).then((cache) => {
          cache.put(event.request, responseToCache)
        })

        return response
      })
    })
  )
})

self.addEventListener('activate', (event) => {
  const cacheWhitelist = [CACHE_NAME]

  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.map((cacheName) => {
          if (!cacheWhitelist.includes(cacheName)) {
            return caches.delete(cacheName)
          }
        })
      )
    })
  )
})
<|endoftext|>


<commit_before>/**
 Esta es una interfaz a Cryptico y a todos los procesos POST
**/
app.factory('$conexion', function ($http) {
//PRIVATE STATIC FINAL
	var ruta = "network/autenticacion",
		cookieHashCode = "",
		llavePrivada = "",
		llavePublica = "",
		llaveServer = "",
		r = {};

/**
Funcion privada que genera una frase aleatorio de tamaño intSize
@parameters
	Number intSize
@return
	String
**/
	var strAleatorio = function (intSize) {
		var str = "",alfabeto = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 ";
		for (var i=0; i < intSize; i++)
			str += alfabeto.charAt(Math.floor(Math.random() * alfabeto.length));
		console.log("strAleatorio: ", str);
		return str;
	};

//PUBLIC
/**
Funcion inicializa las variables de comunicación
@parameters
@return
**/
	r.iniciar = function () {
		llaveServer = localStorage.getItem("3");
		if (llaveServer === null) {//undefined para chrome null para FX
			$http.get("/network/1").then(function(response){
				console.log("Serverkey: ",response);
			});
			localStorage.setItem("3", llaveServer);
		}
		var semilla = localStorage.getItem("1");
		if (semilla === null) {//undefined para chrome null para FX
			semilla = strAleatorio(10);
			cookieHashCode = strAleatorio(10);
			console.log("local storage iniciado");
			localStorage.setItem("1", semilla);
			localStorage.setItem("2", cookieHashCode);

		}
		else cookieHashCode = localStorage.getItem("2");
		//Minimo llaves de 512
		llavePrivada = cryptico.generateRSAKey(semilla, 512);
		llavePublica = cryptico.publicKeyString(llavePrivada);
		console.log("semilla: ", semilla);
		console.log("llpr: ", llavePrivada);
		console.log("llpb: ", llavePublica);
		console.log("chc: ", cookieHashCode);
		console.log("test: ", r.cifrar("perro"));
		console.log("test1: ", r.decifrar(r.cifrar("perro")));
	};

/**
Funcion que cifra con la llave RSA generada por el cliente
@parameters
	String texto original
@return
	String texto cifrado
**/
	r.cifrar = function (strOriginal) {
		//console.log("cifrar con: "+llavePublica)
		return cryptico.encrypt(strOriginal, llavePublica).cipher
		//La documentación pide la llave publica para cifrar ?
	}

/**
Funcion que decifra con la llave RSA del server
@parameters
	String texto a decifrar
@return
	String texto original
**/
	r.decifrar = function (strCifrado) {
		return cryptico.decrypt(strCifrado, llavePrivada).plaintext;
		//0.o la llave privada para decifrar?
	}

/**
Funcion asincrona que hace peticiones rest
@parameters
	String https://dominio/network/<strRuta>
	String parametros del post request
	Function se ejecutará tras cualquier respuesta del server
@return
**/
	r.enviar = function (strRuta, objData, callback) {
		$http({
			method: 'POST',
			headers: {'Content-Type': 'application/x-www-form-urlencoded'},
			url: "/network/"+strRuta,
			transformRequest: function(obj) {
				var str = [];
				for(var p in obj)
				str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
				return str.join('&');
			},
			data: objData
		}).then(callback);
	}

//GETs
	r.getLlavePublica = function () {
		return llavePublica
	}
	r.getCookieHashCode = function () {
		return cookieHashCode
	}

	return r
});
console.log("conexionFactory cargado")
<commit_msg>eliminando archivos que se movieron<commit_after><|endoftext|>


<commit_before>var bike = require("./transportation/bike");
var bus = require("./transportation/bus");
var car = require("./transportation/car");
var walk = require("./transportation/walk");
var bike = require("./transportation/bike");
var Promise = require('bluebird');

var AVG_SALARY_PER_SEC = 0.00693629807

var compareTransportation = function(a, b) {
  costA = a.time * AVG_SALARY_PER_SEC + a.cost;
  costB = b.time * AVG_SALARY_PER_SEC + b.cost;

  if (costA === costB) {
    return 0;
  }
  if (costA < costB) {
    return -1;
  }

  return 1;
}

module.exports = function(origin, destination) {
  directionsPromises = [walk(origin, destination),
                        bus(origin, destination),
                        bike(origin, destination)]//,
                        //car(origin, destination)]

  return Promise.all(directionsPromises).then(function(directions) {
    return directions.sort(compareTransportation);
  });
}
<commit_msg>driving directions now include uber cost<commit_after>var bike = require("./transportation/bike");
var bus = require("./transportation/bus");
var car = require("./transportation/car");
var walk = require("./transportation/walk");
var bike = require("./transportation/bike");
var Promise = require('bluebird');

var AVG_SALARY_PER_SEC = 0.00693629807;
var METER_TO_MILE = 0.000621371;

var cost = function(a) {
  if (a.type === "driving") {
    console.log("computing driving cost");
    a.cost = 1.35 + a.time * 0.24 + a.distance * METER_TO_MILE * 0.000621371 + 1.20 + 0.20;
    if (a.cost < 4.20) {
      a.cost = 4.20;
    }
  }
  return a.time * AVG_SALARY_PER_SEC + a.cost;
}

var compareTransportation = function(a, b) {
  costA = cost(a);
  costB = cost(b);

  if (costA === costB) {
    return 0;
  }
  if (costA < costB) {
    return -1;
  }

  return 1;
}

module.exports = function(origin, destination) {
  directionsPromises = [walk(origin, destination),
                        bus(origin, destination),
                        bike(origin, destination),
                        car(origin, destination)];

  return Promise.all(directionsPromises).then(function(directions) {
    return directions.sort(compareTransportation);
  });
}
<|endoftext|>


<commit_before>function mixins(type) {
  if ('ellipsis' == type) {
    return {
      'white-space': 'nowrap',
      'overflow': 'hidden',
      'text-overflow': 'ellipsis'
    }
  }

  return type;
}

<commit_msg>remove old config folder related to rework<commit_after><|endoftext|>


<commit_before>/*jshint node:true, indent:2, curly:true eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, trailing:true, white:true */
/*global XT:true, Globalize:true, enyo:true, _:true */

(function () {

  /**
    @name XV.ToggleButton
    @class A control that looks like a switch with labels for two states.

    Derived from onyx.ToggleButton.
    @extends onyx.ToggleButton
   */
  enyo.kind(/** @lends XV.ToggleButton# */{
    name: "XV.ToggleButton",
    kind: "onyx.ToggleButton",
    published: {
      attr: null
    },
    events: {
      onValueChange: ""
    },
    handlers: {
      onChange: "changed"
    },
    /**
     @todo Document the clear method.
     */
    clear: function (options) {
      this.setValue(false, options);
    },
    /**
     @todo Document the setValue method.
     */
    setValue: function (value, options) {
      options = options || {};
      this._silent = options.silent;
      this.inherited(arguments);
      this._silent = false;
    },
    /**
     @todo Document the changed method.
     */
    changed: function (inSender, inEvent) {
      if (!this._silent) {
        inEvent.value = this.getValue();
        this.doValueChange(inEvent);
      }
    }
  });

  /**
    @name XV.ToggleButtonWidget
    @class An input control consisting of fittable columns:
     label, decorator, and toggle button.

    Use to implement a toggle button, a switch with labels for two states.

    Creates an HTML input element.
    @extends XV.Input
   */
  enyo.kind(/** @lends XV.ToggleButtonWidget# */{
    name: "XV.ToggleButtonWidget",
    kind: "XV.Input",
    classes: "xv-inputwidget xv-checkboxwidget",
    published: {
      label: ""
    },
    components: [
      {kind: "FittableColumns", components: [
        {name: "label", content: "", classes: "xv-decorated-label"},
        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
          components: [
          {name: "input", kind: "onyx.ToggleButton", onChange: "inputChanged"}
        ]}
      ]}
    ],
    /**
     @todo Document the clear method.
     */
    clear: function (options) {
      this.setValue(false, options);
    },
    /**
     @todo Document the create method.
     */
    create: function () {
      this.inherited(arguments);
      this.labelChanged();
    },
    /**
     @todo Document the inputChanged method.
     */
    inputChanged: function (inSender, inEvent) {
      var input = this.$.input.getValue();
      this.setValue(input);
    },
    /**
     @todo Document the labelChanged method.
     */
    labelChanged: function () {
      var label = (this.getLabel() || ("_" + this.attr || "").loc()) + ":";
      this.$.label.setContent(label);
    },
    /**
	 Not applicable in the context of a toggle button,
	 even though it is available to input widgets generally.
     */
    placeholderChanged: function () {
      // Not applicable
    },
    /**
     @todo Document the valueChanged method.
     */
    valueChanged: function (value) {
      this.$.input.setValue(value);
      return value;
    }
  });

}());
<commit_msg>issue #18766: Fix toggle button to ignore type change requests.<commit_after>/*jshint node:true, indent:2, curly:true eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
regexp:true, undef:true, trailing:true, white:true */
/*global XT:true, Globalize:true, enyo:true, _:true */

(function () {

  /**
    @name XV.ToggleButton
    @class A control that looks like a switch with labels for two states.

    Derived from onyx.ToggleButton.
    @extends onyx.ToggleButton
   */
  enyo.kind(/** @lends XV.ToggleButton# */{
    name: "XV.ToggleButton",
    kind: "onyx.ToggleButton",
    published: {
      attr: null
    },
    events: {
      onValueChange: ""
    },
    handlers: {
      onChange: "changed"
    },
    /**
     @todo Document the clear method.
     */
    clear: function (options) {
      this.setValue(false, options);
    },
    /**
     @todo Document the setValue method.
     */
    setValue: function (value, options) {
      options = options || {};
      this._silent = options.silent;
      this.inherited(arguments);
      this._silent = false;
    },
    /**
     @todo Document the changed method.
     */
    changed: function (inSender, inEvent) {
      if (!this._silent) {
        inEvent.value = this.getValue();
        this.doValueChange(inEvent);
      }
    }
  });

  /**
    @name XV.ToggleButtonWidget
    @class An input control consisting of fittable columns:
     label, decorator, and toggle button.

    Use to implement a toggle button, a switch with labels for two states.

    Creates an HTML input element.
    @extends XV.Input
   */
  enyo.kind(/** @lends XV.ToggleButtonWidget# */{
    name: "XV.ToggleButtonWidget",
    kind: "XV.Input",
    classes: "xv-inputwidget xv-checkboxwidget",
    published: {
      label: ""
    },
    components: [
      {kind: "FittableColumns", components: [
        {name: "label", content: "", classes: "xv-decorated-label"},
        {kind: "onyx.InputDecorator", classes: "xv-input-decorator",
          components: [
          {name: "input", kind: "onyx.ToggleButton", onChange: "inputChanged"}
        ]}
      ]}
    ],
    /**
     @todo Document the clear method.
     */
    clear: function (options) {
      this.setValue(false, options);
    },
    /**
     @todo Document the create method.
     */
    create: function () {
      this.inherited(arguments);
      this.labelChanged();
    },
    /**
     @todo Document the inputChanged method.
     */
    inputChanged: function (inSender, inEvent) {
      var input = this.$.input.getValue();
      this.setValue(input);
    },
    /**
     @todo Document the labelChanged method.
     */
    labelChanged: function () {
      var label = (this.getLabel() || ("_" + this.attr || "").loc()) + ":";
      this.$.label.setContent(label);
    },
    /**
   Not applicable in the context of a toggle button,
   even though it is available to input widgets generally.
     */
    placeholderChanged: function () {
      // Not applicable
    },
    /**
     @todo Document the valueChanged method.
     */
    valueChanged: function (value) {
      this.$.input.setValue(value);
      return value;
    },
    typeChanged: function () {
      // Toggle button doesn't have this
    }
  });

}());
<|endoftext|>


<commit_before>openerp.web_process = function (openerp) {
    var QWeb = openerp.web.qweb,
          _t = openerp.web._t;
    openerp.web.ViewManager.include({
        start: function() {
            this._super();
            var self = this;
            this.process_check();
            this.process_help = this.action ? this.action.help : 'Help: Not Defined';
            this.model = this.dataset.model;
            if(this.action) this.process_model = this.action.res_model;
            else this.process_model = this.model;
        },
        process_check: function() {
            var self = this,
            grandparent = this.widget_parent && this.widget_parent.widget_parent,
            view = this.views[this.views_src[0].view_type],
            $process_view = this.$element.find('.oe-process-view');
            if (!(grandparent instanceof openerp.web.WebClient) ||
                !(view.view_type === this.views_src[0].view_type
                    && view.view_id === this.views_src[0].view_id)) {
                        $process_view.hide();
                        return;
            }
            $process_view.click(function() {
                self.initialize_process_view();
            });
        },
        initialize_process_view: function() {
            var self = this;
            $.when(this.fields_get(), this.help(), this.get_process_object()).pipe(function(fields, help, process) {
                self.process_fields = fields;
                self.process_help = help;
                if(process && process.length) {
                    if(process.length > 1) {
                        self.process_selection = process;
                    } else {
                        self.process_id = process[0][0],
                        self.process_title = process[0][1];
                    }
                }
                return $.Deferred().resolve();
            }).pipe(function() {
                var def = $.Deferred();
                if(self.process_id) {
                    self.graph_get().done(function(res) {
                        self.process_notes = res.notes;
                        self.process_title = res.name;
                        self.process_subflows = _.filter(res.nodes, function(x) {
                            return x.subflow != false;
                        });
                        self.process_related = res.related;
                        def.resolve(res);
                    });
                } else def.resolve();
                return def.promise();
            }).done(function(res) {
                $.when(self.render_process_view()).done(function() {
                    if(res) self.draw_process_graph(res);
                });
            });
        },
        graph_get: function() {
            var self = this;
            var def = $.Deferred();
            this.process_id = parseInt(this.process_id, 10);

            this.process_dataset
            .call("graph_get",[this.process_id, this.model || this.dataset.model, false, [80,80,150,100]])
            .done(function(res) {
                self.process_dataset
                    .call("search_by_model",[self.model || self.dataset.model,self.session.context])
                    .done(
                    function(r) {
                        res['related'] = r;
                        def.resolve(res);
                    });
            });
            return def.promise();
        },
        fields_get : function() {
            var self = this,
                def = $.Deferred(),
                dataset = new openerp.web.DataSetStatic(this, this.model || this.dataset.model, this.session.context);
            dataset
                .call('fields_get',[])
                .done(function(fields) {
                    def.resolve(fields);
                }).fail(def.reject);
            return def.promise();
        },
        help : function() {
            var self = this,
                def = $.Deferred();
            if(!this.subflow_model) {
                def.resolve(this.action ? (this.action.help!=false ? this.action.help : 'Help: Not Defined') : 'Help: Not Defined');
            } else {
                 var dataset = new openerp.web.DataSetSearch(this, "ir.actions.act_window", this.session.context, []);
                 dataset
                    .read_slice(['help'],
                    {
                        domain: [
                            ['res_model', '=', this.subflow_model],
                            ['name', 'ilike', this.subflow_name]
                        ]
                    }
                    ).done(function(res) {
                        def.resolve(res.help || 'Help: Not Defined');
                    });
            }
            return def.promise();
        },
        get_process_object : function() {
            var self = this,
                def = $.Deferred();
            if(this.process_id)
                return def.resolve().promise();

            this.process_dataset = new openerp.web.DataSetStatic(this, "process.process", this.session.context);
            this.process_dataset
            .call("search_by_model", [self.process_model,self.session.context])
            .done(function(res) {
                if (!res.length) {
                    self.process_model = false;
                    self.get_process_object().done(def.resolve);
                }
                else {
                    def.resolve(res);
                }
            })
            .fail(def.reject);
            return def.promise();
        },
        render_process_view : function() {
            this.$element.html(QWeb.render("ProcessView", this));
            var self = this;
            this.$element.find('#edit_process').click(function() {
                self.edit_process_view();
            });
            var $parent = this.widget_parent.$element;
            $parent.find('#change_process').click(function() {
                self.process_selection = false,
                self.process_id = $parent.find('#select_process').val(),
                self.process_title = $.trim($parent.find('#select_process option:selected').text());
                self.initialize_process_view();
            });

            this.$element.find(".toggle_fields").click(function() {
                $(this).children().toggle();
                self.$element.find('.process_fields').toggle();
            });

            this.$element.find(".process_subflow").click(function() {
                self.process_id = this.id;
                self.initialize_process_view();
            });
        },
        draw_process_graph : function(res) {
            var self = this,
                process_graph = new Graph();
            var process_renderer = function(r, n) {
                var process_node,
                    process_node_text,
                    process_node_desc,
                    process_set;

                var node_button,
                    node_menu,
                    img_src;

                var bg = "node",
                    clip_rect = "".concat(n.node.x,",",n.node.y,",150,100");

                //Image part
                bg = n.node.kind == "subflow" ? "node-subflow" : "node";
                bg = n.node.gray ? bg + "-gray" : bg;
                img_src = '/web_process/static/src/img/'+ bg + '.png';

                r['image'](img_src, n.node.x, n.node.y,150, 100)
                    .attr({"clip-rect": clip_rect})
                    .mousedown(function() {
                        return false;
                });
                //Node
                process_node = r['rect'](n.node.x, n.node.y, 150, 100).attr({stroke: "none"});
                // Node text
                process_node_text =  r.text(n.node.x, n.node.y, (n.node.name))
                    .attr({"fill": "#fff", "font-weight": "bold", "cursor": "pointer"});
                process_node_text.translate((process_node.getBBox().width/ 2) + 5, 10)
                if(n.node.subflow) {
                    process_node_text.click(function() {
                        self.process_id = n.node.subflow[0];
                        self.subflow_model = n.node.model;
                        self.subflow_name = n.node.name;
                        self.initialize_process_view();
                    });
                }
                //Node Description
                new_notes = n.node.notes;
                if(n.node.notes.length > 25) {
                    var new_notes= temp_str = '';
                    var from = to = 0;
                    while (1) {
                        from = 25;
                        temp_str = n.node.notes.substr(to ,25);
                        if (temp_str.lastIndexOf(" ") < 25 && temp_str.length >= 25) {
                            from  =  temp_str.lastIndexOf(" ");
                        }
                        new_notes += "\n" + n.node.notes.substr(to , from);
                        if(new_notes.length > n.node.notes.length) break;
                        to += from;
                    }
                }
                process_node_desc = r.text(n.node.x+85, n.node.y+50, (new_notes));
                r['image']('/web/static/src/img/icons/gtk-info.png', n.node.x+20, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": "Help"})
                    .click(function() {
                        window.open(n.node.url || "http://doc.openerp.com/v6.0/index.php?model=" + n.node.model);
                    });

                if(n.node.menu) {
                    r['image']('/web/static/src/img/icons/gtk-jump-to.png', n.node.x+115, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": n.node.menu.name})
                    .click(function() {
                        self.jump_to_view(n.node.res_model, n.node.menu.id);
                    });
                }

                process_set = r.set().push(process_node);
                process_set.mousedown(function() {
                    return false;
                });
                return process_set;
            };

            _.each(res['nodes'],function(node, node_id) {
                node['res_model'] = self.model,
                node['res_id'] = false,
                node['id'] = node_id;
                process_graph.addNode(node['name'], {node: node,render: process_renderer});
            });

            _.each(res['transitions'], function(transitions) {
                var src = res['nodes'][transitions['source']];
                var dst = res['nodes'][transitions['target']];
                // make active
                transitions['active'] = src.active && !dst.gray;
                process_graph.addEdge(src['name'], dst['name'], {directed : true});
            });
            var width = $(document).width();
            var height = $(document).height();
            var layouter = new Graph.Layout.Ordered(process_graph);
            var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, width, height);
        },
        jump_to_view: function(model, id) {
            var self = this;
            var dataset = new openerp.web.DataSetStatic(this, 'ir.values', this.session.context);
            dataset.call('get',
                ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
                function(res) {
                    self.$element.empty();
                    var action = res[0][res[0].length - 1];
                    self.rpc("/web/action/load", {
                        action_id: action.id,
                        context: dataset.context
                        }, function(result) {
                            var action_manager = new openerp.web.ActionManager(self);
                            action_manager.appendTo(self.widget_parent.$element);
                            action_manager.do_action(result.result);
                        });
                });
        },
        edit_process_view: function() {
            var self = this;
            var action_manager = new openerp.web.ActionManager(this);
            var dialog = new openerp.web.Dialog(this, {
                width: 800,
                buttons : [
                    {text: _t("Cancel"), click: function() { $(this).dialog('destroy'); }},
                    {text: _t("Save"), click: function() {
                        var form_view = action_manager.inner_viewmanager.views.form.controller;

                        form_view.do_save(function() {
                            self.initialize_process_view();
                        });
                        $(this).dialog('destroy');
                    }}
                ]
            }).open();

            action_manager.appendTo(dialog.$element);
            action_manager.do_action({
                res_model : 'process.process',
                res_id: self.process_id,
                views : [[false, 'form']],
                type : 'ir.actions.act_window',
                flags : {
                    search_view: false,
                    sidebar : false,
                    views_switcher : false,
                    action_buttons : false,
                    pager: false
                }
            });
        }
    });
};
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<commit_msg>[FIX] display each subflow only once in process view<commit_after>openerp.web_process = function (openerp) {
    var QWeb = openerp.web.qweb,
          _t = openerp.web._t;
    openerp.web.ViewManager.include({
        start: function() {
            this._super();
            var self = this;
            this.process_check();
            this.process_help = this.action ? this.action.help : 'Help: Not Defined';
            this.model = this.dataset.model;
            if(this.action) this.process_model = this.action.res_model;
            else this.process_model = this.model;
        },
        process_check: function() {
            var self = this,
            grandparent = this.widget_parent && this.widget_parent.widget_parent,
            view = this.views[this.views_src[0].view_type],
            $process_view = this.$element.find('.oe-process-view');
            if (!(grandparent instanceof openerp.web.WebClient) ||
                !(view.view_type === this.views_src[0].view_type
                    && view.view_id === this.views_src[0].view_id)) {
                        $process_view.hide();
                        return;
            }
            $process_view.click(function() {
                self.initialize_process_view();
            });
        },
        initialize_process_view: function() {
            var self = this;
            $.when(this.fields_get(), this.help(), this.get_process_object()).pipe(function(fields, help, process) {
                self.process_fields = fields;
                self.process_help = help;
                if(process && process.length) {
                    if(process.length > 1) {
                        self.process_selection = process;
                    } else {
                        self.process_id = process[0][0],
                        self.process_title = process[0][1];
                    }
                }
                return $.Deferred().resolve();
            }).pipe(function() {
                var def = $.Deferred();
                if(self.process_id) {
                    self.graph_get().done(function(res) {
                        self.process_notes = res.notes;
                        self.process_title = res.name;
                        self.process_subflows = _(res.nodes).chain()
                              .filter(function (node) { return node['subflow'] !== false; })
                              .uniq(false, function (node) { return node['subflow'][0]; }).value();
                        self.process_related = res.related;
                        def.resolve(res);
                    });
                } else def.resolve();
                return def.promise();
            }).done(function(res) {
                $.when(self.render_process_view()).done(function() {
                    if(res) self.draw_process_graph(res);
                });
            });
        },
        graph_get: function() {
            var self = this;
            var def = $.Deferred();
            this.process_id = parseInt(this.process_id, 10);

            this.process_dataset
            .call("graph_get",[this.process_id, this.model || this.dataset.model, false, [80,80,150,100]])
            .done(function(res) {
                self.process_dataset
                    .call("search_by_model",[self.model || self.dataset.model,self.session.context])
                    .done(
                    function(r) {
                        res['related'] = r;
                        def.resolve(res);
                    });
            });
            return def.promise();
        },
        fields_get : function() {
            var self = this,
                def = $.Deferred(),
                dataset = new openerp.web.DataSetStatic(this, this.model || this.dataset.model, this.session.context);
            dataset
                .call('fields_get',[])
                .done(function(fields) {
                    def.resolve(fields);
                }).fail(def.reject);
            return def.promise();
        },
        help : function() {
            var self = this,
                def = $.Deferred();
            if(!this.subflow_model) {
                def.resolve(this.action ? (this.action.help!=false ? this.action.help : 'Help: Not Defined') : 'Help: Not Defined');
            } else {
                 var dataset = new openerp.web.DataSetSearch(this, "ir.actions.act_window", this.session.context, []);
                 dataset
                    .read_slice(['help'],
                    {
                        domain: [
                            ['res_model', '=', this.subflow_model],
                            ['name', 'ilike', this.subflow_name]
                        ]
                    }
                    ).done(function(res) {
                        def.resolve(res.help || 'Help: Not Defined');
                    });
            }
            return def.promise();
        },
        get_process_object : function() {
            var self = this,
                def = $.Deferred();
            if(this.process_id)
                return def.resolve().promise();

            this.process_dataset = new openerp.web.DataSetStatic(this, "process.process", this.session.context);
            this.process_dataset
            .call("search_by_model", [self.process_model,self.session.context])
            .done(function(res) {
                if (!res.length) {
                    self.process_model = false;
                    self.get_process_object().done(def.resolve);
                }
                else {
                    def.resolve(res);
                }
            })
            .fail(def.reject);
            return def.promise();
        },
        render_process_view : function() {
            this.$element.html(QWeb.render("ProcessView", this));
            var self = this;
            this.$element.find('#edit_process').click(function() {
                self.edit_process_view();
            });
            var $parent = this.widget_parent.$element;
            $parent.find('#change_process').click(function() {
                self.process_selection = false,
                self.process_id = $parent.find('#select_process').val(),
                self.process_title = $.trim($parent.find('#select_process option:selected').text());
                self.initialize_process_view();
            });

            this.$element.find(".toggle_fields").click(function() {
                $(this).children().toggle();
                self.$element.find('.process_fields').toggle();
            });

            this.$element.find(".process_subflow").click(function() {
                self.process_id = this.id;
                self.initialize_process_view();
            });
        },
        draw_process_graph : function(res) {
            var self = this,
                process_graph = new Graph();
            var process_renderer = function(r, n) {
                var process_node,
                    process_node_text,
                    process_node_desc,
                    process_set;

                var node_button,
                    node_menu,
                    img_src;

                var bg = "node",
                    clip_rect = "".concat(n.node.x,",",n.node.y,",150,100");

                //Image part
                bg = n.node.kind == "subflow" ? "node-subflow" : "node";
                bg = n.node.gray ? bg + "-gray" : bg;
                img_src = '/web_process/static/src/img/'+ bg + '.png';

                r['image'](img_src, n.node.x, n.node.y,150, 100)
                    .attr({"clip-rect": clip_rect})
                    .mousedown(function() {
                        return false;
                });
                //Node
                process_node = r['rect'](n.node.x, n.node.y, 150, 100).attr({stroke: "none"});
                // Node text
                process_node_text =  r.text(n.node.x, n.node.y, (n.node.name))
                    .attr({"fill": "#fff", "font-weight": "bold", "cursor": "pointer"});
                process_node_text.translate((process_node.getBBox().width/ 2) + 5, 10)
                if(n.node.subflow) {
                    process_node_text.click(function() {
                        self.process_id = n.node.subflow[0];
                        self.subflow_model = n.node.model;
                        self.subflow_name = n.node.name;
                        self.initialize_process_view();
                    });
                }
                //Node Description
                new_notes = n.node.notes;
                if(n.node.notes.length > 25) {
                    var new_notes= temp_str = '';
                    var from = to = 0;
                    while (1) {
                        from = 25;
                        temp_str = n.node.notes.substr(to ,25);
                        if (temp_str.lastIndexOf(" ") < 25 && temp_str.length >= 25) {
                            from  =  temp_str.lastIndexOf(" ");
                        }
                        new_notes += "\n" + n.node.notes.substr(to , from);
                        if(new_notes.length > n.node.notes.length) break;
                        to += from;
                    }
                }
                process_node_desc = r.text(n.node.x+85, n.node.y+50, (new_notes));
                r['image']('/web/static/src/img/icons/gtk-info.png', n.node.x+20, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": "Help"})
                    .click(function() {
                        window.open(n.node.url || "http://doc.openerp.com/v6.0/index.php?model=" + n.node.model);
                    });

                if(n.node.menu) {
                    r['image']('/web/static/src/img/icons/gtk-jump-to.png', n.node.x+115, n.node.y+70, 16, 16)
                    .attr({"cursor": "pointer", "title": n.node.menu.name})
                    .click(function() {
                        self.jump_to_view(n.node.res_model, n.node.menu.id);
                    });
                }

                process_set = r.set().push(process_node);
                process_set.mousedown(function() {
                    return false;
                });
                return process_set;
            };

            _.each(res['nodes'],function(node, node_id) {
                node['res_model'] = self.model,
                node['res_id'] = false,
                node['id'] = node_id;
                process_graph.addNode(node['name'], {node: node,render: process_renderer});
            });

            _.each(res['transitions'], function(transitions) {
                var src = res['nodes'][transitions['source']];
                var dst = res['nodes'][transitions['target']];
                // make active
                transitions['active'] = src.active && !dst.gray;
                process_graph.addEdge(src['name'], dst['name'], {directed : true});
            });
            var width = $(document).width();
            var height = $(document).height();
            var layouter = new Graph.Layout.Ordered(process_graph);
            var render_process_graph = new Graph.Renderer.Raphael('process_canvas', process_graph, width, height);
        },
        jump_to_view: function(model, id) {
            var self = this;
            var dataset = new openerp.web.DataSetStatic(this, 'ir.values', this.session.context);
            dataset.call('get',
                ['action', 'tree_but_open',[['ir.ui.menu', id]], dataset.context],
                function(res) {
                    self.$element.empty();
                    var action = res[0][res[0].length - 1];
                    self.rpc("/web/action/load", {
                        action_id: action.id,
                        context: dataset.context
                        }, function(result) {
                            var action_manager = new openerp.web.ActionManager(self);
                            action_manager.appendTo(self.widget_parent.$element);
                            action_manager.do_action(result.result);
                        });
                });
        },
        edit_process_view: function() {
            var self = this;
            var action_manager = new openerp.web.ActionManager(this);
            var dialog = new openerp.web.Dialog(this, {
                width: 800,
                buttons : [
                    {text: _t("Cancel"), click: function() { $(this).dialog('destroy'); }},
                    {text: _t("Save"), click: function() {
                        var form_view = action_manager.inner_viewmanager.views.form.controller;

                        form_view.do_save(function() {
                            self.initialize_process_view();
                        });
                        $(this).dialog('destroy');
                    }}
                ]
            }).open();

            action_manager.appendTo(dialog.$element);
            action_manager.do_action({
                res_model : 'process.process',
                res_id: self.process_id,
                views : [[false, 'form']],
                type : 'ir.actions.act_window',
                flags : {
                    search_view: false,
                    sidebar : false,
                    views_switcher : false,
                    action_buttons : false,
                    pager: false
                }
            });
        }
    });
};
// vim:et fdc=0 fdl=0 foldnestmax=3 fdm=syntax:
<|endoftext|>


<commit_before>/**
 *  paygrade Methods
 */
Meteor.methods({

    /* paygrade
     */

    "paygrade/create": function(paygrade){
        if (!this.userId) {
            throw new Meteor.Error(401, "Unauthorized");
        }
        let userId = Meteor.userId();

        try {
            check(paygrade, Core.Schemas.PayGrade);
        } catch (e) {
            console.log(e);
            throw new Meteor.Error(401, "There's invalid data in the paygrades. Please correct and retry");
        }
        // if a bu object was provided and valid schema
        //if (Core.hasOrderAccess(userId, order.salesLocationId)) {
        //    // must have orders/manage permissions
        this.unblock();

        let pgId = PayGrades.insert(paygrade);
        return {_id: pgId};
    },
    "paygrade/delete": function(id){
        if(!this.userId){
            throw new Meteor.Error(401, "Unauthorized");
        }
        // check if user has permission to delete
        PayGrades.remove({_id: id});
        return true;
    },
    "paygrade/update": function(id, details){
        if(!this.userId){
            throw new Meteor.Error(401, "Unauthorized");
        }
        //update can only be done by authorized user. so check permission
        check(id, String);
        const selector = {
            _id: id
        };
        const result = PayGrades.update(selector, {$set: details} );

        //--We need to update employee paytypes in case new paytypes were added to the paygrade
        let paygradePaytypes = details.payTypes
        let employeesWithPayGrade = Meteor.users.find({'employeeProfile.employment.paygrade': id}).fetch()
        let numberOfEmployeesWithPayGrade = employeesWithPayGrade.length
        //console.log(`numberOfEmployeesWithPayGrade: ${numberOfEmployeesWithPayGrade}`)

        employeesWithPayGrade.forEach(anEmployee => {
            console.log(`employee id: ${anEmployee._id}`)
            let employeePaytypes = anEmployee.employeeProfile.employment.paytypes
            if(employeePaytypes) {
                let newPayTypesToInsert = []

                paygradePaytypes.forEach(function(aPayGradePayType) {
                    let employeePayTypeWithVal = null
                    let numOfEmployeePayTypes = employeePaytypes.length
                    for(let i = 0; i < numOfEmployeePayTypes; i++) {
                        let anEmployeePayType = employeePaytypes[i]
                        if(anEmployeePayType.paytype === aPayGradePayType.paytype) {
                            employeePayTypeWithVal = anEmployeePayType
                            break;
                        }
                    }
                    if(!employeePayTypeWithVal) {
                        delete aPayGradePayType.displayInPayslip
                        newPayTypesToInsert.push(aPayGradePayType);
                    } else {
                        newPayTypesToInsert.push(employeePayTypeWithVal);
                    }
                })
                console.log(`newPayTypesToInsert: ${newPayTypesToInsert.length}`)
                if(newPayTypesToInsert.length > 0) {
                    result = Meteor.users.update(anEmployee._id,
                        { $set: { 'employeeProfile.employment.paytypes': newPayTypesToInsert }}
                    );
                }
            } else {
                result = Meteor.users.update(anEmployee._id,
                    { $set: { 'employeeProfile.employment.paytypes': paygradePaytypes }}
                );
            }
        })
        return result;
    }
});

<commit_msg>fix oversight<commit_after>/**
 *  paygrade Methods
 */
Meteor.methods({

    /* paygrade
     */

    "paygrade/create": function(paygrade){
        if (!this.userId) {
            throw new Meteor.Error(401, "Unauthorized");
        }
        let userId = Meteor.userId();

        try {
            check(paygrade, Core.Schemas.PayGrade);
        } catch (e) {
            console.log(e);
            throw new Meteor.Error(401, "There's invalid data in the paygrades. Please correct and retry");
        }
        // if a bu object was provided and valid schema
        //if (Core.hasOrderAccess(userId, order.salesLocationId)) {
        //    // must have orders/manage permissions
        this.unblock();

        let pgId = PayGrades.insert(paygrade);
        return {_id: pgId};
    },
    "paygrade/delete": function(id){
        if(!this.userId){
            throw new Meteor.Error(401, "Unauthorized");
        }
        // check if user has permission to delete
        PayGrades.remove({_id: id});
        return true;
    },
    "paygrade/update": function(id, details){
        if(!this.userId){
            throw new Meteor.Error(401, "Unauthorized");
        }
        //update can only be done by authorized user. so check permission
        check(id, String);
        const selector = {
            _id: id
        };
        let result = PayGrades.update(selector, {$set: details} );

        //--We need to update employee paytypes in case new paytypes were added to the paygrade
        let paygradePaytypes = details.payTypes
        let employeesWithPayGrade = Meteor.users.find({'employeeProfile.employment.paygrade': id}).fetch()
        let numberOfEmployeesWithPayGrade = employeesWithPayGrade.length
        //console.log(`numberOfEmployeesWithPayGrade: ${numberOfEmployeesWithPayGrade}`)

        employeesWithPayGrade.forEach(anEmployee => {
            console.log(`employee id: ${anEmployee._id}`)
            let employeePaytypes = anEmployee.employeeProfile.employment.paytypes
            if(employeePaytypes) {
                let newPayTypesToInsert = []

                paygradePaytypes.forEach(function(aPayGradePayType) {
                    let employeePayTypeWithVal = null
                    let numOfEmployeePayTypes = employeePaytypes.length
                    for(let i = 0; i < numOfEmployeePayTypes; i++) {
                        let anEmployeePayType = employeePaytypes[i]
                        if(anEmployeePayType.paytype === aPayGradePayType.paytype) {
                            employeePayTypeWithVal = anEmployeePayType
                            break;
                        }
                    }
                    if(!employeePayTypeWithVal) {
                        delete aPayGradePayType.displayInPayslip
                        newPayTypesToInsert.push(aPayGradePayType);
                    } else {
                        newPayTypesToInsert.push(employeePayTypeWithVal);
                    }
                })
                console.log(`newPayTypesToInsert: ${newPayTypesToInsert.length}`)
                if(newPayTypesToInsert.length > 0) {
                    result = Meteor.users.update(anEmployee._id,
                        { $set: { 'employeeProfile.employment.paytypes': newPayTypesToInsert }}
                    );
                }
            } else {
                result = Meteor.users.update(anEmployee._id,
                    { $set: { 'employeeProfile.employment.paytypes': paygradePaytypes }}
                );
            }
        })
        return result;
    }
});

<|endoftext|>


<commit_before>'use strict';

var TestHelper = require('./test_helper')
var User = require('../models/user')
var assert = require('chai').assert;

describe("User",function() {
    beforeEach(function() {
        TestHelper.dropDatabase()
    });

    var user = new User({ name: "prueba",
                        email: "example@example.com" })

    it("#initialize",function(){
        assert.equal(user.name,"prueba")
        assert.equal(user.email,"example@example.com")
    })

    it("#save",function(done){
        user.save(done)
    })

    it("User.find",function(done){
        user.save(function(){
            User.findOne({"email":"example@example.com"}, function(err,doc){
                assert.equal(doc.name,"prueba");
                assert.equal(doc.email,"example@example.com");
                done();
            })
        })
    })
})
<commit_msg>Improvements to test_user.js<commit_after>'use strict';

var TestHelper = require('./test_helper')
var User = require('../models/user')
var assert = require('chai').assert;

describe("User",function() {
    beforeEach(function() {
        TestHelper.dropDatabase()
    });

    var user = new User({ name: "prueba",
                        email: "example@example.com" })

    it("#initialize",function(){
        assert.equal(user.name,"prueba")
        assert.equal(user.email,"example@example.com")
    })

    it("#save",function(done){
        user.save(function(err,doc){
            assert.equal(doc.name,"prueba");
            assert.equal(doc.email,"example@example.com");
            assert.equal(doc._id._bsontype,"ObjectID");
            done();
        })
    })

    it("User.find",function(done){
        user.save(function(){
            User.findOne({"email":"example@example.com"}, function(err,doc){
                assert.equal(doc.name,"prueba");
                assert.equal(doc.email,"example@example.com");
                done();
            })
        })
    })
})
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Uni FM96.7 Player Updater
// @name:zh-TW   FM96.7 環宇廣播電台線上收聽播放器調整
// @namespace    http://www.twsiyuan.com/
// @version      0.21
// @description:zh-TW  產生下載連結，修改 Flash Player 為 HTML5 內鍵撥放器
// @author       Siyuan
// @match        http://www.uni967.com/newweb/AOD2_no.php*
// @grant        none
// @require      http://code.jquery.com/jquery-latest.js
// ==/UserScript==

$(document).ready(function() {
    var embed = $("embed");

    // 音源位置
    var audioUrl = getUrlParameterFromString(embed.attr("flashvars"), "son");

    // 節目資料網頁位置
    var id = getUrlParameterFromString(window.location.search.substring(1), "ID");
    var dataUrl = "http://www.uni967.com/newweb/index.php?menu=2&page=2_1&ID=" + id;

    $.get(dataUrl, function(data) {
        // 分析資料網頁，抓取節目名稱
        var title = $(data).find("span.news_title_blue").text();
        var parent = embed.parent();

        // 產生下載連結
        var download = $('Download (' + title + ')');

        // 產生音源播放 (HTML5 標準)
        var paramSaveName = "ui967Volume";
        var volumeChanged = "if(typeof(Storage) !== 'undefined'){localStorage.setItem('" + paramSaveName + "', this.volume);}";
        var loadStart = "if(typeof(Storage) !== 'undefined'){this.volume=localStorage.getItem('" + paramSaveName + "');}";

        var player = $('<audio controls autoplay src="' + audioUrl + '" onvolumechange="' + volumeChanged + '" onloadstart="' + loadStart + '" style="width:100%;">Your browser does not support the audio tag.</audio>');

        parent.append(player);
        parent.append(download);

        embed.remove();
    });
});

var getUrlParameterFromString = function getUrlParameter(sUrl, sParam) {
    var sPageURL = decodeURIComponent(sUrl);
    var sURLVariables = sPageURL.split('&');

    for (var i = 0; i < sURLVariables.length; i++) {
        var sParameterName = sURLVariables[i].split('=');
        if (sParameterName[0] === sParam && sParameterName.length >= 2) {
            return sParameterName[1] === undefined ? '' : sParameterName[1];
        }
    }
};
<commit_msg>節目頁面表格直接產生下載連結，改用 Regex 分析資料<commit_after>// ==UserScript==
// @name         Uni FM96.7 Player Updater
// @name:zh-TW   FM96.7 環宇廣播電台線上收聽播放器調整
// @namespace    http://www.twsiyuan.com/
// @version      0.3
// @description:zh-TW  產生下載連結，修改 Flash Player 為 HTML5 內鍵撥放器
// @author       Siyuan
// @match        http://www.uni967.com/newweb/AOD2_no.php*
// @match        http://www.uni967.com/newweb/index.php*
// @grant        none
// @require      http://code.jquery.com/jquery-latest.js
// @description 產生下載連結，修改 Flash Player 為 HTML5 內鍵撥放器
// ==/UserScript==

$(document).ready(function() {
    if (window.location.pathname.toString().startsWith('/newweb/AOD2_no')) {
        doPlayer();
    } else {
        doTable();
    }
});

var analysisCallback = function(embed, url, callback) {
    if (!embed) {
        return;
    }

    var flashvars = embed.attr("flashvars");
    if (!flashvars) {
         return;
    }

    // 音源位置
    var vars = /son=([^&]+)/.exec(flashvars);
    if (!vars){
        return;
    }

    var audioUrl = vars[1];

    // 節目資料網頁位置
    var ids = /ID=([0-9]+)$/.exec(url);
    if (!ids){
        return;
    }

    var id = ids[1];
    var dataUrl = "http://www.uni967.com/newweb/index.php?menu=2&page=2_1&ID=" + id;

    $.get(dataUrl, function(data) {
        // 分析資料網頁，抓取節目名稱
        var title = $(data).find("span.news_title_blue").text();

        callback(audioUrl, title);
    });
};

var doPlayer = function() {
    var embed = $("embed");
    analysisCallback(embed, window.location.href, function(audioUrl, title) {
         // 產生下載連結
        var download = $('Download (' + title + ')');

        // 產生音源播放 (HTML5 標準)
        var paramSaveName = "ui967Volume";
        var volumeChanged = "if(typeof(Storage) !== 'undefined'){localStorage.setItem('" + paramSaveName + "', this.volume);}";
        var loadStart = "if(typeof(Storage) !== 'undefined'){this.volume=localStorage.getItem('" + paramSaveName + "');}";

        var player = $('<audio controls autoplay src="' + audioUrl + '" onvolumechange="' + volumeChanged + '" onloadstart="' + loadStart + '" style="width:100%;">Your browser does not support the audio tag.</audio>');
        var parent = embed.parent();

        parent.append(player);
        parent.append(download);

        embed.remove();
    });
};

var doTable = function() {
    var links = $("a");
    links.each(function(){
        var link = $(this);
        var onclick = link.attr('onclick');
        if (onclick) {
            var arr = /window.open\('([^']+)'/.exec(onclick);
            if (arr) {
                var uri = arr[1];
                var dataUrl = "http://www.uni967.com/newweb/" + uri;

                $.get(dataUrl, function(data) {
                    var embed = /<embed(.+)<\/embed>/.exec(data);
                    if (embed) {
                        analysisCallback($(embed[0]), dataUrl, function(audioUrl, title) {
                            var parent = link.parent();
                            var download = $('下載');

                            parent.append($('
'));
                            parent.append(download);
                        });
                    }
                });
            }
        }
    });
};
<|endoftext|>


<commit_before>// ========== Adding Table code ============

afqb.table = {
	fieldHeight: 30,
   	rowPadding: 1,
   	fieldWidth: 140
};

afqb.table.previousSort = {
	key: null,
	order: "ascending"
};

afqb.table.format = d3.time.format("%m/%d/%Y");
//var dateFn = function(date) { return format.parse(d.created_at) };

afqb.table.subData = [];
afqb.table.subGroups = {};
afqb.table.splitGroups = false;

afqb.table.ramp = null;
afqb.table.headerGrp;
afqb.table.rowsGrp;

afqb.queues.subjectQ = d3_queue.queue();
afqb.queues.subjectQ.defer(d3.json, "data/subjects.json");
afqb.queues.subjectQ.await(buildTable);

function buildTable(error, data) {
	data.forEach(function (d) {
        if (typeof d.subjectID === 'number'){
          d.subjectID = "s" + d.subjectID.toString();}
		afqb.table.subData.push(d);
	});

	afqb.table.ramp = null;

	var tableSvg = d3.select("#table").append("svg")
		.attr("width", d3.keys(afqb.table.subData[0]).length * afqb.table.fieldWidth)
		.attr("height", (afqb.table.subData.length + 1) * (afqb.table.fieldHeight + afqb.table.rowPadding));

	afqb.table.headerGrp = tableSvg.append("g").attr("class", "headerGrp");
	afqb.table.rowsGrp = tableSvg.append("g").attr("class","rowsGrp");

	var tableGuiConfigObj = function () {
		this.groupCount = 2;
	};

	var tableGui = new dat.GUI({
		autoplace: false,
		width: 350,
		scrollable: false
	});

	afqb.controls.tableControlBox = new tableGuiConfigObj();

	var tableGuiContainer = $('.tableGUI').append($(tableGui.domElement));

	var groupCountController = tableGui.add(afqb.controls.tableControlBox, 'groupCount')
		.min(2).step(1)
		.name('Number of Groups')
		.onChange(function () {
			return refreshTable(sortOn);
		});
	tableGui.close()

	groupCountController.onChange(function () {
		refreshTable(sortOn);
	});

	tableGui.close();

	var sortOn = null;
	refreshTable(sortOn);
}

function refreshTable(sortOn){

    // create the table header
    var header = afqb.table.headerGrp.selectAll("g")
        .data(d3.keys(afqb.table.subData[0]))
        .enter().append("g")
        .attr("class", "t_header")
        .attr("transform", function (d, i){
            return "translate(" + i * afqb.table.fieldWidth + ",0)";
        })
        .on("mouseover", function (d,i) {
            d3.select(this).style("cursor", "n-resize");
        })
		// this is where the magic happens...(d) is the column being sorted
        .on("click", function (d) { return refreshTable(d); });

    header.append("rect")
        .attr("width", afqb.table.fieldWidth-1)
        .attr("height", afqb.table.fieldHeight);

    header.append("text")
        .attr("x", afqb.table.fieldWidth / 2)
        .attr("y", afqb.table.fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    // fill the table
    // select rows
    var rows = afqb.table.rowsGrp.selectAll("g.row").data(afqb.table.subData,
        function(d){ return d.subjectID; });

    // create rows
    var rowsEnter = rows.enter().append("svg:g")
        .attr("class","row")
        .attr("id", function(d){ return d.subjectID; })
        .attr("transform", function (d, i){
            return "translate(0," + (i+1) * (afqb.table.fieldHeight+afqb.table.rowPadding) + ")";
        })
        //.on('click', rowSelect )
        .on('mouseover', tableMouseDown )
        .on('mousedown', rowSelect );
    // select cells
    var cells = rows.selectAll("g.cell")
		.data(function(d){return d3.values(d);});

    // create cells
    var cellsEnter = cells.enter().append("svg:g")
        .attr("class", "cell")
				.style("opacity",0.3)
        .attr("transform", function (d, i){
            return "translate(" + i * afqb.table.fieldWidth + ",0)";
        });

    cellsEnter.append("rect")
        .attr("width", afqb.table.fieldWidth-1)
        .attr("height", afqb.table.fieldHeight);

    cellsEnter.append("text")
        .attr("x", afqb.table.fieldWidth / 2)
        .attr("y", afqb.table.fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    // Update if not in initialisation
    if (sortOn !== null) {
        // Update row order
        if(sortOn === afqb.table.previousSort.key){
			if (afqb.table.previousSort.order === "ascending") {
				rows.sort(function(a,b){
					return descendingWithNull(a[sortOn], b[sortOn]);
				});
				afqb.table.previousSort.order = "descending";
			} else {
				rows.sort(function(a,b){
					return ascendingWithNull(a[sortOn], b[sortOn]);
				});
				afqb.table.previousSort.order = "ascending";
			}
        } else {
			rows.sort(function(a,b){
				return ascendingWithNull(a[sortOn], b[sortOn]);
			});
            afqb.table.subData.sort(function(a,b){
				return ascendingWithNull(a[sortOn], b[sortOn]);
			});
			afqb.table.previousSort.key = sortOn;
			afqb.table.previousSort.order = "ascending";

			// Get unique, non-null values from the column `sortOn`
			function uniqueNotNull(value, index, self) {
				return (self.indexOf(value) === index) && (value !== null);
			}

			var uniques = afqb.table.subData
				.map(function(element) {
					return element[sortOn];
				})
			.filter(uniqueNotNull);

			// usrGroups is the user requested number of groups
			// numGroups may be smaller if there are not enough unique values
			var usrGroups = afqb.controls.tableControlBox.groupCount;
			var numGroups = Math.min(usrGroups, uniques.length);

			// Create groupScale to map between the unique
			// values and the discrete group indices.
			var groupScale;
			// TODO: Use the datatype json instead of
			// just testing the first element of uniques
			if (typeof uniques[0] === 'number') {
				groupScale = d3.scale.quantile()
					.range(d3.range(numGroups));
			} else {
				var rangeOrdinal = Array(uniques.length);
				for (i = 0; i < numGroups; i++) {
					rangeOrdinal.fill(i,
							i * uniques.length / numGroups,
							(i + 1) * uniques.length / numGroups);
				}
				groupScale = d3.scale.ordinal()
					.range(rangeOrdinal);
			}
			groupScale.domain(uniques);

			// Assign group index to each element of afqb.table.subData
			afqb.table.subData.forEach(function(element) {
				if (element[sortOn] === null) {
					element["group"] = null;
					afqb.table.subGroups[element.subjectID] = null;
				} else {
					element["group"] = groupScale(element[sortOn]);
					afqb.table.subGroups[element.subjectID] = groupScale(element[sortOn]);
				}
			});

			// Prepare to split on group index
			afqb.table.splitGroups = d3.nest()
				.key(function (d) { return d["group"]; })
				.entries(afqb.table.subData);

			// Create color ramp for subject groups
			afqb.table.ramp = d3.scale.linear()
				.domain([0, numGroups-1]).range(["red", "blue"]);

			function idColor(element) {
				d3.selectAll('#' + element["subjectID"])
					.selectAll('.line')
					.style("stroke",
							element["group"] === null ? "black" : afqb.table.ramp(element["group"]));

				d3.selectAll('#' + element["subjectID"])
					.selectAll('.cell').select('text')
					.style("fill",
							element["group"] === null ? "black" : afqb.table.ramp(element["group"]));
			}

			afqb.table.subData.forEach(idColor); // color lines

			// call update -> noticed there is a delay here.
			// update plots may be the slow down
			d3.csv("data/nodes.csv", updatePlots);
		}

        rows//.transition() // sort row position
           //.duration(500)
           .attr("transform", function (d, i) {
               return "translate(0," + (i + 1) * (afqb.table.fieldHeight + 1) + ")";
           });
    }
}

function ascendingWithNull(a, b) {
	// d3.ascending ignores null and undefined values
	// Return the same as d3.ascending but keep all null and
	// undefined values at the bottom of the list
	return b == null ? -1 : a == null ? 1 : d3.ascending(a, b);
}

function descendingWithNull(a, b) {
	// d3.descending ignores null and undefined values
	// Return the same as d3.descending but keep all null and
	// undefined values at the bottom of the list
	return b == null ? -1 : a == null ? 1 : d3.descending(a, b);
}

// onclick function to toggle on and off rows
function rowSelect() {
    if($('g',this).css("opacity") == 0.3) {
		//uses the opacity of the row for selection and deselection
        d3.selectAll('#' + this.id)
			.selectAll('g')
            .style("opacity", 1);

		d3.selectAll('#' + this.id)
			.selectAll('path')
            .style("opacity", 1)
            .style("stroke-width", "2.1px");
    } else {
		d3.selectAll('#' + this.id)
			.selectAll('g')
			.style("opacity", 0.3);

        d3.selectAll('#' + this.id)
			.selectAll('path')
            .style("opacity", afqb.controls.plotsControlBox.lineOpacity)
            .style("stroke-width", "1.1px");
	}
}

afqb.mouse.isDown = false;   // Tracks status of mouse button

$(document).mousedown(function() {
		// When mouse goes down, set isDown to true
		afqb.mouse.isDown = true;
	})
    .mouseup(function() {
		// When mouse goes up, set isDown to false
        afqb.mouse.isDown = false;
    });

function tableMouseDown() {
	if(afqb.mouse.isDown) {
		if($('g',this).css("opacity") == 0.3) {
			//uses the opacity of the row for selection and deselection
			d3.selectAll('#' + this.id)
				.selectAll('g')
				.style("opacity", 1);

			d3.selectAll('#' + this.id)
				.selectAll('path')
				.style("opacity", 1)
				.style("stroke-width", "2.1px");
		} else {
			d3.selectAll('#' + this.id)
				.selectAll('g')
				.style("opacity", 0.3);

			d3.selectAll('#' + this.id)
				.selectAll('path')
				.style("opacity", afqb.controls.plotsControlBox.lineOpacity)
				.style("stroke-width", "1.1px");
		}
	}
}
<commit_msg>Update sortable-table.js to use new afqb structure.<commit_after>// ========== Adding Table code ============

afqb.table = {
	fieldHeight: 30,
   	rowPadding: 1,
   	fieldWidth: 140
};

afqb.table.previousSort = {
	key: null,
	order: "ascending"
};

afqb.table.format = d3.time.format("%m/%d/%Y");
//var dateFn = function(date) { return format.parse(d.created_at) };

afqb.table.subData = [];
afqb.table.subGroups = {};
afqb.table.splitGroups = false;

afqb.table.ramp = null;
afqb.table.headerGrp;
afqb.table.rowsGrp;

afqb.global.queues.subjectQ = d3_queue.queue();
afqb.global.queues.subjectQ.defer(d3.json, "data/subjects.json");
afqb.global.queues.subjectQ.await(afqb.table.buildTable);

function afqb.table.buildTable(error, data) {
	data.forEach(function (d) {
        if (typeof d.subjectID === 'number'){
          d.subjectID = "s" + d.subjectID.toString();}
		afqb.table.subData.push(d);
	});

	afqb.table.ramp = null;

	var tableSvg = d3.select("#table").append("svg")
		.attr("width", d3.keys(afqb.table.subData[0]).length * afqb.table.fieldWidth)
		.attr("height", "100%")
		.attr("display", "flex")
		.attr("flex-direction", "column");
		// .attr("height", (afqb.table.subData.length + 1) * (afqb.table.fieldHeight + afqb.table.rowPadding));

	afqb.table.headerGrp = tableSvg.append("g").attr("class", "headerGrp")
		.attr("flex", "0 1 auto");
	afqb.table.rowsGrp = tableSvg.append("g").attr("class","rowsGrp")
		.attr("flex", "1 1 auto");
		//.attr("height", afqb.table.subData.length * (afqb.table.fieldHeight + afqb.table.rowPadding));

	var tableGuiConfigObj = function () {
		this.groupCount = 2;
	};

	var tableGui = new dat.GUI({
		autoplace: false,
		width: 350,
		scrollable: false
	});

	afqb.global.controls.tableControlBox = new tableGuiConfigObj();

	var tableGuiContainer = $('.tableGUI').append($(tableGui.domElement));

	var groupCountController = tableGui.add(afqb.global.controls.tableControlBox, 'groupCount')
		.min(2).step(1)
		.name('Number of Groups')
		.onChange(function () {
			return afqb.table.refreshTable(sortOn);
		});
	tableGui.close()

	groupCountController.onChange(function () {
		afqb.table.refreshTable(sortOn);
	});

	tableGui.close();

	var sortOn = null;
	afqb.table.refreshTable(sortOn);
}

function afqb.table.refreshTable(sortOn){

    // create the table header
    var header = afqb.table.headerGrp.selectAll("g")
        .data(d3.keys(afqb.table.subData[0]))
        .enter().append("g")
        .attr("class", "t_header")
        .attr("transform", function (d, i){
            return "translate(" + i * afqb.table.fieldWidth + ",0)";
        })
        .on("mouseover", function (d,i) {
            d3.select(this).style("cursor", "n-resize");
        })
		// this is where the magic happens...(d) is the column being sorted
        .on("click", function (d) { return afqb.table.refreshTable(d); });

    header.append("rect")
        .attr("width", afqb.table.fieldWidth-1)
        .attr("height", afqb.table.fieldHeight);

    header.append("text")
        .attr("x", afqb.table.fieldWidth / 2)
        .attr("y", afqb.table.fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    // fill the table
    // select rows
    var rows = afqb.table.rowsGrp.selectAll("g.row").data(afqb.table.subData,
        function(d){ return d.subjectID; });

    // create rows
    var rowsEnter = rows.enter().append("svg:g")
        .attr("class","row")
        .attr("id", function(d){ return d.subjectID; })
        .attr("transform", function (d, i){
            return "translate(0," + (i+1) * (afqb.table.fieldHeight+afqb.table.rowPadding) + ")";
        })
        //.on('click', afqb.table.rowSelect )
        .on('mouseover', afqb.table.tableMouseDown )
        .on('mousedown', afqb.table.rowSelect );

    // select cells
    var cells = rows.selectAll("g.cell")
		.data(function(d){return d3.values(d);});

    // create cells
    var cellsEnter = cells.enter().append("svg:g")
        .attr("class", "cell")
				.style("opacity",0.3)
        .attr("transform", function (d, i){
            return "translate(" + i * afqb.table.fieldWidth + ",0)";
        });

    cellsEnter.append("rect")
        .attr("width", afqb.table.fieldWidth-1)
        .attr("height", afqb.table.fieldHeight);

    cellsEnter.append("text")
        .attr("x", afqb.table.fieldWidth / 2)
        .attr("y", afqb.table.fieldHeight / 2)
        .attr("dy", ".35em")
        .text(String);

    // Update if not in initialisation
    if (sortOn !== null) {
        // Update row order
        if(sortOn === afqb.table.previousSort.key){
			if (afqb.table.previousSort.order === "ascending") {
				rows.sort(function(a,b){
					return afqb.table.descendingWithNull(a[sortOn], b[sortOn]);
				});
				afqb.table.previousSort.order = "descending";
			} else {
				rows.sort(function(a,b){
					return afqb.table.ascendingWithNull(a[sortOn], b[sortOn]);
				});
				afqb.table.previousSort.order = "ascending";
			}
        } else {
			rows.sort(function(a,b){
				return afqb.table.ascendingWithNull(a[sortOn], b[sortOn]);
			});
            afqb.table.subData.sort(function(a,b){
				return afqb.table.ascendingWithNull(a[sortOn], b[sortOn]);
			});
			afqb.table.previousSort.key = sortOn;
			afqb.table.previousSort.order = "ascending";

			// Get unique, non-null values from the column `sortOn`
			function uniqueNotNull(value, index, self) {
				return (self.indexOf(value) === index) && (value !== null);
			}

			var uniques = afqb.table.subData
				.map(function(element) {
					return element[sortOn];
				})
			.filter(uniqueNotNull);

			// usrGroups is the user requested number of groups
			// numGroups may be smaller if there are not enough unique values
			var usrGroups = afqb.global.controls.tableControlBox.groupCount;
			var numGroups = Math.min(usrGroups, uniques.length);

			// Create groupScale to map between the unique
			// values and the discrete group indices.
			var groupScale;
			// TODO: Use the datatype json instead of
			// just testing the first element of uniques
			if (typeof uniques[0] === 'number') {
				groupScale = d3.scale.quantile()
					.range(d3.range(numGroups));
			} else {
				var rangeOrdinal = Array(uniques.length);
				for (i = 0; i < numGroups; i++) {
					rangeOrdinal.fill(i,
							i * uniques.length / numGroups,
							(i + 1) * uniques.length / numGroups);
				}
				groupScale = d3.scale.ordinal()
					.range(rangeOrdinal);
			}
			groupScale.domain(uniques);

			// Assign group index to each element of afqb.table.subData
			afqb.table.subData.forEach(function(element) {
				if (element[sortOn] === null) {
					element["group"] = null;
					afqb.table.subGroups[element.subjectID] = null;
				} else {
					element["group"] = groupScale(element[sortOn]);
					afqb.table.subGroups[element.subjectID] = groupScale(element[sortOn]);
				}
			});

			// Prepare to split on group index
			afqb.table.splitGroups = d3.nest()
				.key(function (d) { return d["group"]; })
				.entries(afqb.table.subData);

			// Create color ramp for subject groups
			afqb.table.ramp = d3.scale.linear()
				.domain([0, numGroups-1]).range(["red", "blue"]);

			function idColor(element) {
				d3.selectAll('#' + element["subjectID"])
					.selectAll('.line')
					.style("stroke",
							element["group"] === null ? "black" : afqb.table.ramp(element["group"]));

				d3.selectAll('#' + element["subjectID"])
					.selectAll('.cell').select('text')
					.style("fill",
							element["group"] === null ? "black" : afqb.table.ramp(element["group"]));
			}

			afqb.table.subData.forEach(idColor); // color lines

			// call update -> noticed there is a delay here.
			// update plots may be the slow down
			d3.csv("data/nodes.csv", afqb.plots.updatePlots);
		}

        rows//.transition() // sort row position
           //.duration(500)
           .attr("transform", function (d, i) {
               return "translate(0," + (i + 1) * (afqb.table.fieldHeight + 1) + ")";
           });
    }
}

function afqb.table.ascendingWithNull(a, b) {
	// d3.ascending ignores null and undefined values
	// Return the same as d3.ascending but keep all null and
	// undefined values at the bottom of the list
	return b == null ? -1 : a == null ? 1 : d3.ascending(a, b);
}

function afqb.table.descendingWithNull(a, b) {
	// d3.descending ignores null and undefined values
	// Return the same as d3.descending but keep all null and
	// undefined values at the bottom of the list
	return b == null ? -1 : a == null ? 1 : d3.descending(a, b);
}

// onclick function to toggle on and off rows
function afqb.table.rowSelect() {
    if($('g',this).css("opacity") == 0.3) {
		//uses the opacity of the row for selection and deselection
        d3.selectAll('#' + this.id)
			.selectAll('g')
            .style("opacity", 1);

		d3.selectAll('#' + this.id)
			.selectAll('path')
            .style("opacity", 1)
            .style("stroke-width", "2.1px");
    } else {
		d3.selectAll('#' + this.id)
			.selectAll('g')
			.style("opacity", 0.3);

        d3.selectAll('#' + this.id)
			.selectAll('path')
            .style("opacity", afqb.global.controls.plotsControlBox.lineOpacity)
            .style("stroke-width", "1.1px");
	}
}

afqb.global.mouse.isDown = false;   // Tracks status of mouse button

$(document).mousedown(function() {
		// When mouse goes down, set isDown to true
		afqb.global.mouse.isDown = true;
	})
    .mouseup(function() {
		// When mouse goes up, set isDown to false
        afqb.global.mouse.isDown = false;
    });

function afqb.table.tableMouseDown() {
	if(afqb.global.mouse.isDown) {
		if($('g',this).css("opacity") == 0.3) {
			//uses the opacity of the row for selection and deselection
			d3.selectAll('#' + this.id)
				.selectAll('g')
				.style("opacity", 1);

			d3.selectAll('#' + this.id)
				.selectAll('path')
				.style("opacity", 1)
				.style("stroke-width", "2.1px");
		} else {
			d3.selectAll('#' + this.id)
				.selectAll('g')
				.style("opacity", 0.3);

			d3.selectAll('#' + this.id)
				.selectAll('path')
				.style("opacity", afqb.global.controls.plotsControlBox.lineOpacity)
				.style("stroke-width", "1.1px");
		}
	}
}
<|endoftext|>