<commit_before>var complete_data = null;
var meuGrafico = null;
new dimple.color("")

function carrega () {
  //desenha grafico
    d3.csv("dados/ibope_2014.csv", function (data) {
        window.complete_data = data;
        //atualiza_recorte("escolaridade","medio");
        cria_grafico();
   });
}

function cria_grafico() {
    var data = dimple.filterData(window.complete_data, "cat_recorte", "total");
        data = dimple.filterData(data, "recorte", "total");
        data = dimple.filterData(data, "cat_pergunta", "intencao_estimulada");
    var myChart = new dimple.chart(svg,data);
    window.chart=myChart;
    myChart.setBounds(45,20,725,390);
    var x = myChart.addTimeAxis("x","data","%Y-%m-%d","%d/%m");
    x.addOrderRule("");
    x.title = "";
    x.overrideMin = new Date("2014-03-16"); //TODO: pegar a menor data usando a d3 e lendo a base de dados e subtrair 1
    x.overrideMax = new Date("2014-05-20"); //TODO: pegar a maior data usando a d3 e lendo a base de dados e somar 1
    //x.timeInterval = 4;
    myChart.addMeasureAxis("y","valor");

    myChart.addSeries("dado",dimple.plot.line);
    s = myChart.addSeries("dado", dimple.plot.bubble);
    legend = myChart.addLegend(720, 2, 195, 220, "right");
    myChart = configuraCores(myChart,"intencao_estimulada");

    //arruma ordem da legenda
    legend._getEntries = function () { return ordemLegenda("intencao_estimulada"); };

    //arruma as fontes
    //legend.fontFamily = "Arial";
    legend.fontSize = "82%";

    //x.fontFamily = "Arial";
    x.fontSize = "95%";

    y = myChart.axes[1]

    //y.fontFamily = "Arial";
    y.fontSize = "95%";
    y.title = "Intenção de Voto (%)"

    //customiza a tooltip
    s.getTooltipText = function (e) {
        return [
            e.aggField[0]+": "+ e.y
        ];
    };

    myChart.draw();

    x.shapes.selectAll("text").attr("transform",
        function (d) {
            //return d3.select(this).attr("transform") + " translate(-14, 38) rotate(-90)";
            return d3.select(this).attr("transform") + " translate(0, 20) rotate(-45)";
        });
}

function ordemLegenda(pergunta) {
    var orderedValues = []
    if (pergunta.indexOf("intencao_estimulada") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves", "Eduardo Campos","Pastor Everaldo","Outros","Branco e Nulo","Não sabe"];
    } else if (pergunta.indexOf("intencao_espontanea") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves", "Eduardo Campos","Pastor Everaldo","Lula","Marina Silva","Outros","Branco e Nulo","Não sabe"];
    } else if (pergunta.indexOf("rejeicao") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves", "Eduardo Campos","Pastor Everaldo"];
    } else if (pergunta.indexOf("turno_aecio") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves","Branco e Nulo","Não sabe"];
    } else if (pergunta.indexOf("turno_campos") != -1) {
        orderedValues = ["Dilma Rousseff", "Eduardo Campos","Branco e Nulo","Não sabe"];
    } else if (pergunta.indexOf("avaliacao") != -1) {
        orderedValues = ["Ótimo ou bom","Regular","Ruim ou péssimo","NS/NR*"]
    } else if (pergunta.indexOf("interesse")!= -1) {
        orderedValues = ["Tem muito interesse","Tem médio interesse","Não tem interesse","NS/NR*"]
    } else if (pergunta.indexOf("aprova")!= -1) {
        orderedValues = ["Aprova","Desaprova","NS/NR*"]
    } else if (pergunta.indexOf("desejo")!= -1) {
        orderedValues = ["Quer mudança","Quer continuidade","NS/NR*"]
    }

    console.log(pergunta)
    var entries = [];
    orderedValues.forEach(function (v) {
        entries.push(
        {
                key: v,
                fill: window.chart.getColor(v).fill,
                stroke: window.chart.getColor(v).stroke,
                opacity: window.chart.getColor(v).opacity,
                series: s,
                aggField: [v]
            }
        );
    }, this);
    return entries
}
function configuraCores(grafico, pergunta) {
    if (pergunta.indexOf("intencao") != -1 || pergunta.indexOf("rejeicao") != -1 || pergunta.indexOf("turno") != -1) {
        grafico.assignColor("Aécio Neves","#1C4587");
        grafico.assignColor("Dilma Rousseff","#CC0000");
        grafico.assignColor("Eduardo Campos","#E69138");
        grafico.assignColor("Pastor Everaldo","#6AA84F");
        grafico.assignColor("Não sabe","#2E2B2D");
        grafico.assignColor("Branco e Nulo","#C9C9C9");
    } else if (pergunta.indexOf("avalia") != -1 || pergunta.indexOf("aprova") != -1 ) {
        grafico.defaultColors = [
            new dimple.color("#3C3C3C"),
            new dimple.color("#5C5C5C"),
            new dimple.color("#8C8C8C"),
            new dimple.color("#ACACAC"),
            new dimple.color("#CCCCCC"),
            new dimple.color("#000000")
            ]
    }else if (pergunta.indexOf("interesse") != -1) {
         grafico.defaultColors = [
            new dimple.color("#001C44"),
            new dimple.color("#002159"),
            new dimple.color("#0A4F87"),
            new dimple.color("#1E5DAE"),
            new dimple.color("#D3CAD3")
         ]
    } else {
         grafico.defaultColors = [
            new dimple.color("#6C2817"),
            new dimple.color("#BA7E50"),
            new dimple.color("#F3AA4B"),
            new dimple.color("#EDF1DB"),
            new dimple.color("#A9C4BB")
         ]
    }
    return grafico;
}

function limpar_legendas() {
    $('*[class^="dimple-legend"]').remove()
}

function atualiza_grafico(argumentos) {
    // argumentos é um dicionário com as seguintes variáveis:
    // pergunta, recorte, variavel, texto_pergunta, texto_recorte

    // Definindo valor padrão para as variáveis, caso nenhum seja passado.
    var pergunta = argumentos.pergunta || $(".botao-selecao-pergunta").data("pergunta") || "intencao_estimulada",
        cat_recorte = argumentos.cat_recorte || $(".botao-selecao-recorte").data("catRecorte") || "total",
        recorte = argumentos.recorte || $(".botao-selecao-recorte").data("recorte") || "total",
        texto_pergunta = argumentos.texto_pergunta || $(".botao-selecao-pergunta").html() || "Intenção de Voto Estimulada",
        texto_recorte = argumentos.texto_recorte || $(".botao-selecao-recorte").html() || "Total do eleitorado";
    //Escondendo opções de recorte que são incompatíveis com perguntas
    if ( pergunta == "desejo_mudanca" ){
        $(".rec-avalia").show();
        $(".rec-muda").hide();
        if (cat_recorte == "desejo_mudanca" ) {
            cat_recorte = "total";
            recorte = "total";
            texto_recorte = "Total do Eleitorado";
        }
    } else if (pergunta == "avaliacao_governo") {
        $(".rec-muda").show();
        $(".rec-avalia").hide();
        if (cat_recorte == "avaliacao_governo") {
            cat_recorte = "total";
            recorte = "total";
            texto_recorte = "Total do Eleitorado";
        }
    } else {
        $(".rec-muda").show();
        $(".rec-avalia").show();
    }

    // filtra os dados de acordo com a pergunta e o recorte atuais
    var data = dimple.filterData(window.complete_data,"cat_recorte", cat_recorte);
        data = dimple.filterData(data, "recorte", recorte);
        data = dimple.filterData(data, "cat_pergunta", pergunta);

    $(".botao-selecao-pergunta").html(texto_pergunta); // Alterando texto do botão de pergunta
    $(".botao-selecao-recorte").html(texto_recorte); // Alterando texto do botão de recorte
    $(".botao-selecao-pergunta").data("pergunta",pergunta); // e coloca um atributo de "data" no botão mostrando qual é a atual pergunta
    $(".botao-selecao-recorte").data("catRecorte",cat_recorte); // e coloca um atributo de "data" no botão mostrando qual é a atual pergunta
    $(".botao-selecao-recorte").data("recorte",recorte); // e coloca um atributo de "data" no botão mostrando qual é a atual pergunta

    chart.data = data; // Definindo novo conjunto de dados do gráfico

    //arruma as legendas
    chart.legends = [];
    limpar_legendas(); //limpa as antigas
    legend = chart.addLegend(720, 2, 195, 220, "right"); //adiciona as novas
    legend._getEntries = function () { return ordemLegenda(pergunta); }; //arruma a ordem
    chart = configuraCores(chart, pergunta); //aruma as cores

    y.title = texto_pergunta + " (%)";

    chart.draw(1000); // Desenhando novo gráfico com animação durando 1000 ms
}

function atualiza_recorte(cat_recorte, recorte, texto){
        atualiza_grafico({cat_recorte: cat_recorte, recorte: recorte, texto_recorte: texto});
}

function atualiza_pergunta(pergunta, texto){
    atualiza_grafico({pergunta: pergunta, texto_pergunta: texto})
}

$(document).ready(function(){
    window.svg = dimple.newSvg("#grafico", 950, 490);
    carrega();
});
<commit_msg>Fixes #7<commit_after>var complete_data = null;
var meuGrafico = null;
new dimple.color("")

function carrega () {
  //desenha grafico
    d3.csv("dados/ibope_2014.csv", function (data) {
        window.complete_data = data;
        //atualiza_recorte("escolaridade","medio");
        cria_grafico();
   });
}

function cria_grafico() {
    var data = dimple.filterData(window.complete_data, "cat_recorte", "total");
        data = dimple.filterData(data, "recorte", "total");
        data = dimple.filterData(data, "cat_pergunta", "intencao_estimulada");
    var myChart = new dimple.chart(svg,data);
    window.chart=myChart;
    myChart.setBounds(45,20,725,390);
    var x = myChart.addTimeAxis("x","data","%Y-%m-%d","%d/%m");
    x.addOrderRule("");
    x.title = "";
    x.overrideMin = new Date("2014-03-16"); //TODO: pegar a menor data usando a d3 e lendo a base de dados e subtrair 1
    x.overrideMax = new Date("2014-05-20"); //TODO: pegar a maior data usando a d3 e lendo a base de dados e somar 1
    //x.timeInterval = 4;
    myChart.addMeasureAxis("y","valor");

    myChart.addSeries("dado",dimple.plot.line);
    s = myChart.addSeries("dado", dimple.plot.bubble);
    legend = myChart.addLegend(720, 2, 195, 220, "right");
    myChart = configuraCores(myChart,"intencao_estimulada");

    //arruma ordem da legenda
    legend._getEntries = function () { return ordemLegenda("intencao_estimulada"); };

    //arruma as fontes
    //legend.fontFamily = "Arial";
    legend.fontSize = "82%";

    //x.fontFamily = "Arial";
    x.fontSize = "95%";

    y = myChart.axes[1]

    //y.fontFamily = "Arial";
    y.fontSize = "95%";
    y.title = "Intenção de Voto (%)"

    //customiza a tooltip
    s.getTooltipText = function (e) {
        return [
            e.aggField[0]+": "+ e.y
        ];
    };

    myChart.draw();

    x.shapes.selectAll("text").attr("transform",
        function (d) {
            //return d3.select(this).attr("transform") + " translate(-14, 38) rotate(-90)";
            return d3.select(this).attr("transform") + " translate(0, 20) rotate(-45)";
        });
}

function ordemLegenda(pergunta) {
    var orderedValues = []
    if (pergunta.indexOf("intencao_estimulada") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves", "Eduardo Campos","Pastor Everaldo","Outros","Branco e Nulo","NS/NR*"];
    } else if (pergunta.indexOf("intencao_espontanea") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves", "Eduardo Campos","Pastor Everaldo","Lula","Marina Silva","Outros","Branco e Nulo","NS/NR*"];
    } else if (pergunta.indexOf("rejeicao") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves", "Eduardo Campos","Pastor Everaldo"];
    } else if (pergunta.indexOf("turno_aecio") != -1) {
        orderedValues = ["Dilma Rousseff", "Aécio Neves","Branco e Nulo","NS/NR*"];
    } else if (pergunta.indexOf("turno_campos") != -1) {
        orderedValues = ["Dilma Rousseff", "Eduardo Campos","Branco e Nulo","NS/NR*"];
    } else if (pergunta.indexOf("avaliacao") != -1) {
        orderedValues = ["Ótimo ou bom","Regular","Ruim ou péssimo","NS/NR*"]
    } else if (pergunta.indexOf("interesse")!= -1) {
        orderedValues = ["Tem muito interesse","Tem médio interesse","Não tem interesse","NS/NR*"]
    } else if (pergunta.indexOf("aprova")!= -1) {
        orderedValues = ["Aprova","Desaprova","NS/NR*"]
    } else if (pergunta.indexOf("desejo")!= -1) {
        orderedValues = ["Quer mudança","Quer continuidade","NS/NR*"]
    }

    var entries = [];
    orderedValues.forEach(function (v) {
        entries.push(
        {
                key: v,
                fill: window.chart.getColor(v).fill,
                stroke: window.chart.getColor(v).stroke,
                opacity: window.chart.getColor(v).opacity,
                series: s,
                aggField: [v]
            }
        );
    }, this);
    return entries
}
function configuraCores(grafico, pergunta) {
    if (pergunta.indexOf("intencao") != -1 || pergunta.indexOf("rejeicao") != -1 || pergunta.indexOf("turno") != -1) {
        grafico.assignColor("Aécio Neves","#1C4587");
        grafico.assignColor("Dilma Rousseff","#CC0000");
        grafico.assignColor("Eduardo Campos","#E69138");
        grafico.assignColor("Pastor Everaldo","#6AA84F");
        grafico.assignColor("NS/NR*","#2E2B2D");
        grafico.assignColor("Branco e Nulo","#C9C9C9");
    } else if (pergunta.indexOf("avalia") != -1 || pergunta.indexOf("aprova") != -1 ) {
        grafico.defaultColors = [
            new dimple.color("#3C3C3C"),
            new dimple.color("#5C5C5C"),
            new dimple.color("#8C8C8C"),
            new dimple.color("#ACACAC"),
            new dimple.color("#CCCCCC"),
            new dimple.color("#000000")
            ]
    }else if (pergunta.indexOf("interesse") != -1) {
         grafico.defaultColors = [
            new dimple.color("#001C44"),
            new dimple.color("#002159"),
            new dimple.color("#0A4F87"),
            new dimple.color("#1E5DAE"),
            new dimple.color("#D3CAD3")
         ]
    } else {
         grafico.defaultColors = [
            new dimple.color("#6C2817"),
            new dimple.color("#BA7E50"),
            new dimple.color("#F3AA4B"),
            new dimple.color("#EDF1DB"),
            new dimple.color("#A9C4BB")
         ]
    }
    return grafico;
}

function limpar_legendas() {
    $('*[class^="dimple-legend"]').remove()
}

function atualiza_grafico(argumentos) {
    // argumentos é um dicionário com as seguintes variáveis:
    // pergunta, recorte, variavel, texto_pergunta, texto_recorte

    // Definindo valor padrão para as variáveis, caso nenhum seja passado.
    var pergunta = argumentos.pergunta || $(".botao-selecao-pergunta").data("pergunta") || "intencao_estimulada",
        cat_recorte = argumentos.cat_recorte || $(".botao-selecao-recorte").data("catRecorte") || "total",
        recorte = argumentos.recorte || $(".botao-selecao-recorte").data("recorte") || "total",
        texto_pergunta = argumentos.texto_pergunta || $(".botao-selecao-pergunta").html() || "Intenção de Voto Estimulada",
        texto_recorte = argumentos.texto_recorte || $(".botao-selecao-recorte").html() || "Total do eleitorado";
    //Escondendo opções de recorte que são incompatíveis com perguntas
    if ( pergunta == "desejo_mudanca" ){
        $(".rec-avalia").show();
        $(".rec-muda").hide();
        if (cat_recorte == "desejo_mudanca" ) {
            cat_recorte = "total";
            recorte = "total";
            texto_recorte = "Total do Eleitorado";
        }
    } else if (pergunta == "avaliacao_governo") {
        $(".rec-muda").show();
        $(".rec-avalia").hide();
        if (cat_recorte == "avaliacao_governo") {
            cat_recorte = "total";
            recorte = "total";
            texto_recorte = "Total do Eleitorado";
        }
    } else {
        $(".rec-muda").show();
        $(".rec-avalia").show();
    }

    // filtra os dados de acordo com a pergunta e o recorte atuais
    var data = dimple.filterData(window.complete_data,"cat_recorte", cat_recorte);
        data = dimple.filterData(data, "recorte", recorte);
        data = dimple.filterData(data, "cat_pergunta", pergunta);

    $(".botao-selecao-pergunta").html(texto_pergunta); // Alterando texto do botão de pergunta
    $(".botao-selecao-recorte").html(texto_recorte); // Alterando texto do botão de recorte
    $(".botao-selecao-pergunta").data("pergunta",pergunta); // e coloca um atributo de "data" no botão mostrando qual é a atual pergunta
    $(".botao-selecao-recorte").data("catRecorte",cat_recorte); // e coloca um atributo de "data" no botão mostrando qual é a atual pergunta
    $(".botao-selecao-recorte").data("recorte",recorte); // e coloca um atributo de "data" no botão mostrando qual é a atual pergunta

    chart.data = data; // Definindo novo conjunto de dados do gráfico

    //arruma as legendas
    chart.legends = [];
    limpar_legendas(); //limpa as antigas
    legend = chart.addLegend(720, 2, 195, 220, "right"); //adiciona as novas
    legend._getEntries = function () { return ordemLegenda(pergunta); }; //arruma a ordem
    chart = configuraCores(chart, pergunta); //aruma as cores

    y.title = texto_pergunta + " (%)";

    chart.draw(1000); // Desenhando novo gráfico com animação durando 1000 ms
}

function atualiza_recorte(cat_recorte, recorte, texto){
        atualiza_grafico({cat_recorte: cat_recorte, recorte: recorte, texto_recorte: texto});
}

function atualiza_pergunta(pergunta, texto){
    atualiza_grafico({pergunta: pergunta, texto_pergunta: texto})
}

$(document).ready(function(){
    window.svg = dimple.newSvg("#grafico", 950, 490);
    carrega();
});
<|endoftext|>


<commit_before>'use strict';

module.exports = {
	db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://' + (process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost') + '/wanderlist',
	assets: {
		lib: {
			css: [
				'public/lib/bootstrap/dist/css/bootstrap.min.css',
				'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
			],
			js: [
				'public/lib/angular/angular.min.js',
				'public/lib/angular-resource/angular-resource.js',
				'public/lib/angular-cookies/angular-cookies.js',
				'public/lib/angular-animate/angular-animate.js',
				'public/lib/angular-touch/angular-touch.js',
				'public/lib/angular-sanitize/angular-sanitize.js',
				'public/lib/angular-ui-router/release/angular-ui-router.min.js',
				'public/lib/angular-ui-utils/ui-utils.min.js',
				'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js'
			]
		},
		css: 'public/dist/application.min.css',
		js: 'public/dist/application.min.js'
	},
	facebook: {
		clientID: process.env.FACEBOOK_ID || 'APP_ID',
		clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
		callbackURL: '/auth/facebook/callback'
	},
	twitter: {
		clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
		clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
		callbackURL: '/auth/twitter/callback'
	},
	google: {
		clientID: process.env.GOOGLE_ID || 'APP_ID',
		clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
		callbackURL: '/auth/google/callback'
	},
	linkedin: {
		clientID: process.env.LINKEDIN_ID || 'APP_ID',
		clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
		callbackURL: '/auth/linkedin/callback'
	},
	github: {
		clientID: process.env.GITHUB_ID || 'APP_ID',
		clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET',
		callbackURL: 'http://www.wanderlist.info/auth/github/callback'
	},
	mailer: {
		from: process.env.MAILER_FROM || 'MAILER_FROM',
		options: {
			service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
			auth: {
				user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
				pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
			}
		}
	}
};
<commit_msg>add ngmap dependency to production<commit_after>'use strict';

module.exports = {
	db: process.env.MONGOHQ_URL || process.env.MONGOLAB_URI || 'mongodb://' + (process.env.DB_1_PORT_27017_TCP_ADDR || 'localhost') + '/wanderlist',
	assets: {
		lib: {
			css: [
				'public/lib/bootstrap/dist/css/bootstrap.min.css',
				'public/lib/bootstrap/dist/css/bootstrap-theme.min.css',
			],
			js: [
				'public/lib/angular/angular.min.js',
				'public/lib/angular-resource/angular-resource.js',
				'public/lib/angular-cookies/angular-cookies.js',
				'public/lib/angular-animate/angular-animate.js',
				'public/lib/angular-touch/angular-touch.js',
				'public/lib/angular-sanitize/angular-sanitize.js',
				'public/lib/angular-ui-router/release/angular-ui-router.min.js',
				'public/lib/angular-ui-utils/ui-utils.min.js',
				'public/lib/angular-bootstrap/ui-bootstrap-tpls.min.js',
				'public/lib/ngmap/build/scripts/ng-map.js'
			]
		},
		css: 'public/dist/application.min.css',
		js: 'public/dist/application.min.js'
	},
	facebook: {
		clientID: process.env.FACEBOOK_ID || 'APP_ID',
		clientSecret: process.env.FACEBOOK_SECRET || 'APP_SECRET',
		callbackURL: '/auth/facebook/callback'
	},
	twitter: {
		clientID: process.env.TWITTER_KEY || 'CONSUMER_KEY',
		clientSecret: process.env.TWITTER_SECRET || 'CONSUMER_SECRET',
		callbackURL: '/auth/twitter/callback'
	},
	google: {
		clientID: process.env.GOOGLE_ID || 'APP_ID',
		clientSecret: process.env.GOOGLE_SECRET || 'APP_SECRET',
		callbackURL: '/auth/google/callback'
	},
	linkedin: {
		clientID: process.env.LINKEDIN_ID || 'APP_ID',
		clientSecret: process.env.LINKEDIN_SECRET || 'APP_SECRET',
		callbackURL: '/auth/linkedin/callback'
	},
	github: {
		clientID: process.env.GITHUB_ID || 'APP_ID',
		clientSecret: process.env.GITHUB_SECRET || 'APP_SECRET',
		callbackURL: 'http://www.wanderlist.info/auth/github/callback'
	},
	mailer: {
		from: process.env.MAILER_FROM || 'MAILER_FROM',
		options: {
			service: process.env.MAILER_SERVICE_PROVIDER || 'MAILER_SERVICE_PROVIDER',
			auth: {
				user: process.env.MAILER_EMAIL_ID || 'MAILER_EMAIL_ID',
				pass: process.env.MAILER_PASSWORD || 'MAILER_PASSWORD'
			}
		}
	}
};
<|endoftext|>


<commit_before>Core.Object.extend('Core.DelayedTask',
/**@lends Core.DelayedTask#*/
{
	delay: 1,
	scope: undefined,
	callback: undefined,
	arguments: undefined,
	isDone: false,

	/**
    *   @constructs
	*	@class
    *   @extends Core.Object
	*	@param config.delay
	*	@param config.scope
	*	@param config.arguments
	*	@param config.callback
	*/
	constructor: function(config) {
		if('delay' in config) {
			this.delay = config.delay;
			delete(config.delay);
		}
		if('scope' in config) {
			this.scope = config.scope;
			delete(config.scope);
		}
		if('arguments' in config) {
			this.arguments = config.arguments;
			delete(config.arguments);
		}
		else
			this.arguments = [];
		if('callback' in config) {
			this.callback = config.callback;
			delete(config.callback);
		}
		else
			throw('callback MUST be given for a DelayedTask');

		var wrapper = function() {
			arguments.callee.delayedtask.handle = undefined;
			arguments.callee.delayedtask.callback.apply(arguments.callee.delayedtask.scope, arguments.callee.delayedtask.arguments);
			arguments.callee.delayedtask.isDone = true;
		};
		wrapper.delayedtask = this;
		this.handle = setTimeout(wrapper, this.delay * 1000);
	},

	abort: function() {
		if(this.handle !== undefined) {
			clearTimeout(this.handle);
			this.handle = undefined;
		}
	}
});

<commit_msg>use bind for the callback<commit_after>Core.Object.extend('Core.DelayedTask',
/**@lends Core.DelayedTask#*/
{
	delay: 1,
	scope: undefined,
	callback: undefined,
	arguments: undefined,
	isDone: false,
	handle: undefined,

	/**
    *   @constructs
	*	@class
    *   @extends Core.Object
	*	@param config.delay
	*	@param config.scope
	*	@param config.arguments
	*	@param config.callback
	*/
	constructor: function(config) {
		if('delay' in config) {
			this.delay = config.delay;
			delete(config.delay);
		}
		if('scope' in config) {
			this.scope = config.scope;
			delete(config.scope);
		}
		if('arguments' in config) {
			this.arguments = config.arguments;
			delete(config.arguments);
		}
		else
			this.arguments = [];
		if('callback' in config) {
			this.callback = config.callback;
			delete(config.callback);
		}
		else
			throw('callback MUST be given for a DelayedTask');
		this.handle = setTimeout(this.onTimeout.bind(this), this.delay * 1000);
	},

	onTimeout: function() {
		this.handle = undefined;
		this.isDone = true;
		this.callback.apply(this.scope, this);
	},

	abort: function() {
		if(this.handle !== undefined) {
			clearTimeout(this.handle);
			this.handle = undefined;
		}
	}
});

<|endoftext|>


<commit_before>odoo.define('web_tour.tour', function(require) {
"use strict";

var ajax = require('web.ajax');
var config = require('web.config');
var core = require('web.core');
var Model = require('web.Model');
var session = require('web.session');
var TourManager = require('web_tour.TourManager');

var QWeb = core.qweb;

if (config.device.size_class <= config.device.SIZES.XS) { return; }

return session.is_bound.then(function () {
    var defs = [];
    // Load the list of consumed tours and the tip template only if we are admin, in the frontend,
    // tours being only available for the admin. For the backend, the list of consumed is directly
    // in the page source.
    if (session.is_frontend && session.is_admin) {
        defs.push(new Model('web_tour.tour').call('get_consumed_tours'));
        defs.push(ajax.loadXML('/web_tour/static/src/xml/tip.xml', QWeb));
    }
    return $.when.apply($, defs).then(function (consumed_tours) {
        var tour = new TourManager(session.is_frontend ? consumed_tours : session.web_tours);

        // Use a MutationObserver to detect DOM changes
        var untracked_classnames = ["o_tooltip", "o_tooltip_content", "o_tooltip_overlay"];
        var check_tooltip = _.throttle(function (records) {
            var update = _.find(records, function (record) {
                var record_class = record.target.className;
                return !_.isString(record_class) ||
                       _.intersection(record_class.split(' '), untracked_classnames).length === 0;
            });
            if (update) { // ignore mutations in the tooltip itself
                tour.update();
            }
        }, 500, {leading: false});
        var observer = new MutationObserver(check_tooltip);
        var observe = function () {
            $(function () {
                observer.observe(document.body, {
                    attributes: true,
                    childList: true,
                    subtree: true,
                });
            });
        };

        // Enable the MutationObserver for the admin or if a tour is running, when the DOM is ready
        if (session.is_admin || tour.running_tour) {
            observe();
        }
        // Override the TourManager so that it enables/disables the observer when necessary
        if (!session.is_admin) {
            var run = tour.run;
            tour.run = function () {
                run.apply(this, arguments);
                if (this.running_tour) { observe(); }
            };
            var _consume_tour = tour._consume_tour;
            tour._consume_tour = function () {
                _consume_tour.apply(this, arguments);
                observer.disconnect();
            };
        }

        return tour;
    });
});

});
<commit_msg>[FIX] web_tour: tours for mobile mode<commit_after>odoo.define('web_tour.tour', function(require) {
"use strict";

var ajax = require('web.ajax');
var config = require('web.config');
var core = require('web.core');
var Model = require('web.Model');
var session = require('web.session');
var TourManager = require('web_tour.TourManager');

var QWeb = core.qweb;

if (config.device.size_class <= config.device.SIZES.XS) {
    return {
        register: function () {},
        run: function () {
            console.warn("Tours are disabled for mobile mode.");
        },
    };
}

return session.is_bound.then(function () {
    var defs = [];
    // Load the list of consumed tours and the tip template only if we are admin, in the frontend,
    // tours being only available for the admin. For the backend, the list of consumed is directly
    // in the page source.
    if (session.is_frontend && session.is_admin) {
        defs.push(new Model('web_tour.tour').call('get_consumed_tours'));
        defs.push(ajax.loadXML('/web_tour/static/src/xml/tip.xml', QWeb));
    }
    return $.when.apply($, defs).then(function (consumed_tours) {
        var tour = new TourManager(session.is_frontend ? consumed_tours : session.web_tours);

        // Use a MutationObserver to detect DOM changes
        var untracked_classnames = ["o_tooltip", "o_tooltip_content", "o_tooltip_overlay"];
        var check_tooltip = _.throttle(function (records) {
            var update = _.find(records, function (record) {
                var record_class = record.target.className;
                return !_.isString(record_class) ||
                       _.intersection(record_class.split(' '), untracked_classnames).length === 0;
            });
            if (update) { // ignore mutations in the tooltip itself
                tour.update();
            }
        }, 500, {leading: false});
        var observer = new MutationObserver(check_tooltip);
        var observe = function () {
            $(function () {
                observer.observe(document.body, {
                    attributes: true,
                    childList: true,
                    subtree: true,
                });
            });
        };

        // Enable the MutationObserver for the admin or if a tour is running, when the DOM is ready
        if (session.is_admin || tour.running_tour) {
            observe();
        }
        // Override the TourManager so that it enables/disables the observer when necessary
        if (!session.is_admin) {
            var run = tour.run;
            tour.run = function () {
                run.apply(this, arguments);
                if (this.running_tour) { observe(); }
            };
            var _consume_tour = tour._consume_tour;
            tour._consume_tour = function () {
                _consume_tour.apply(this, arguments);
                observer.disconnect();
            };
        }

        return tour;
    });
});

});
<|endoftext|>


<commit_before>/**
 * Created by aleckim on 2018. 2. 2..
 */

var async = require('async');
var express = require('express');
var router = express.Router();
var ControllerPush = require('../../controllers/controllerPush');
var AlertPushController = require('../../controllers/alert.push.controller');

function updatePushInfoList(language, pushList, callback) {
    if (!Array.isArray(pushList)) {
        var err = new Error('Invalid push info list');
        err.statusCode = 403;
        return callback(err);
    }

    async.map(pushList,
        function (pushInfo, callback) {
            try {
                pushInfo.lang = language;
                if (pushInfo.location) {
                    pushInfo.geo = [pushInfo.location.long, pushInfo.location.lat];
                }
                if (pushInfo.source == undefined) {
                    log.error('pushInfo source is undefined');
                    pushInfo.source = "KMA"
                }
                if (pushInfo.category == undefined) {
                    log.error('pushInfo category is undefined');
                    pushInfo.category = 'alarm';
                }

                pushInfo.units = UnitConverter.initUnits(pushInfo.units);

                log.info('pushInfo : '+ JSON.stringify(pushInfo));
            }
            catch (err) {
                return callback (err);
            }
            if (pushInfo.category === 'alarm') {
                var co = new ControllerPush();
                co.updatePushInfo(pushInfo, function (err, result) {
                    callback(err, result);
                });
            }
            else if (pushInfo.category === 'alert') {
                var ca = new AlertPushController();
                ca.updateAlertPush(pushInfo, function (err, result) {
                   callback(err, result) ;
                })
            }
        },
        function (err, results) {
            if (err) {
                err.statusCode = 500;
                return callback(err);
            }
            callback(null, results);
        });
}

router.post('/', function(req, res) {
    log.info('post : '+ JSON.stringify(req.body));
    log.info('accept-language:'+req.headers['accept-language']);

    var language = req.headers['accept-language'] || req.headers['Accept-Language'];

    if (language == undefined) {
        log.warn("accept-language is undefined");
        language = 'en';
    }
    else {
        language = language.split(',')[0];
        if (language) {
            if ( language.indexOf('ko') >= 0 ||
                language.indexOf('en') >= 0 ||
                language.indexOf('ja') >= 0 ||
                language.indexOf('de') >= 0 )
            {
                language = language.substr(0, 2);
            }
        }
        else {
            log.error("Fail to parse language="+req.headers['accept-language']);
            language = 'en';
        }
    }

    var pushList = req.body;
    try {
        pushList.forEach(function (obj) {
           if (!obj.hasOwnProperty('registrationId') ||
               !obj.hasOwnProperty('type') )
           {
               throw new Error('invalid push info registrationId/type');
           }

           if (obj.registrationId.length === 0 ||
               obj.type.length === 0)
           {
               throw new Error('invalid push info registrationId/type');
           }

           if (!obj.hasOwnProperty('location') && !obj.hasOwnProperty('town')) {
               throw new Error('invalid push info location or town is empty');
           }
        });
    }
    catch (err) {
        log.error(err);
        return res.status(403).send(err.message);
    }

    updatePushInfoList(language, pushList, function (err, result) {
        if (err) {
            log.error(err);
            if (err.statusCode) {
                return res.status(err.statusCode).send(err.message);
            }
            else {
                return res.status(501).send(err.message);
            }
        }
        return res.send(result);
    });
});

module.exports = router;
<commit_msg>TW-173 add missed UnitConverter<commit_after>/**
 * Created by aleckim on 2018. 2. 2..
 */

var async = require('async');
var express = require('express');
var router = express.Router();
var ControllerPush = require('../../controllers/controllerPush');
var AlertPushController = require('../../controllers/alert.push.controller');
var UnitConverter = require('../../lib/unitConverter');

function updatePushInfoList(language, pushList, callback) {
    if (!Array.isArray(pushList)) {
        var err = new Error('Invalid push info list');
        err.statusCode = 403;
        return callback(err);
    }

    async.map(pushList,
        function (pushInfo, callback) {
            try {
                pushInfo.lang = language;
                if (pushInfo.location) {
                    pushInfo.geo = [pushInfo.location.long, pushInfo.location.lat];
                }
                if (pushInfo.source == undefined) {
                    log.error('pushInfo source is undefined');
                    pushInfo.source = "KMA"
                }
                if (pushInfo.category == undefined) {
                    log.error('pushInfo category is undefined');
                    pushInfo.category = 'alarm';
                }

                pushInfo.units = UnitConverter.initUnits(pushInfo.units);

                log.info('pushInfo : '+ JSON.stringify(pushInfo));
            }
            catch (err) {
                return callback (err);
            }
            if (pushInfo.category === 'alarm') {
                var co = new ControllerPush();
                co.updatePushInfo(pushInfo, function (err, result) {
                    callback(err, result);
                });
            }
            else if (pushInfo.category === 'alert') {
                var ca = new AlertPushController();
                ca.updateAlertPush(pushInfo, function (err, result) {
                   callback(err, result) ;
                })
            }
        },
        function (err, results) {
            if (err) {
                err.statusCode = 500;
                return callback(err);
            }
            callback(null, results);
        });
}

router.post('/', function(req, res) {
    log.info('post : '+ JSON.stringify(req.body));
    log.info('accept-language:'+req.headers['accept-language']);

    var language = req.headers['accept-language'] || req.headers['Accept-Language'];

    if (language == undefined) {
        log.warn("accept-language is undefined");
        language = 'en';
    }
    else {
        language = language.split(',')[0];
        if (language) {
            if ( language.indexOf('ko') >= 0 ||
                language.indexOf('en') >= 0 ||
                language.indexOf('ja') >= 0 ||
                language.indexOf('de') >= 0 )
            {
                language = language.substr(0, 2);
            }
        }
        else {
            log.error("Fail to parse language="+req.headers['accept-language']);
            language = 'en';
        }
    }

    var pushList = req.body;
    try {
        pushList.forEach(function (obj) {
           if (!obj.hasOwnProperty('registrationId') ||
               !obj.hasOwnProperty('type') )
           {
               throw new Error('invalid push info registrationId/type');
           }

           if (obj.registrationId.length === 0 ||
               obj.type.length === 0)
           {
               throw new Error('invalid push info registrationId/type');
           }

           if (!obj.hasOwnProperty('location') && !obj.hasOwnProperty('town')) {
               throw new Error('invalid push info location or town is empty');
           }
        });
    }
    catch (err) {
        log.error(err);
        return res.status(403).send(err.message);
    }

    updatePushInfoList(language, pushList, function (err, result) {
        if (err) {
            log.error(err);
            if (err.statusCode) {
                return res.status(err.statusCode).send(err.message);
            }
            else {
                return res.status(501).send(err.message);
            }
        }
        return res.send(result);
    });
});

module.exports = router;
<|endoftext|>


<commit_before>/*
 *  fs/list.js
 *
 *  David Janes
 *  IOTDB.org
 *  2018-11-06
 *
 *  Copyright [2013-2019] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License")
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict"

const _ = require("iotdb-helpers")

const assert = require("assert")

const logger = require("../logger")(__filename)

/**
 */
const _list_folder = _.promise((self, done) => {
    const mongodb = require("..")

    _.promise(self)
        .add({
            table_name: `${self.bucket}.files`,
            query: {
                "metadata.folder": self.folder,
            },
            projection: [ "filename" ],
        })
        .then(mongodb.collection)
        .then(mongodb.find)
        .add("paths", sd => sd.jsons.map(json => json.filename))
        .end(done, self, "paths")
})

/**
 */
const _list_file = _.promise((self, done) => {
    const mongodb = require("..")

    _.promise(self)
        .then(mongodb.fs.exists)
        .make(sd => {
            if (sd.exists) {
                sd.paths.push(sd.path)
            }
        })
        .end(done, self)
})

/**
 */
const list = _.promise((self, done) => {
    const mongodb = require("..")

    logger.trace({
        method: list.method,
        path: self.path,
    }, "called")

    _.promise(self)
        .validate(list)
        .add("paths", [])
        .then(mongodb.fs.parse_path)
        .conditional(sd => sd.filename === sd.folder, _list_folder, _list_file)
        .end(done, self, "paths")
})

list.method = "fs.list"
list.required = {
    path: _.is.String,
    mongodb: _.is.Object,
}
list.accepts = {
}

/**
 *  API
 */
exports.list = list
<commit_msg>add a filter<commit_after>/*
 *  fs/list.js
 *
 *  David Janes
 *  IOTDB.org
 *  2018-11-06
 *
 *  Copyright [2013-2019] [David P. Janes]
 *
 *  Licensed under the Apache License, Version 2.0 (the "License")
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */

"use strict"

const _ = require("iotdb-helpers")

const assert = require("assert")

const logger = require("../logger")(__filename)

/**
 */
const _list_folder = _.promise((self, done) => {
    const mongodb = require("..")

    _.promise(self)
        .add({
            table_name: `${self.bucket}.files`,
            query: {
                "metadata.folder": self.folder,
            },
            projection: [ "filename" ],
        })
        .then(mongodb.collection)
        .then(mongodb.find)
        .add("paths", sd => sd.jsons.map(json => json.filename))
        .end(done, self, "paths")
})

/**
 */
const _list_file = _.promise((self, done) => {
    const mongodb = require("..")

    _.promise(self)
        .then(mongodb.fs.exists)
        .make(sd => {
            if (sd.exists) {
                sd.paths.push(sd.path)
            }
        })
        .end(done, self)
})

/**
 */
const list = _.promise((self, done) => {
    const mongodb = require("..")

    logger.trace({
        method: list.method,
        path: self.path,
    }, "called")

    _.promise(self)
        .validate(list)
        .add("paths", [])
        .then(mongodb.fs.parse_path)
        .conditional(sd => sd.filename === sd.folder, _list_folder, _list_file)
        .make(sd => {
            if (sd.filter) {
                sd.paths = sd.paths.filter(path => sd.filter(path))
            }
        })
        .end(done, self, "paths")
})

list.method = "fs.list"
list.required = {
    path: _.is.String,
    mongodb: _.is.Object,
}
list.accepts = {
    filter: _.is.Function,
}

/**
 *  API
 */
exports.list = list
<|endoftext|>


<commit_before>import styled from 'styled-components';

export const Backdrop = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 109;
`;

const StyledOptions = styled.div`
  display: flex;
  flex-flow: column;
  position: fixed;
  left: calc(50vw - 300px);
  bottom: 118px;
  width: 600px;
  height: calc(100vh - 110px - 137px);
  max-height: 750px;
  z-index: 110;
  border-radius: 3px;
  color: #dcdcdc;
  background: #242527;
  box-shadow: 0 11px 7px 0 rgba(0, 0, 0, 0.19);
  transform-origin: center bottom 0;
  transition: transform 0.3s;

  &:after {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    box-sizing: border-box;
    left: calc(100% / 2 - 8px);
    bottom: -8px;
    transform-origin: 50% 50%;
    transform: rotate(-45deg);
    border: 8px solid black;
    border-color: transparent transparent #1b1c1f #1b1c1f;
    box-shadow: -12px 12px 15px 0 rgba(0, 0, 0, 0.24);
  }

  .animate-enter & {
    transform: scale(0.2);
    opacity: 0.01;
  }

  .animate-enter.animate-enter-active & {
    transform: scale(1);
    opacity: 1;
    transition: transform 300ms, opacity 300ms;
  }

  .animate-leave & {
    transform: scale(1);
    opacity: 1;
  }

  .animate-leave.animate-leave-active & {
    transform: scale(0.2);
    opacity: 0.01;
    transition: transform 300ms, opacity 300ms;
  }

  .PlayMidnightOptions__header {
    text-align: center;
    flex: 0 0 auto;
    background: #27292d;
    border-bottom: 1px solid #0f1012;
    padding: 15px 25px;

    .PlayMidnightOptions__header-logo {
      height: 50px;
      width: auto;
      margin: 0 0 10px;
    }

    .PlayMidnightOptions__header-title {
      font-weight: 300;
      font-size: 28px;
      margin: 0 0 5px;

      span {
        font-weight: 100;
      }
    }

    .PlayMidnightOptions__header-version {
      font-size: 10px;
      font-weight: 700;
    }
  }

  .PlayMidnightOptions__section {
    &:last-child .PlayMidnightOptions__section-options {
      border: none;
    }

    .PlayMidnightOptions__section-title {
      background: #1b1c1f;
      margin: 0;
      padding: 15px 20px;
      font-weight: 700;
      border-bottom: 1px solid #141517;

      &:last-child {
        border: none;
      }
    }

    .PlayMidnightOptions__section-options {
      border-bottom: 1px solid #141517;

      &:empty {
        border: none;
      }
    }
  }

  .PlayMidnightOptions__options {
    position: relative;
    flex: 1 1 auto;
    overflow: hidden;
    box-shadow: inset 0 5px 25px 0 rgba(0, 0, 0, 0.12), inset 0 -5px 25px 0 rgba(0, 0, 0, 0.12);

    .PlayMidnightOptions__options-container {
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      overflow: auto;
    }
  }

  .PlayMidnightOptions__footer {
    flex: 0 0 auto;
    background: #1b1c1f;
    border-top: 1px solid #141517;
    padding: 15px 25px;
    text-align: center;
  }

  a {
    color: #dcdcdc;
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }
`;

export default StyledOptions;
<commit_msg>Added a min-height to Options<commit_after>import styled from 'styled-components';

export const Backdrop = styled.div`
  position: fixed;
  top: 0;
  left: 0;
  bottom: 0;
  right: 0;
  z-index: 109;
`;

const StyledOptions = styled.div`
  display: flex;
  flex-flow: column;
  position: fixed;
  left: calc(50vw - 300px);
  bottom: 118px;
  width: 600px;
  height: calc(100vh - 110px - 137px);
  min-height: 360px;
  max-height: 750px;
  z-index: 110;
  border-radius: 3px;
  color: #dcdcdc;
  background: #242527;
  box-shadow: 0 11px 7px 0 rgba(0, 0, 0, 0.19);
  transform-origin: center bottom 0;
  transition: transform 0.3s;

  &:after {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    box-sizing: border-box;
    left: calc(100% / 2 - 8px);
    bottom: -8px;
    transform-origin: 50% 50%;
    transform: rotate(-45deg);
    border: 8px solid black;
    border-color: transparent transparent #1b1c1f #1b1c1f;
    box-shadow: -12px 12px 15px 0 rgba(0, 0, 0, 0.24);
  }

  .animate-enter & {
    transform: scale(0.2);
    opacity: 0.01;
  }

  .animate-enter.animate-enter-active & {
    transform: scale(1);
    opacity: 1;
    transition: transform 300ms, opacity 300ms;
  }

  .animate-leave & {
    transform: scale(1);
    opacity: 1;
  }

  .animate-leave.animate-leave-active & {
    transform: scale(0.2);
    opacity: 0.01;
    transition: transform 300ms, opacity 300ms;
  }

  .PlayMidnightOptions__header {
    text-align: center;
    flex: 0 0 auto;
    background: #27292d;
    border-bottom: 1px solid #0f1012;
    padding: 15px 25px;

    .PlayMidnightOptions__header-logo {
      height: 50px;
      width: auto;
      margin: 0 0 10px;
    }

    .PlayMidnightOptions__header-title {
      font-weight: 300;
      font-size: 28px;
      margin: 0 0 5px;

      span {
        font-weight: 100;
      }
    }

    .PlayMidnightOptions__header-version {
      font-size: 10px;
      font-weight: 700;
    }
  }

  .PlayMidnightOptions__section {
    &:last-child .PlayMidnightOptions__section-options {
      border: none;
    }

    .PlayMidnightOptions__section-title {
      background: #1b1c1f;
      margin: 0;
      padding: 15px 20px;
      font-weight: 700;
      border-bottom: 1px solid #141517;

      &:last-child {
        border: none;
      }
    }

    .PlayMidnightOptions__section-options {
      border-bottom: 1px solid #141517;

      &:empty {
        border: none;
      }
    }
  }

  .PlayMidnightOptions__options {
    position: relative;
    flex: 1 1 auto;
    overflow: hidden;
    box-shadow: inset 0 5px 25px 0 rgba(0, 0, 0, 0.12), inset 0 -5px 25px 0 rgba(0, 0, 0, 0.12);

    .PlayMidnightOptions__options-container {
      position: absolute;
      top: 0;
      right: 0;
      left: 0;
      bottom: 0;
      overflow: auto;
    }
  }

  .PlayMidnightOptions__footer {
    flex: 0 0 auto;
    background: #1b1c1f;
    border-top: 1px solid #141517;
    padding: 15px 25px;
    text-align: center;
  }

  a {
    color: #dcdcdc;
    text-decoration: none;

    &:hover {
      text-decoration: underline;
    }
  }
`;

export default StyledOptions;
<|endoftext|>


<commit_before>// NAVIGATOR Module

// Load templates
const TopbarTemplate = require('../templates/topbar.hbs');
const TopbarLayoutJumpList = require('../templates/toolbar-layout-jump-list.hbs');

/**
 * Bottom topbar contructor
 * @param {object} container - the container to render the navigator to
 * @param {object[]} [customDropdownOptions] - customized dropdown buttons
 * @param {object} [customActions] - customized actions
 * @param {boolean=} [showOptions] - show options menu
 */
let Topbar = function(parent, container, customDropdownOptions = null, customActions = {}, jumpList = {}, showOptions = false) {

    this.parent = parent;

    this.DOMObject = container;

    // Layout jumplist
    this.jumpList = jumpList;

    // Custom dropdown buttons
    this.customDropdownOptions = customDropdownOptions;

    // Custom actions
    this.customActions = customActions;

    // Options menu
    this.showOptions = showOptions;

    // Flag to mark if the topbar has been rendered at least one time
    this.firstRun = true;
};

/**
 * Render topbar
 */
Topbar.prototype.render = function() {

    // Load preferences when the topbar is rendered for the first time
    if(this.firstRun) {
        // Mark topbar as loaded
        this.firstRun = false;
    }

    let self = this;
    const app = this.parent;

    // Get main object
    const mainObject = app.getElementByTypeAndId(app.mainObjectType, app.mainObjectId);

    // Get topbar trans
    let newTopbarTrans = $.extend(toolbarTrans, topbarTrans);

    // Compile layout template with data
    const html = TopbarTemplate({
        customDropdownOptions: this.customDropdownOptions,
        displayTooltips: app.common.displayTooltips,
        trans: newTopbarTrans,
        mainObject: mainObject,
        showOptions: self.showOptions
    });

    // Append layout html to the main div
    this.DOMObject.html(html);

    const setButtonActionAndState = function(button) {
        let buttonInactive = false;

        // Bind action to button
        self.DOMObject.find('#' + button.id).click(
            button.action
        );

        // If there is a inactiveCheck, use that function to switch button state
        if(button.inactiveCheck != undefined) {
            const inactiveClass = (button.inactiveCheckClass != undefined) ? button.inactiveCheckClass : 'disabled';
            const toggleValue = button.inactiveCheck();
            self.DOMObject.find('#' + button.id).toggleClass(inactiveClass, toggleValue);
            buttonInactive = toggleValue;
        }

        return buttonInactive;
    };

    // Handle custom dropwdown buttons
    if(this.customDropdownOptions != null) {

        let activeDropdown = false;

        for(let index = 0;index < this.customDropdownOptions.length;index++) {
            let buttonInactive = setButtonActionAndState(this.customDropdownOptions[index]);

            if(!buttonInactive) {
                activeDropdown = true;
            }
        }

        self.DOMObject.find('.dropdown.navbar-submenu:not(.navbar-submenu-options)').toggle(activeDropdown);
    }

    // Set layout jumpList if exists
    if(!$.isEmptyObject(this.jumpList) && $('#layoutJumpList').length == 0) {
        this.setupJumpList($("#layoutJumpListContainer"));
    }

    // Options menu
    if(self.showOptions) {
        self.DOMObject.find('.navbar-submenu-options-container').off().click(function(e) {
            e.stopPropagation();
        });

        // Toggle tooltips
        self.DOMObject.find('#displayTooltips').off().click(function() {

            app.common.displayTooltips = $('#displayTooltips').prop('checked');

            if(app.common.displayTooltips) {
                toastr.success(editorsTrans.tooltipsEnabled);
            } else {
                toastr.error(editorsTrans.tooltipsDisabled);
            }

            app.toolbar.savePrefs();

            app.common.reloadTooltips(app.editorContainer);
        });

        // Reset tour
        if(typeof app.resetTour === 'function') {
            self.DOMObject.find('#resetTour').removeClass('d-none').off().click(function() {
                app.resetTour();
            });
        }
    }

    // Update layout status
    this.updateLayoutStatus();
};

/**
* Setup layout jumplist
* @param {object} jumpListContainer
*/
Topbar.prototype.setupJumpList = function(jumpListContainer) {

    const html = TopbarLayoutJumpList(this.jumpList);
    const self = this;

    // Append layout html to the main div
    jumpListContainer.html(html);

    jumpListContainer.removeClass('d-none');

    const jumpList = jumpListContainer.find('#layoutJumpList');

    jumpList.select2({
        ajax: {
            url: jumpList.data().url,
            dataType: "json",
            data: function(params) {

                var query = {
                    layout: params.term,
                    onlyMyLayouts: $('#onlyMyLayouts').is(":checked"),
                    start: 0,
                    length: 10
                };

                localStorage.liveSearchOnlyMyLayouts = $('#onlyMyLayouts').is(":checked") ? 1 : 0;

                // Tags
                if(query.layout != undefined) {
                    var tags = query.layout.match(/\[([^}]+)\]/);
                    if(tags != null) {
                        // Add tags to search
                        query.tags = tags[1];

                        // Replace tags in the query text
                        query.layout = query.layout.replace(tags[0], '');
                    }
                }

                // Set the start parameter based on the page number
                if(params.page != null) {
                    query.start = (params.page - 1) * 10;
                }

                // Find out what is inside the search box for this list, and save it (so we can replay it when the list
                // is opened again)
                if(params.term !== undefined) {
                    localStorage.liveSearchPlaceholder = params.term;
                }

                return query;
            },
            processResults: function(data, params) {
                var results = [];

                $.each(data.data, function(index, element) {
                    results.push({
                        "id": element.layoutId,
                        "text": element.layout
                    });
                });

                var page = params.page || 1;
                page = (page > 1) ? page - 1 : page;

                return {
                    results: results,
                    pagination: {
                        more: (page * 10 < data.recordsTotal)
                    }
                };
            },
            delay: 250
        }
    });

    jumpList.on("select2:select", function(e) {
        // OPTIMIZE: Maybe use the layout load without reloading page
        //self.jumpList.callback(e.params.data.id);

        // Go to the Layout we've selected.
        window.location = jumpList.data().designerUrl.replace(":id", e.params.data.id);
    }).on("select2:opening", function(e) {
        // Set the search box according to the saved value (if we have one)

        if(localStorage.liveSearchPlaceholder != null && localStorage.liveSearchPlaceholder !== "") {
            var $search = jumpList.data("select2").dropdown.$search;
            $search.val(localStorage.liveSearchPlaceholder);

            setTimeout(function() {
                $search.trigger("input");
            }, 100);
        }
    }).on('select2:open', function(e) {
        // append checkbox after select2 search input (only once)
        if ($('#onlyMyLayouts').length === 0) {
            $("<input style='margin-left: 5px; margin-bottom: 15px' type='checkbox' id='onlyMyLayouts' name='onlyMyLayouts'> " + topbarTrans.onlyMyLayouts + "</input>")
                .insertAfter(".select2-search");

            // if checkbox was checked last time, check it now
            if (Number(localStorage.getItem('liveSearchOnlyMyLayouts')) === 1) {
                $('#onlyMyLayouts').prop('checked', true);
            }
        }

        var $search = jumpList.data("select2").dropdown.$search;

        // when checkbox state is changed trigger the select2 to make a new search
        $('#onlyMyLayouts').on('change', function(e) {
            setTimeout(function() {
                $search.trigger("input");
            }, 100);
        })
    });
};

/**
 * Update layout status in the info fields
 */
Topbar.prototype.updateLayoutStatus = function() {

    const statusContainer = this.DOMObject.find('#layout-info-status');
    const app = this.parent;

    // Use status loader icon
    statusContainer.find('i').removeClass().addClass('fa fa-spinner fa-spin');
    statusContainer.removeClass().addClass('badge badge-default');

    // Prevent the update if there's no layout status yet
    if(lD.layout.status == undefined) {
        return;
    }

    let title = '';
    let content = '';

    const labelCodes = {
        '1': 'success',
        '2': 'warning',
        '3': 'info',
        '': 'danger'
    };

    const iconCodes = {
        '1': 'check',
        '2': 'exclamation',
        '3': 'cogs',
        '': 'times'
    };

    // Create title and description
    if(lD.layout.status.messages.length > 0) {
        title = lD.layout.status.description;
        for(let index = 0;index < lD.layout.status.messages.length;index++) {
            content += '
' + lD.layout.status.messages[index] + '
';
        }
    } else {
        title = '';
        content = '
' + lD.layout.status.description + '
';
    }

    // Update label
    let labelType = (labelCodes[lD.layout.status.code] != undefined) ? labelCodes[lD.layout.status.code] : labelCodes[''];
    statusContainer.removeClass().addClass('badge badge-' + labelType)
        .attr('data-status-code', lD.layout.status.code);

    // Create or update popover
    if(statusContainer.data('bs.popover') == undefined) {
        // Create popover
        statusContainer.popover(
            {
                delay: tooltipDelay,
                title: title,
                content: content
            }
        );
    } else {
        // Update popover
        statusContainer.data('bs.popover').config.title = title;
        statusContainer.data('bs.popover').config.content = content;
    }

    // Click status to scroll timeline to first broken widget
    statusContainer.toggleClass('clickable', (iconCodes[lD.layout.status.code] == undefined)).on('click', function(){
        if(iconCodes[lD.layout.status.code] == undefined) {
            app.timeline.scrollToBrokenWidget();
        }
    });

    // Change Icon
    let iconType = (iconCodes[lD.layout.status.code] != undefined) ? iconCodes[lD.layout.status.code] : iconCodes[''];
    statusContainer.find('i').removeClass().addClass('fa fa-' + iconType);
};

module.exports = Topbar;<commit_msg>Layout Editor: Duration needs some formatting fixes xibosignage/xibo#2688<commit_after>// NAVIGATOR Module

// Load templates
const TopbarTemplate = require('../templates/topbar.hbs');
const TopbarLayoutJumpList = require('../templates/toolbar-layout-jump-list.hbs');

/**
 * Bottom topbar contructor
 * @param {object} container - the container to render the navigator to
 * @param {object[]} [customDropdownOptions] - customized dropdown buttons
 * @param {object} [customActions] - customized actions
 * @param {boolean=} [showOptions] - show options menu
 */
let Topbar = function(parent, container, customDropdownOptions = null, customActions = {}, jumpList = {}, showOptions = false) {

    this.parent = parent;

    this.DOMObject = container;

    // Layout jumplist
    this.jumpList = jumpList;

    // Custom dropdown buttons
    this.customDropdownOptions = customDropdownOptions;

    // Custom actions
    this.customActions = customActions;

    // Options menu
    this.showOptions = showOptions;

    // Flag to mark if the topbar has been rendered at least one time
    this.firstRun = true;
};

/**
 * Render topbar
 */
Topbar.prototype.render = function() {

    // Load preferences when the topbar is rendered for the first time
    if(this.firstRun) {
        // Mark topbar as loaded
        this.firstRun = false;
    }

    let self = this;
    const app = this.parent;

    // Get main object
    const mainObject = app.getElementByTypeAndId(app.mainObjectType, app.mainObjectId);

    // Format duration
    mainObject.duration = Math.round(Number(mainObject.duration)*100)/100;

    // Get topbar trans
    let newTopbarTrans = $.extend(toolbarTrans, topbarTrans);

    // Compile layout template with data
    const html = TopbarTemplate({
        customDropdownOptions: this.customDropdownOptions,
        displayTooltips: app.common.displayTooltips,
        trans: newTopbarTrans,
        mainObject: mainObject,
        showOptions: self.showOptions
    });

    // Append layout html to the main div
    this.DOMObject.html(html);

    const setButtonActionAndState = function(button) {
        let buttonInactive = false;

        // Bind action to button
        self.DOMObject.find('#' + button.id).click(
            button.action
        );

        // If there is a inactiveCheck, use that function to switch button state
        if(button.inactiveCheck != undefined) {
            const inactiveClass = (button.inactiveCheckClass != undefined) ? button.inactiveCheckClass : 'disabled';
            const toggleValue = button.inactiveCheck();
            self.DOMObject.find('#' + button.id).toggleClass(inactiveClass, toggleValue);
            buttonInactive = toggleValue;
        }

        return buttonInactive;
    };

    // Handle custom dropwdown buttons
    if(this.customDropdownOptions != null) {

        let activeDropdown = false;

        for(let index = 0;index < this.customDropdownOptions.length;index++) {
            let buttonInactive = setButtonActionAndState(this.customDropdownOptions[index]);

            if(!buttonInactive) {
                activeDropdown = true;
            }
        }

        self.DOMObject.find('.dropdown.navbar-submenu:not(.navbar-submenu-options)').toggle(activeDropdown);
    }

    // Set layout jumpList if exists
    if(!$.isEmptyObject(this.jumpList) && $('#layoutJumpList').length == 0) {
        this.setupJumpList($("#layoutJumpListContainer"));
    }

    // Options menu
    if(self.showOptions) {
        self.DOMObject.find('.navbar-submenu-options-container').off().click(function(e) {
            e.stopPropagation();
        });

        // Toggle tooltips
        self.DOMObject.find('#displayTooltips').off().click(function() {

            app.common.displayTooltips = $('#displayTooltips').prop('checked');

            if(app.common.displayTooltips) {
                toastr.success(editorsTrans.tooltipsEnabled);
            } else {
                toastr.error(editorsTrans.tooltipsDisabled);
            }

            app.toolbar.savePrefs();

            app.common.reloadTooltips(app.editorContainer);
        });

        // Reset tour
        if(typeof app.resetTour === 'function') {
            self.DOMObject.find('#resetTour').removeClass('d-none').off().click(function() {
                app.resetTour();
            });
        }
    }

    // Update layout status
    this.updateLayoutStatus();
};

/**
* Setup layout jumplist
* @param {object} jumpListContainer
*/
Topbar.prototype.setupJumpList = function(jumpListContainer) {

    const html = TopbarLayoutJumpList(this.jumpList);
    const self = this;

    // Append layout html to the main div
    jumpListContainer.html(html);

    jumpListContainer.removeClass('d-none');

    const jumpList = jumpListContainer.find('#layoutJumpList');

    jumpList.select2({
        ajax: {
            url: jumpList.data().url,
            dataType: "json",
            data: function(params) {

                var query = {
                    layout: params.term,
                    onlyMyLayouts: $('#onlyMyLayouts').is(":checked"),
                    start: 0,
                    length: 10
                };

                localStorage.liveSearchOnlyMyLayouts = $('#onlyMyLayouts').is(":checked") ? 1 : 0;

                // Tags
                if(query.layout != undefined) {
                    var tags = query.layout.match(/\[([^}]+)\]/);
                    if(tags != null) {
                        // Add tags to search
                        query.tags = tags[1];

                        // Replace tags in the query text
                        query.layout = query.layout.replace(tags[0], '');
                    }
                }

                // Set the start parameter based on the page number
                if(params.page != null) {
                    query.start = (params.page - 1) * 10;
                }

                // Find out what is inside the search box for this list, and save it (so we can replay it when the list
                // is opened again)
                if(params.term !== undefined) {
                    localStorage.liveSearchPlaceholder = params.term;
                }

                return query;
            },
            processResults: function(data, params) {
                var results = [];

                $.each(data.data, function(index, element) {
                    results.push({
                        "id": element.layoutId,
                        "text": element.layout
                    });
                });

                var page = params.page || 1;
                page = (page > 1) ? page - 1 : page;

                return {
                    results: results,
                    pagination: {
                        more: (page * 10 < data.recordsTotal)
                    }
                };
            },
            delay: 250
        }
    });

    jumpList.on("select2:select", function(e) {
        // OPTIMIZE: Maybe use the layout load without reloading page
        //self.jumpList.callback(e.params.data.id);

        // Go to the Layout we've selected.
        window.location = jumpList.data().designerUrl.replace(":id", e.params.data.id);
    }).on("select2:opening", function(e) {
        // Set the search box according to the saved value (if we have one)

        if(localStorage.liveSearchPlaceholder != null && localStorage.liveSearchPlaceholder !== "") {
            var $search = jumpList.data("select2").dropdown.$search;
            $search.val(localStorage.liveSearchPlaceholder);

            setTimeout(function() {
                $search.trigger("input");
            }, 100);
        }
    }).on('select2:open', function(e) {
        // append checkbox after select2 search input (only once)
        if ($('#onlyMyLayouts').length === 0) {
            $("<input style='margin-left: 5px; margin-bottom: 15px' type='checkbox' id='onlyMyLayouts' name='onlyMyLayouts'> " + topbarTrans.onlyMyLayouts + "</input>")
                .insertAfter(".select2-search");

            // if checkbox was checked last time, check it now
            if (Number(localStorage.getItem('liveSearchOnlyMyLayouts')) === 1) {
                $('#onlyMyLayouts').prop('checked', true);
            }
        }

        var $search = jumpList.data("select2").dropdown.$search;

        // when checkbox state is changed trigger the select2 to make a new search
        $('#onlyMyLayouts').on('change', function(e) {
            setTimeout(function() {
                $search.trigger("input");
            }, 100);
        })
    });
};

/**
 * Update layout status in the info fields
 */
Topbar.prototype.updateLayoutStatus = function() {

    const statusContainer = this.DOMObject.find('#layout-info-status');
    const app = this.parent;

    // Use status loader icon
    statusContainer.find('i').removeClass().addClass('fa fa-spinner fa-spin');
    statusContainer.removeClass().addClass('badge badge-default');

    // Prevent the update if there's no layout status yet
    if(lD.layout.status == undefined) {
        return;
    }

    let title = '';
    let content = '';

    const labelCodes = {
        '1': 'success',
        '2': 'warning',
        '3': 'info',
        '': 'danger'
    };

    const iconCodes = {
        '1': 'check',
        '2': 'exclamation',
        '3': 'cogs',
        '': 'times'
    };

    // Create title and description
    if(lD.layout.status.messages.length > 0) {
        title = lD.layout.status.description;
        for(let index = 0;index < lD.layout.status.messages.length;index++) {
            content += '
' + lD.layout.status.messages[index] + '
';
        }
    } else {
        title = '';
        content = '
' + lD.layout.status.description + '
';
    }

    // Update label
    let labelType = (labelCodes[lD.layout.status.code] != undefined) ? labelCodes[lD.layout.status.code] : labelCodes[''];
    statusContainer.removeClass().addClass('badge badge-' + labelType)
        .attr('data-status-code', lD.layout.status.code);

    // Create or update popover
    if(statusContainer.data('bs.popover') == undefined) {
        // Create popover
        statusContainer.popover(
            {
                delay: tooltipDelay,
                title: title,
                content: content
            }
        );
    } else {
        // Update popover
        statusContainer.data('bs.popover').config.title = title;
        statusContainer.data('bs.popover').config.content = content;
    }

    // Click status to scroll timeline to first broken widget
    statusContainer.toggleClass('clickable', (iconCodes[lD.layout.status.code] == undefined)).on('click', function(){
        if(iconCodes[lD.layout.status.code] == undefined) {
            app.timeline.scrollToBrokenWidget();
        }
    });

    // Change Icon
    let iconType = (iconCodes[lD.layout.status.code] != undefined) ? iconCodes[lD.layout.status.code] : iconCodes[''];
    statusContainer.find('i').removeClass().addClass('fa fa-' + iconType);
};

module.exports = Topbar;<|endoftext|>


<commit_before>import chalk from 'chalk'
import prompt from 'prompt'
import server from '../server'
import setUser from '../account'

export default { builder, handler : login }

function builder(yargs) {
  return yargs
  .usage('Usage: tick login')
}

function login(argv) {
  let values = [
    { name : 'username' },
    { name : 'password', hidden : true }
  ]

  prompt.message = ''
  prompt.delimiter = ''
  prompt.start()

  prompt.get(values, (err, user) => {
    if (err && err.message === 'canceled')
      return console.log('\nCanceled login.')

    if (err)
      throw err

    server.login(user)
    .then(user => setUser(user))
    .then(() => console.log('You\'re logged in now'))
    .catch(err => console.error(chalk.bgRed('Error'), err.data))
  })

}
<commit_msg>Format login errors better<commit_after>import chalk from 'chalk'
import prompt from 'prompt'
import server from '../server'
import setUser from '../account'

export default { builder, handler : login }

function builder(yargs) {
  return yargs
  .usage('Usage: tick login')
}

function login(argv) {
  let values = [
    { name : 'username' },
    { name : 'password', hidden : true }
  ]

  prompt.message = ''
  prompt.delimiter = ''
  prompt.start()

  prompt.get(values, (err, user) => {
    if (err && err.message === 'canceled')
      return console.log('\nCanceled login.')

    if (err)
      throw err

    server.login(user)
    .then(user => setUser(user))
    .then(() => console.log('You\'re logged in now'))
    .catch(err => console.error(formatError(err)))
  })

}

function formatError(err) {
  const prefix = chalk.bgRed('Error')
  const message = err.data || err.message
  return prefix + ' ' + message
}
<|endoftext|>


<commit_before>/*

Utilities to generate the app's GraphQL schema

*/

import deepmerge from 'deepmerge';
import GraphQLJSON from 'graphql-type-json';
import GraphQLDate from 'graphql-date';
import Vulcan from './config.js'; // used for global export
import { Utils } from './utils.js';
import { disableFragmentWarnings } from 'graphql-tag';

disableFragmentWarnings();

// get GraphQL type for a given schema and field name
const getGraphQLType = (schema, fieldName) => {

  const field = schema[fieldName];
  const type = field.type.singleType;
  const typeName = typeof type === 'object' ? 'Object' : typeof type === 'function' ? type.name : type;

  if (field.intl) {
    return 'IntlString';
  }

  switch (typeName) {

    case 'String':
      return 'String';

    case 'Boolean':
      return 'Boolean';

    case 'Number':
      return 'Float';

    case 'SimpleSchema.Integer':
      return 'Int';

    // for arrays, look for type of associated schema field or default to [String]
    case 'Array':
      const arrayItemFieldName = `${fieldName}.$`;
      // note: make sure field has an associated array
      if (schema[arrayItemFieldName]) {
        // try to get array type from associated array
        const arrayItemType = getGraphQLType(schema, arrayItemFieldName);
        return arrayItemType ? `[${arrayItemType}]` : null;
      }
      return null;

    case 'Object':
      return 'JSON';

    case 'Date':
      return 'Date';

    default:
      return null;
  }
}

export const GraphQLSchema = {

  // collections used to auto-generate schemas
  collections: [],
  addCollection(collection) {
    this.collections.push(collection);
  },
  // generate GraphQL schemas for all registered collections
  getCollectionsSchemas() {
    const collectionsSchemas = this.collections.map(collection => {
      return this.generateSchema(collection);
    }).join('');
    return collectionsSchemas;
  },

  // additional schemas
  schemas: [],
  addSchema(schema) {
    this.schemas.push(schema);
  },
  // get extra schemas defined manually
  getAdditionalSchemas() {
    const additionalSchemas = this.schemas.join('\n');
    return additionalSchemas;
  },

  // queries
  queries: [],
  addQuery(query, description) {
    this.queries.push({ query, description });
  },

  // mutations
  mutations: [],
  addMutation(mutation, description) {
    this.mutations.push({ mutation, description });
  },

  // add resolvers
  resolvers: {
    JSON: GraphQLJSON,
    Date: GraphQLDate,
  },
  addResolvers(resolvers) {
    this.resolvers = deepmerge(this.resolvers, resolvers);
  },
  removeResolver(typeName, resolverName) {
    delete this.resolvers[typeName][resolverName];
  },

  // add objects to context
  context: {},
  addToContext(object) {
    this.context = deepmerge(this.context, object);
  },

  directives: {},
  addDirective(directive) {
    this.directives = deepmerge(this.directives, directive);
  },

  // generate a GraphQL schema corresponding to a given collection
  generateSchema(collection) {

    const collectionName = collection.options.collectionName;

    const mainTypeName = collection.typeName ? collection.typeName : Utils.camelToSpaces(_.initial(collectionName).join('')); // default to posts -> Post

    // backward-compatibility code: we do not want user.telescope fields in the graphql schema
    const schema = Utils.stripTelescopeNamespace(collection.simpleSchema()._schema);

    let mainSchema = [], inputSchema = [], unsetSchema = [], graphQLSchema = '';

    _.forEach(schema, (field, fieldName) => {
      // console.log(field, fieldName)

      const fieldType = getGraphQLType(schema, fieldName);

      // only include fields that are viewable/insertable/editable and don't contain "$" in their name
      // note: insertable/editable fields must be included in main schema in case they're returned by a mutation
      if ((field.viewableBy || field.insertableBy || field.editableBy) && fieldName.indexOf('$') === -1) {

        const fieldDescription = field.description ? `# ${field.description}
  ` : '';

        const fieldDirective = field.intl ? ` @intl` : '';

        // if field has a resolveAs, push it to schema
        if (field.resolveAs) {

          if (typeof field.resolveAs === 'string') {
            // if resolveAs is a string, push it and done
            mainSchema.push(field.resolveAs);
          } else {

            // get resolver name from resolveAs object, or else default to field name
            const resolverName = field.resolveAs.fieldName || fieldName;

            // use specified GraphQL type or else convert schema type
            const fieldGraphQLType = field.resolveAs.type || fieldType;

            // if resolveAs is an object, first push its type definition
            // include arguments if there are any
            mainSchema.push(`${resolverName}${field.resolveAs.arguments ? `(${field.resolveAs.arguments})` : ''}: ${fieldGraphQLType}${fieldDirective}`);

            // then build actual resolver object and pass it to addGraphQLResolvers
            const resolver = {
              [mainTypeName]: {
                [resolverName]: field.resolveAs.resolver
              }
            };
            addGraphQLResolvers(resolver);
          }

          // if addOriginalField option is enabled, also add original field to schema
          if (field.resolveAs.addOriginalField && fieldType) {
            mainSchema.push(
`${fieldDescription}${fieldName}: ${fieldType}${fieldDirective}`);
          }

        } else {
          // try to guess GraphQL type
          if (fieldType) {
            mainSchema.push(
`${fieldDescription}${fieldName}(locale: String): ${fieldType}${fieldDirective}`);
          }
        }

        if (field.insertableBy || field.editableBy) {

          // note: marking a field as required makes it required for updates, too,
          // which makes partial updates impossible
          // const isRequired = field.optional ? '' : '!';

          const isRequired = '';

          // 2. input schema
          inputSchema.push(`${fieldName}: ${fieldType}${isRequired}`);

          // 3. unset schema
          unsetSchema.push(`${fieldName}: Boolean`);

        }

        // if field is i18nized, add special field containing all languages
        if (field.intl) {
          const intlFieldName = `${fieldName}Intl`;
          mainSchema.push(
`${intlFieldName}: JSON`);

          // add resolver that returns the actual db field without the effetcs of the @intl directive
          const intlResolver = {
            [mainTypeName]: {
              [intlFieldName]: doc => doc[fieldName]
            }
          };
          addGraphQLResolvers(intlResolver);
        }
      }
    });

    const { interfaces = [] } = collection.options;
    const graphQLInterfaces = interfaces.length ? `implements ${interfaces.join(`, `)} ` : '';

    const description = collection.options.description ? collection.options.description : `Type for ${collectionName}`

    if (mainSchema.length) {

      graphQLSchema +=
`# ${description}
type ${mainTypeName} ${graphQLInterfaces}{
  ${mainSchema.join('\n  ')}
}

`
    }

    if (inputSchema.length) {
      graphQLSchema +=
`# ${description} (input type)
input ${collectionName}Input {
  ${inputSchema.join('\n  ')}
}

`
    }

    if (unsetSchema.length) {
      graphQLSchema +=
`# ${description} (unset input type)
input ${collectionName}Unset {
  ${unsetSchema.join('\n  ')}
}

`
    }

    return graphQLSchema;
  }
};

Vulcan.getGraphQLSchema = () => {
  const schema = GraphQLSchema.finalSchema[0];
  // eslint-disable-next-line no-console
  console.log(schema);
  return schema;
}

export const addGraphQLCollection = GraphQLSchema.addCollection.bind(GraphQLSchema);
export const addGraphQLSchema = GraphQLSchema.addSchema.bind(GraphQLSchema);
export const addGraphQLQuery = GraphQLSchema.addQuery.bind(GraphQLSchema);
export const addGraphQLMutation = GraphQLSchema.addMutation.bind(GraphQLSchema);
export const addGraphQLResolvers = GraphQLSchema.addResolvers.bind(GraphQLSchema);
export const removeGraphQLResolver = GraphQLSchema.removeResolver.bind(GraphQLSchema);
export const addToGraphQLContext = GraphQLSchema.addToContext.bind(GraphQLSchema);
export const addGraphQLDirective = GraphQLSchema.addDirective.bind(GraphQLSchema);
<commit_msg>Not using IntlString scalar anymore<commit_after>/*

Utilities to generate the app's GraphQL schema

*/

import deepmerge from 'deepmerge';
import GraphQLJSON from 'graphql-type-json';
import GraphQLDate from 'graphql-date';
import Vulcan from './config.js'; // used for global export
import { Utils } from './utils.js';
import { disableFragmentWarnings } from 'graphql-tag';

disableFragmentWarnings();

// get GraphQL type for a given schema and field name
const getGraphQLType = (schema, fieldName) => {

  const field = schema[fieldName];
  const type = field.type.singleType;
  const typeName = typeof type === 'object' ? 'Object' : typeof type === 'function' ? type.name : type;

  // intl fields should be treated as strings
  if (field.intl) {
    return 'String';
  }

  switch (typeName) {

    case 'String':
      return 'String';

    case 'Boolean':
      return 'Boolean';

    case 'Number':
      return 'Float';

    case 'SimpleSchema.Integer':
      return 'Int';

    // for arrays, look for type of associated schema field or default to [String]
    case 'Array':
      const arrayItemFieldName = `${fieldName}.$`;
      // note: make sure field has an associated array
      if (schema[arrayItemFieldName]) {
        // try to get array type from associated array
        const arrayItemType = getGraphQLType(schema, arrayItemFieldName);
        return arrayItemType ? `[${arrayItemType}]` : null;
      }
      return null;

    case 'Object':
      return 'JSON';

    case 'Date':
      return 'Date';

    default:
      return null;
  }
}

export const GraphQLSchema = {

  // collections used to auto-generate schemas
  collections: [],
  addCollection(collection) {
    this.collections.push(collection);
  },
  // generate GraphQL schemas for all registered collections
  getCollectionsSchemas() {
    const collectionsSchemas = this.collections.map(collection => {
      return this.generateSchema(collection);
    }).join('');
    return collectionsSchemas;
  },

  // additional schemas
  schemas: [],
  addSchema(schema) {
    this.schemas.push(schema);
  },
  // get extra schemas defined manually
  getAdditionalSchemas() {
    const additionalSchemas = this.schemas.join('\n');
    return additionalSchemas;
  },

  // queries
  queries: [],
  addQuery(query, description) {
    this.queries.push({ query, description });
  },

  // mutations
  mutations: [],
  addMutation(mutation, description) {
    this.mutations.push({ mutation, description });
  },

  // add resolvers
  resolvers: {
    JSON: GraphQLJSON,
    Date: GraphQLDate,
  },
  addResolvers(resolvers) {
    this.resolvers = deepmerge(this.resolvers, resolvers);
  },
  removeResolver(typeName, resolverName) {
    delete this.resolvers[typeName][resolverName];
  },

  // add objects to context
  context: {},
  addToContext(object) {
    this.context = deepmerge(this.context, object);
  },

  directives: {},
  addDirective(directive) {
    this.directives = deepmerge(this.directives, directive);
  },

  // generate a GraphQL schema corresponding to a given collection
  generateSchema(collection) {

    const collectionName = collection.options.collectionName;

    const mainTypeName = collection.typeName ? collection.typeName : Utils.camelToSpaces(_.initial(collectionName).join('')); // default to posts -> Post

    // backward-compatibility code: we do not want user.telescope fields in the graphql schema
    const schema = Utils.stripTelescopeNamespace(collection.simpleSchema()._schema);

    let mainSchema = [], inputSchema = [], unsetSchema = [], graphQLSchema = '';

    _.forEach(schema, (field, fieldName) => {
      // console.log(field, fieldName)

      const fieldType = getGraphQLType(schema, fieldName);

      // only include fields that are viewable/insertable/editable and don't contain "$" in their name
      // note: insertable/editable fields must be included in main schema in case they're returned by a mutation
      if ((field.viewableBy || field.insertableBy || field.editableBy) && fieldName.indexOf('$') === -1) {

        const fieldDescription = field.description ? `# ${field.description}
  ` : '';

        const fieldDirective = field.intl ? ` @intl` : '';

        // if field has a resolveAs, push it to schema
        if (field.resolveAs) {

          if (typeof field.resolveAs === 'string') {
            // if resolveAs is a string, push it and done
            mainSchema.push(field.resolveAs);
          } else {

            // get resolver name from resolveAs object, or else default to field name
            const resolverName = field.resolveAs.fieldName || fieldName;

            // use specified GraphQL type or else convert schema type
            const fieldGraphQLType = field.resolveAs.type || fieldType;

            // if resolveAs is an object, first push its type definition
            // include arguments if there are any
            mainSchema.push(`${resolverName}${field.resolveAs.arguments ? `(${field.resolveAs.arguments})` : ''}: ${fieldGraphQLType}${fieldDirective}`);

            // then build actual resolver object and pass it to addGraphQLResolvers
            const resolver = {
              [mainTypeName]: {
                [resolverName]: field.resolveAs.resolver
              }
            };
            addGraphQLResolvers(resolver);
          }

          // if addOriginalField option is enabled, also add original field to schema
          if (field.resolveAs.addOriginalField && fieldType) {
            mainSchema.push(
`${fieldDescription}${fieldName}: ${fieldType}${fieldDirective}`);
          }

        } else {
          // try to guess GraphQL type
          if (fieldType) {
            mainSchema.push(
`${fieldDescription}${fieldName}(locale: String): ${fieldType}${fieldDirective}`);
          }
        }

        if (field.insertableBy || field.editableBy) {

          // note: marking a field as required makes it required for updates, too,
          // which makes partial updates impossible
          // const isRequired = field.optional ? '' : '!';

          const isRequired = '';

          // 2. input schema
          inputSchema.push(`${fieldName}: ${fieldType}${isRequired}`);

          // 3. unset schema
          unsetSchema.push(`${fieldName}: Boolean`);

        }

        // if field is i18nized, add special field containing all languages
        if (field.intl) {
          const intlFieldName = `${fieldName}Intl`;
          mainSchema.push(
`${intlFieldName}: JSON`);

          // add resolver that returns the actual db field without the effetcs of the @intl directive
          const intlResolver = {
            [mainTypeName]: {
              [intlFieldName]: doc => doc[fieldName]
            }
          };
          addGraphQLResolvers(intlResolver);
        }
      }
    });

    const { interfaces = [] } = collection.options;
    const graphQLInterfaces = interfaces.length ? `implements ${interfaces.join(`, `)} ` : '';

    const description = collection.options.description ? collection.options.description : `Type for ${collectionName}`

    if (mainSchema.length) {

      graphQLSchema +=
`# ${description}
type ${mainTypeName} ${graphQLInterfaces}{
  ${mainSchema.join('\n  ')}
}

`
    }

    if (inputSchema.length) {
      graphQLSchema +=
`# ${description} (input type)
input ${collectionName}Input {
  ${inputSchema.join('\n  ')}
}

`
    }

    if (unsetSchema.length) {
      graphQLSchema +=
`# ${description} (unset input type)
input ${collectionName}Unset {
  ${unsetSchema.join('\n  ')}
}

`
    }

    return graphQLSchema;
  }
};

Vulcan.getGraphQLSchema = () => {
  const schema = GraphQLSchema.finalSchema[0];
  // eslint-disable-next-line no-console
  console.log(schema);
  return schema;
}

export const addGraphQLCollection = GraphQLSchema.addCollection.bind(GraphQLSchema);
export const addGraphQLSchema = GraphQLSchema.addSchema.bind(GraphQLSchema);
export const addGraphQLQuery = GraphQLSchema.addQuery.bind(GraphQLSchema);
export const addGraphQLMutation = GraphQLSchema.addMutation.bind(GraphQLSchema);
export const addGraphQLResolvers = GraphQLSchema.addResolvers.bind(GraphQLSchema);
export const removeGraphQLResolver = GraphQLSchema.removeResolver.bind(GraphQLSchema);
export const addToGraphQLContext = GraphQLSchema.addToContext.bind(GraphQLSchema);
export const addGraphQLDirective = GraphQLSchema.addDirective.bind(GraphQLSchema);
<|endoftext|>


<commit_before>/**
 * TODO: documentation
 * TODO: rename sketch -> p5?
 */
angular.module('scribbler', [])
  .factory('scribblerFactory', function(p5, scribbleEdgeFactory) {
    function setAttribute(attribute, value) {
      if(_.isFunction(value)) {
        this.attributes[attribute] = _.partial.apply(null, _.rest(arguments));
      }
      else {
        this.attributes[attribute] = _.constant(value);
      }
      return this;
    }

    function calc(attribute) {
      return this.attributes[attribute]();
    }

    function draw() {
      //update
      var count = this.sketch.floor(this.calc('count'));
      if(this.edges.length < count) {
        this.edges = this.edges.concat(_.times(count - this.edges.length, function() {
          var edge = scribbleEdgeFactory();
          edge.point = this.calc('initPoint');
          return edge;
        }, this));
      }
      else if(this.edges.length > count) {
        this.edges = _.dropRight(this.edges, this.edges.length - count);
      }

      _.forEach(this.edges, function(edge) {
        _.assign(edge, {
          point: edge.nextPoint(),
          active: this.calc('active'),
          heading: this.calc('heading'),
          magnitude: this.calc('magnitude'),
          stroke: this.calc('stroke')
        });
      }, this);

      //draw
      _.forEach(_.filter(this.edges, 'active'), function(edge) {
          var nextPoint = edge.nextPoint();

          this.sketch.stroke(edge.stroke);
          this.sketch.line(edge.point.x, edge.point.y, nextPoint.x, nextPoint.y);
        }, this);

      return this;
    }

    var scribbler = {
      initPoint: _.partial(setAttribute, 'initPoint'),
      count: _.partial(setAttribute, 'count'),
      active: _.partial(setAttribute, 'active'),
      heading: _.partial(setAttribute, 'heading'),
      magnitude: _.partial(setAttribute, 'magnitude'),
      stroke: _.partial(setAttribute, 'stroke'),
      calc: calc,
      draw: draw
    };

    return function(sketch, properties) {
      var obj = Object.create(scribbler);
      obj.attributes = {};
      obj.edges = [];

      obj.sketch = sketch;

      return obj
        .initPoint(sketch.createVector, sketch.width / 2, sketch.height / 2)
        .count(1)
        .active(true)
        .heading(sketch.random, -sketch.PI, sketch.PI)
        .magnitude(16)
        .stroke(sketch.color(0));
    };
  })
  .service('scribbleEdgeFactory', function() {
    var scribbleEdge = {
      nextPoint: nextPoint
    };

    function nextPoint() {
      var offset = p5.Vector.fromAngle(this.heading).setMag(this.magnitude);
      return p5.Vector.add(this.point, offset);
    }

    return function() {
      return _.create(scribbleEdge, {

      });
    };
  });
<commit_msg>make attributes private, further abstract attribute methods<commit_after>/**
 * TODO: documentation
 * TODO: rename sketch -> p5?
 */
angular.module('scribbler', [])
  .factory('scribblerFactory', function(p5, scribbleEdgeFactory) {
    function draw() {
      //update
      var count = this.sketch.floor(this.calc('count'));
      if(this.edges.length < count) {
        this.edges = this.edges.concat(_.times(count - this.edges.length, function() {
          var edge = scribbleEdgeFactory();
          edge.point = this.calc('initPoint');
          return edge;
        }, this));
      }
      else if(this.edges.length > count) {
        this.edges = _.dropRight(this.edges, this.edges.length - count);
      }

      _.forEach(this.edges, function(edge) {
        _.assign(edge, {
          point: edge.nextPoint(),
          active: this.calc('active'),
          heading: this.calc('heading'),
          magnitude: this.calc('magnitude'),
          stroke: this.calc('stroke')
        });
      }, this);

      //draw
      _.forEach(_.filter(this.edges, 'active'), function(edge) {
          var nextPoint = edge.nextPoint();

          this.sketch.stroke(edge.stroke);
          this.sketch.line(edge.point.x, edge.point.y, nextPoint.x, nextPoint.y);
        }, this);

      return this;
    }

    var scribbler = {
      draw: draw
    };

    function defineAttribute(attributes, attribute, value) {
      if(_.isFunction(value)) {
        attributes[attribute] = _.partial.apply(null, _.drop(arguments, 2));
      }
      else {
        attributes[attribute] = _.constant(value);
      }
    }

    function calculateAttribute(attributes, attribute) {
      return attributes[attribute](); //.apply(this);
    }

    var attributeNames = [
      'initPoint',
      'count',
      'active',
      'heading',
      'magnitude',
      'stroke'
    ];

    return function(sketch) {
      var attributes = {};

      var attributeMethods = _.map(attributeNames, function(attribute) {
        var setAttribute = _.partial(defineAttribute, attributes, attribute);
        return function() {
          setAttribute.apply(this, arguments);
          return this;
        };
      });

      var properties = _.assign(_.zipObject(attributeNames, attributeMethods), {
        edges: [],
        sketch: sketch,
        calc: _.partial(calculateAttribute, attributes)
      });

      return _.create(scribbler, properties)
        .initPoint(sketch.createVector, sketch.width / 2, sketch.height / 2)
        .count(1)
        .active(true)
        .heading(sketch.random, -sketch.PI, sketch.PI)
        .magnitude(16)
        .stroke(sketch.color(0));
    };
  })
  .service('scribbleEdgeFactory', function(p5) {
    var scribbleEdge = {
      nextPoint: nextPoint
    };

    function nextPoint() {
      var offset = p5.Vector.fromAngle(this.heading).setMag(this.magnitude);
      return p5.Vector.add(this.point, offset);
    }

    return function() {
      return _.create(scribbleEdge, {

      });
    };
  });
<|endoftext|>