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

/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

// @ts-check

const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
const util = require('util');
const opn = require('opn');
const minimist = require('vscode-minimist');

const APP_ROOT = path.dirname(__dirname);
const EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html');

const args = minimist(process.argv, {
	boolean: [
		'no-launch',
		'help'
	],
	string: [
		'scheme',
		'host',
		'port',
		'local_port'
	],
});

if (args.help) {
	console.log(
		'yarn web [options]\n' +
		' --no-launch   Do not open VSCode web in the browser\n' +
		' --scheme      Protocol (https or http)\n' +
		' --host        Remote host\n' +
		' --port        Remote/Local port\n' +
		' --local_port  Local port override\n' +
		' --help\n' +
		'[Example]\n' +
		' yarn web --scheme https --host example.com --port 8080 --local_port 30000'
	);
	process.exit(0);
}

const PORT = args.port || process.env.PORT || 8080;
const LOCAL_PORT = args.local_port || process.env.LOCAL_PORT || PORT;
const SCHEME = args.scheme || process.env.VSCODE_SCHEME || 'http';
const HOST = args.host || 'localhost';
const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`;

const server = http.createServer((req, res) => {
	const parsedUrl = url.parse(req.url, true);
	const pathname = parsedUrl.pathname;

	try {
		if (pathname === '/favicon.ico') {
			// favicon
			return serveFile(req, res, path.join(APP_ROOT, 'resources', 'win32', 'code.ico'));
		}
		if (pathname === '/manifest.json') {
			// manifest
			res.writeHead(200, { 'Content-Type': 'application/json' });
			return res.end(JSON.stringify({
				"name": "Code Web - OSS",
				"short_name": "Code Web - OSS",
				"start_url": "/",
				"lang": "en-US",
				"display": "standalone"
			}));
		}
		if (/^\/static\//.test(pathname)) {
			// static requests
			return handleStatic(req, res, parsedUrl);
		}
		if (/^\/static-extension\//.test(pathname)) {
			// static extension requests
			return handleStaticExtension(req, res, parsedUrl);
		}
		if (pathname === '/') {
			// main web
			return handleRoot(req, res);
		}

		return serveError(req, res, 404, 'Not found.');
	} catch (error) {
		console.error(error.toString());

		return serveError(req, res, 500, 'Internal Server Error.');
	}
});

server.listen(LOCAL_PORT, () => {
	if (LOCAL_PORT !== PORT) {
		console.log(`Operating location at http://0.0.0.0:${LOCAL_PORT}`);
	}
	console.log(`Web UI available at   ${SCHEME}://${AUTHORITY}`);
});

server.on('error', err => {
	console.error(`Error occurred in server:`);
	console.error(err);
});

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {import('url').UrlWithParsedQuery} parsedUrl
 */
function handleStatic(req, res, parsedUrl) {

	// Strip `/static/` from the path
	const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static/'.length)));

	return serveFile(req, res, path.join(APP_ROOT, relativeFilePath));
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {import('url').UrlWithParsedQuery} parsedUrl
 */
function handleStaticExtension(req, res, parsedUrl) {

	// Strip `/static-extension/` from the path
	const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static-extension/'.length)));

	const filePath = path.join(EXTENSIONS_ROOT, relativeFilePath);

	return serveFile(req, res, filePath);
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 */
async function handleRoot(req, res) {
	const extensionFolders = await util.promisify(fs.readdir)(EXTENSIONS_ROOT);
	const mapExtensionFolderToExtensionPackageJSON = new Map();

	await Promise.all(extensionFolders.map(async extensionFolder => {
		try {
			const packageJSON = JSON.parse((await util.promisify(fs.readFile)(path.join(EXTENSIONS_ROOT, extensionFolder, 'package.json'))).toString());
			if (packageJSON.main && packageJSON.name !== 'vscode-api-tests') {
				return; // unsupported
			}

			if (packageJSON.name === 'scss') {
				return; // seems to fail to JSON.parse()?!
			}

			packageJSON.extensionKind = ['web']; // enable for Web

			mapExtensionFolderToExtensionPackageJSON.set(extensionFolder, packageJSON);
		} catch (error) {
			return null;
		}
	}));

	const staticExtensions = [];

	// Built in extensions
	mapExtensionFolderToExtensionPackageJSON.forEach((packageJSON, extensionFolder) => {
		staticExtensions.push({
			packageJSON,
			extensionLocation: { scheme: SCHEME, authority: AUTHORITY, path: `/static-extension/${extensionFolder}` }
		});
	});

	const data = (await util.promisify(fs.readFile)(WEB_MAIN)).toString()
		.replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({
			staticExtensions,
			folderUri: { scheme: 'memfs', path: `/sample-folder` }
		})))
		.replace('{{WEBVIEW_ENDPOINT}}', '')
		.replace('{{REMOTE_USER_DATA_URI}}', '');

	res.writeHead(200, { 'Content-Type': 'text/html' });
	return res.end(data);
}

/**
 * @param {string} value
 */
function escapeAttribute(value) {
	return value.replace(/"/g, '"');
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {string} errorMessage
 */
function serveError(req, res, errorCode, errorMessage) {
	res.writeHead(errorCode, { 'Content-Type': 'text/plain' });
	res.end(errorMessage);
}

const textMimeType = {
	'.html': 'text/html',
	'.js': 'text/javascript',
	'.json': 'application/json',
	'.css': 'text/css',
	'.svg': 'image/svg+xml',
};

const mapExtToMediaMimes = {
	'.bmp': 'image/bmp',
	'.gif': 'image/gif',
	'.ico': 'image/x-icon',
	'.jpe': 'image/jpg',
	'.jpeg': 'image/jpg',
	'.jpg': 'image/jpg',
	'.png': 'image/png',
	'.tga': 'image/x-tga',
	'.tif': 'image/tiff',
	'.tiff': 'image/tiff',
	'.woff': 'application/font-woff'
};

/**
 * @param {string} forPath
 */
function getMediaMime(forPath) {
	const ext = path.extname(forPath);

	return mapExtToMediaMimes[ext.toLowerCase()];
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {string} filePath
 */
async function serveFile(req, res, filePath, responseHeaders = Object.create(null)) {
	try {

		// Sanity checks
		filePath = path.normalize(filePath); // ensure no "." and ".."
		if (filePath.indexOf(`${APP_ROOT}${path.sep}`) !== 0) {
			// invalid location outside of APP_ROOT
			return serveError(req, res, 400, `Bad request.`);
		}

		const stat = await util.promisify(fs.stat)(filePath);

		// Check if file modified since
		const etag = `W/"${[stat.ino, stat.size, stat.mtime.getTime()].join('-')}"`; // weak validator (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag)
		if (req.headers['if-none-match'] === etag) {
			res.writeHead(304);
			return res.end();
		}

		// Headers
		responseHeaders['Content-Type'] = textMimeType[path.extname(filePath)] || getMediaMime(filePath) || 'text/plain';
		responseHeaders['Etag'] = etag;

		res.writeHead(200, responseHeaders);

		// Data
		fs.createReadStream(filePath).pipe(res);
	} catch (error) {
		console.error(error.toString());
		res.writeHead(404, { 'Content-Type': 'text/plain' });
		return res.end('Not found');
	}
}

if (args.launch !== false) {
	opn(`${SCHEME}://${HOST}:${PORT}`);
}
<commit_msg>web - fix warnings<commit_after>#!/usr/bin/env node

/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

// @ts-check

const http = require('http');
const url = require('url');
const fs = require('fs');
const path = require('path');
const util = require('util');
const opn = require('opn');
const minimist = require('vscode-minimist');

const APP_ROOT = path.dirname(__dirname);
const EXTENSIONS_ROOT = path.join(APP_ROOT, 'extensions');
const WEB_MAIN = path.join(APP_ROOT, 'src', 'vs', 'code', 'browser', 'workbench', 'workbench-dev.html');

const args = minimist(process.argv, {
	boolean: [
		'no-launch',
		'help'
	],
	string: [
		'scheme',
		'host',
		'port',
		'local_port'
	],
});

if (args.help) {
	console.log(
		'yarn web [options]\n' +
		' --no-launch   Do not open VSCode web in the browser\n' +
		' --scheme      Protocol (https or http)\n' +
		' --host        Remote host\n' +
		' --port        Remote/Local port\n' +
		' --local_port  Local port override\n' +
		' --help\n' +
		'[Example]\n' +
		' yarn web --scheme https --host example.com --port 8080 --local_port 30000'
	);
	process.exit(0);
}

const PORT = args.port || process.env.PORT || 8080;
const LOCAL_PORT = args.local_port || process.env.LOCAL_PORT || PORT;
const SCHEME = args.scheme || process.env.VSCODE_SCHEME || 'http';
const HOST = args.host || 'localhost';
const AUTHORITY = process.env.VSCODE_AUTHORITY || `${HOST}:${PORT}`;

const server = http.createServer((req, res) => {
	const parsedUrl = url.parse(req.url, true);
	const pathname = parsedUrl.pathname;

	try {
		if (pathname === '/favicon.ico') {
			// favicon
			return serveFile(req, res, path.join(APP_ROOT, 'resources', 'win32', 'code.ico'));
		}
		if (pathname === '/manifest.json') {
			// manifest
			res.writeHead(200, { 'Content-Type': 'application/json' });
			return res.end(JSON.stringify({
				'name': 'Code Web - OSS',
				'short_name': 'Code Web - OSS',
				'start_url': '/',
				'lang': 'en-US',
				'display': 'standalone'
			}));
		}
		if (/^\/static\//.test(pathname)) {
			// static requests
			return handleStatic(req, res, parsedUrl);
		}
		if (/^\/static-extension\//.test(pathname)) {
			// static extension requests
			return handleStaticExtension(req, res, parsedUrl);
		}
		if (pathname === '/') {
			// main web
			return handleRoot(req, res);
		}

		return serveError(req, res, 404, 'Not found.');
	} catch (error) {
		console.error(error.toString());

		return serveError(req, res, 500, 'Internal Server Error.');
	}
});

server.listen(LOCAL_PORT, () => {
	if (LOCAL_PORT !== PORT) {
		console.log(`Operating location at http://0.0.0.0:${LOCAL_PORT}`);
	}
	console.log(`Web UI available at   ${SCHEME}://${AUTHORITY}`);
});

server.on('error', err => {
	console.error(`Error occurred in server:`);
	console.error(err);
});

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {import('url').UrlWithParsedQuery} parsedUrl
 */
function handleStatic(req, res, parsedUrl) {

	// Strip `/static/` from the path
	const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static/'.length)));

	return serveFile(req, res, path.join(APP_ROOT, relativeFilePath));
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {import('url').UrlWithParsedQuery} parsedUrl
 */
function handleStaticExtension(req, res, parsedUrl) {

	// Strip `/static-extension/` from the path
	const relativeFilePath = path.normalize(decodeURIComponent(parsedUrl.pathname.substr('/static-extension/'.length)));

	const filePath = path.join(EXTENSIONS_ROOT, relativeFilePath);

	return serveFile(req, res, filePath);
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 */
async function handleRoot(req, res) {
	const extensionFolders = await util.promisify(fs.readdir)(EXTENSIONS_ROOT);
	const mapExtensionFolderToExtensionPackageJSON = new Map();

	await Promise.all(extensionFolders.map(async extensionFolder => {
		try {
			const packageJSON = JSON.parse((await util.promisify(fs.readFile)(path.join(EXTENSIONS_ROOT, extensionFolder, 'package.json'))).toString());
			if (packageJSON.main && packageJSON.name !== 'vscode-api-tests') {
				return; // unsupported
			}

			if (packageJSON.name === 'scss') {
				return; // seems to fail to JSON.parse()?!
			}

			packageJSON.extensionKind = ['web']; // enable for Web

			mapExtensionFolderToExtensionPackageJSON.set(extensionFolder, packageJSON);
		} catch (error) {
			return null;
		}
	}));

	const staticExtensions = [];

	// Built in extensions
	mapExtensionFolderToExtensionPackageJSON.forEach((packageJSON, extensionFolder) => {
		staticExtensions.push({
			packageJSON,
			extensionLocation: { scheme: SCHEME, authority: AUTHORITY, path: `/static-extension/${extensionFolder}` }
		});
	});

	const data = (await util.promisify(fs.readFile)(WEB_MAIN)).toString()
		.replace('{{WORKBENCH_WEB_CONFIGURATION}}', escapeAttribute(JSON.stringify({
			staticExtensions,
			folderUri: { scheme: 'memfs', path: `/sample-folder` }
		})))
		.replace('{{WEBVIEW_ENDPOINT}}', '')
		.replace('{{REMOTE_USER_DATA_URI}}', '');

	res.writeHead(200, { 'Content-Type': 'text/html' });
	return res.end(data);
}

/**
 * @param {string} value
 */
function escapeAttribute(value) {
	return value.replace(/"/g, '"');
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {string} errorMessage
 */
function serveError(req, res, errorCode, errorMessage) {
	res.writeHead(errorCode, { 'Content-Type': 'text/plain' });
	res.end(errorMessage);
}

const textMimeType = {
	'.html': 'text/html',
	'.js': 'text/javascript',
	'.json': 'application/json',
	'.css': 'text/css',
	'.svg': 'image/svg+xml',
};

const mapExtToMediaMimes = {
	'.bmp': 'image/bmp',
	'.gif': 'image/gif',
	'.ico': 'image/x-icon',
	'.jpe': 'image/jpg',
	'.jpeg': 'image/jpg',
	'.jpg': 'image/jpg',
	'.png': 'image/png',
	'.tga': 'image/x-tga',
	'.tif': 'image/tiff',
	'.tiff': 'image/tiff',
	'.woff': 'application/font-woff'
};

/**
 * @param {string} forPath
 */
function getMediaMime(forPath) {
	const ext = path.extname(forPath);

	return mapExtToMediaMimes[ext.toLowerCase()];
}

/**
 * @param {import('http').IncomingMessage} req
 * @param {import('http').ServerResponse} res
 * @param {string} filePath
 */
async function serveFile(req, res, filePath, responseHeaders = Object.create(null)) {
	try {

		// Sanity checks
		filePath = path.normalize(filePath); // ensure no "." and ".."
		if (filePath.indexOf(`${APP_ROOT}${path.sep}`) !== 0) {
			// invalid location outside of APP_ROOT
			return serveError(req, res, 400, `Bad request.`);
		}

		const stat = await util.promisify(fs.stat)(filePath);

		// Check if file modified since
		const etag = `W/"${[stat.ino, stat.size, stat.mtime.getTime()].join('-')}"`; // weak validator (https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/ETag)
		if (req.headers['if-none-match'] === etag) {
			res.writeHead(304);
			return res.end();
		}

		// Headers
		responseHeaders['Content-Type'] = textMimeType[path.extname(filePath)] || getMediaMime(filePath) || 'text/plain';
		responseHeaders['Etag'] = etag;

		res.writeHead(200, responseHeaders);

		// Data
		fs.createReadStream(filePath).pipe(res);
	} catch (error) {
		console.error(error.toString());
		res.writeHead(404, { 'Content-Type': 'text/plain' });
		return res.end('Not found');
	}
}

if (args.launch !== false) {
	opn(`${SCHEME}://${HOST}:${PORT}`);
}
<|endoftext|>


<commit_before>/*!
 * Copyright(c) 2014 Jan Blaha
 */

var path = require("path"),
    q = require("q"),
    uuid = require("uuid").v1,
    fs = require("fs"),
    httpRequest = require("request"),
    toArray = require('stream-to-array'),
    excelbuilder = require('msexcel-builder-extended');

function preview(request, response, generationId, cb) {
    var req = httpRequest.post("http://jsreport.net/temp", function (err, resp, body) {
        response.headers["File-Extension"] = "html";
        response.result = "<iframe style='height:100%;width:100%' src='https://view.officeapps.live.com/op/view.aspx?src=" + encodeURIComponent("http://jsreport.net/temp/" + body) + "' />";

        //sometimes files is not completely flushed and excel online cannot find it immediately
        setTimeout(function() {
            cb();
        }, 500);

    });

    var form = req.form();
    form.append('file', fs.createReadStream(path.join(request.reporter.options.tempDirectory, generationId + ".xlsx")));
    response.headers["Content-Type"] = "text/html";
}

function render(request, response, generationId) {
    response.result = fs.createReadStream(path.join(request.reporter.options.tempDirectory, generationId + ".xlsx"));
    response.isStream = true;
    response.headers["Content-Type"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetf";
    response.headers["Content-Disposition"] = "inline; filename=\"report.xlsx\"";
    response.headers["File-Extension"] = "xlsx";
}

function responseXlsx(workbook, generationId, request, response) {
    var deferred = q.defer();

    workbook.save(function (err) {

        if (request.options.preview) {
            preview(request, response, generationId, function () {
                return deferred.resolve();
            });
        } else {
            render(request, response, generationId);
            toArray(response.result, function (err, arr) {
                if (err) {
                    return deferred.reject(err);
                }
                response.result = Buffer.concat(arr);
                return deferred.resolve();
            });
        }
    });

    return deferred.promise;
}

module.exports = function (reporter, definition) {
    reporter.xlsx = {responseXlsx: responseXlsx};

    reporter.extensionsManager.recipes.push({
        name: "xlsx",
        execute: function (request, response) {

            var generationId = uuid();

            return reporter.renderContent(request, response).then(function () {
                var deferred = q.defer();
                var workbook = excelbuilder.createWorkbook(request.reporter.options.tempDirectory, generationId + ".xlsx");

                var worksheet = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" + response.result.substring(
                        response.result.indexOf("<worksheet"),
                        response.result.indexOf("</worksheet>") + "</worksheet>".length);

                var sheet1 = workbook.createSheet('sheet1', 0, 0);
                sheet1.raw(worksheet);

                if (response.result.indexOf("<styleSheet") > 0) {
                    var stylesheet = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" + response.result.substring(
                            response.result.indexOf("<styleSheet"),
                            response.result.indexOf("</styleSheet>") + "</styleSheet>".length);
                    workbook.st.raw(stylesheet);
                }

                return reporter.xlsx.responseXlsx(workbook, generationId, request, response);
            });
        }
    });
};<commit_msg>fixing minor bugs and improving .net embedded integration<commit_after>/*!
 * Copyright(c) 2014 Jan Blaha
 */

var path = require("path"),
    q = require("q"),
    uuid = require("uuid").v1,
    fs = require("fs"),
    httpRequest = require("request"),
    toArray = require('stream-to-array'),
    excelbuilder = require('msexcel-builder-extended');

function preview(request, response, generationId, cb) {
    var req = httpRequest.post("http://jsreport.net/temp", function (err, resp, body) {
        response.headers["File-Extension"] = "html";
        response.result = "<iframe style='height:100%;width:100%' src='https://view.officeapps.live.com/op/view.aspx?src=" + encodeURIComponent("http://jsreport.net/temp/" + body) + "' />";

        //sometimes files is not completely flushed and excel online cannot find it immediately
        setTimeout(function() {
            cb();
        }, 500);

    });

    var form = req.form();
    form.append('file', fs.createReadStream(path.join(request.reporter.options.tempDirectory, generationId + ".xlsx")));
    response.headers["Content-Type"] = "text/html";
}

function render(request, response, generationId) {
    response.result = fs.createReadStream(path.join(request.reporter.options.tempDirectory, generationId + ".xlsx"));
    response.isStream = true;
    response.headers["Content-Type"] = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetf";
    response.headers["Content-Disposition"] = "inline; filename=\"report.xlsx\"";
    response.headers["File-Extension"] = "xlsx";
}

function responseXlsx(workbook, generationId, request, response) {
    var deferred = q.defer();

    workbook.save(function (err) {

        if (err) {
            return deferred.reject(err);
        }

        if (request.options.preview) {
            preview(request, response, generationId, function () {
                return deferred.resolve();
            });
        } else {
            render(request, response, generationId);
            toArray(response.result, function (err, arr) {
                if (err) {
                    return deferred.reject(err);
                }
                response.result = Buffer.concat(arr);
                return deferred.resolve();
            });
        }
    });

    return deferred.promise;
}

module.exports = function (reporter, definition) {
    reporter.xlsx = {responseXlsx: responseXlsx};

    reporter.extensionsManager.recipes.push({
        name: "xlsx",
        execute: function (request, response) {

            var generationId = uuid();

            return reporter.renderContent(request, response).then(function () {
                var deferred = q.defer();
                var workbook = excelbuilder.createWorkbook(request.reporter.options.tempDirectory, generationId + ".xlsx");

                var worksheet = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" + response.result.substring(
                        response.result.indexOf("<worksheet"),
                        response.result.indexOf("</worksheet>") + "</worksheet>".length);

                var sheet1 = workbook.createSheet('sheet1', 0, 0);
                sheet1.raw(worksheet);

                if (response.result.indexOf("<styleSheet") > 0) {
                    var stylesheet = "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>" + response.result.substring(
                            response.result.indexOf("<styleSheet"),
                            response.result.indexOf("</styleSheet>") + "</styleSheet>".length);
                    workbook.st.raw(stylesheet);
                }

                return reporter.xlsx.responseXlsx(workbook, generationId, request, response);
            });
        }
    });
};<|endoftext|>


<commit_before>import React from 'react'
import Page from 'components/Page'
import autobind from 'autobind-decorator'

import {Alert, Table, Modal, Button, Nav, NavItem, Badge} from 'react-bootstrap'
import {Link} from 'react-router'

import {ContentForNav} from 'components/Nav'
import Breadcrumbs from 'components/Breadcrumbs'
import LinkTo from 'components/LinkTo'
import ReportCollection from 'components/ReportCollection'
import Form from 'components/Form'
import Messages from 'components/Messages'

import API from 'api'
import {Person, Organization, Position, Poam} from 'models'

import REPORTS_ICON from 'resources/reports.png'
import PEOPLE_ICON from 'resources/people.png'
import LOCATIONS_ICON from 'resources/locations.png'
import POSITIONS_ICON from 'resources/positions.png'
import ORGANIZATIONS_ICON from 'resources/organizations.png'

const QUERY_STRINGS = {
	reports: {
		pendingApprovalOf: "reports pending your approval",
		authorOrgId: "reports recently authored by your organization",
		authorId: "reports you recently authored",
	},
	organizations: "Organizations TODO",
	people: "People TODO",
}

const SEARCH_CONFIG = {
	"reports" : {
		listName : "reports: reportList",
		variableType: "ReportSearchQuery",
		fields : `id, intent, engagementDate, keyOutcomes, nextSteps, cancelledReason,
			author { id, name }
			primaryAdvisor { id, name, role, position { organization { id, shortName}}},
			primaryPrincipal { id, name, role, position { organization { id, shortName}}},
			advisorOrg { id, shortName},
			principalOrg { id, shortName},
			location { id, name, lat, lng},
			poams {id, shortName, longName}`
	},
	"persons" : {
		listName : "people: peopleList",
		variableType: "PersonSearchQuery",
		fields: "id, name, rank, emailAddress, role , position { id, name, organization { id, shortName} }"
	},
	"positions" : {
		listName: "positions: positionList",
		variableType: "PositionSearchQuery",
		fields: "id , name, type, organization { id, shortName}, person { id, name }"
	},
	"poams" : {
		listName: "poams: poamList",
		variableType: "PoamSearchQuery",
		fields: "id, shortName, longName"
	},
	"locations" : {
		listName: "locations: locationList",
		variableType: "LocationSearchQuery",
		fields : "id, name, lat, lng"
	},
	"organizations" : {
		listName: "organizations: organizationList",
		variableType: "OrganizationSearchQuery",
		fields: "id, shortName, longName"
	}
};

export default class Search extends Page {
	constructor(props) {
		super(props)

		this.state = {
			query: props.location.query.text,
			saveSearch: {show: false},
			reportsPageNum: 0,
			results: {
				reports: null,
				people: null,
				organizations: null,
				positions: null,
				location: null,
				poams: null
			},
			error: null,
			success: null
		}
	}

	fetchData(props) {
		let type = props.location.query.type
		let text = props.location.query.text

		//Any query with a field other than 'text' and 'type' is an advanced query.
		let advQuery = Object.without(props.location.query, "type", "text")
		let isAdvQuery = Object.keys(advQuery).length
		advQuery.text = text

		if (isAdvQuery) {
			// FIXME currently you have to pass page params in the query object
			// instead of the query variables
			advQuery.pageSize = 10
			advQuery.pageNum = this.state.reportsPageNum

			let config = SEARCH_CONFIG[type]
			API.query(/* GraphQL */`
					${config.listName} (f:search, query:$query) {
						pageNum, pageSize, totalCount, list { ${config.fields} }
					}
				`,
				{query: advQuery}, `($query: ${config.variableType})`
			).then(data => {
				this.setState({results: data})
			}).catch(response =>
				this.setState({error: response})
			)
		} else {
			this.setState({text})
			//TODO: escape query in the graphQL query
			API.query(/* GraphQL */`
				searchResults(f:search, q:"${text}") {
					report { totalCount, list { ${SEARCH_CONFIG.reports.fields}} }
					people { totalCount, list { ${SEARCH_CONFIG.persons.fields}} }
					positions { totalCount, list { ${SEARCH_CONFIG.positions.fields} }}
					poams { totalCount, list { ${SEARCH_CONFIG.poams.fields} }}
					locations { totalCount, list { ${SEARCH_CONFIG.locations.fields} }}
					organizations { totalCount, list { ${SEARCH_CONFIG.organizations.fields} }}
				}
			`).then(data =>
				this.setState({results: data.searchResults})
			).catch(response => {
				this.setState({error: response})
			})
		}
	}

	render() {
		let results = this.state.results
		let error = this.state.error
		let success = this.state.success

		let numReports = results.reports ? results.reports.totalCount : 0
		let numPeople = results.people ? results.people.totalCount : 0
		let numPositions = results.positions ? results.positions.totalCount : 0
		let numLocations = results.locations ? results.locations.totalCount : 0
		let numOrganizations = results.organizations ? results.organizations.totalCount : 0

		let numResults = numReports + numPeople + numPositions + numLocations + numOrganizations
		let noResults = numResults === 0

		let query = this.props.location.query
		let queryString = QUERY_STRINGS[query.type] || query.text || "TODO"

		if (typeof queryString === 'object') {
			queryString = queryString[Object.keys(query)[1]]
		}

		return (

				<Breadcrumbs items={[['Searching for ' + queryString, '/search']]} />

				<ContentForNav>

<Link to="/">< Return to previous page</Link>

							<NavItem eventKey="reports" disabled={!numReports}>
								 Reports
								{!!numReports && <Badge pullRight>{numReports}</Badge>}
							</NavItem>
							<NavItem eventKey="people" disabled={!numPeople}>
								 People
								{!!numPeople && <Badge pullRight>{numPeople}</Badge>}
							</NavItem>
							<NavItem eventKey="positions" disabled={!numPositions}>
								 Positions
								{!!numPositions && <Badge pullRight>{numPositions}</Badge>}
							</NavItem>
							<NavItem eventKey="locations" disabled={!numLocations}>
								 Locations
								{!!numLocations && <Badge pullRight>{numLocations}</Badge>}
							</NavItem>
							<NavItem eventKey="organizations" disabled={!numOrganizations}>
								 Organizations
								{!!numOrganizations && <Badge pullRight>{numOrganizations}</Badge>}
							</NavItem>

				</ContentForNav>

				<Messages error={error} success={success} />

				{noResults &&
					<Alert bsStyle="warning">
						No search results found!
					</Alert>
				}

					{this.props.location.query.text && <Button onClick={this.showSaveModal}>Save search</Button>}

				{results.reports && results.reports.totalCount > 0 &&
					<fieldset>
						<legend>Reports</legend>
						<ReportCollection paginatedReports={results.reports} goToPage={this.goToReportsPage} />
					</fieldset>
				}

				{results.people && results.people.totalCount > 0 &&
					<fieldset>
						<legend>People</legend>
						{this.renderPeople()}
					</fieldset>
				}

				{results.organizations && results.organizations.totalCount > 0 &&
					<fieldset>
						<legend>Organizations</legend>
						{this.renderOrgs()}
					</fieldset>
				}

				{results.positions && results.positions.totalCount > 0 &&
					<fieldset>
						<legend>Positions</legend>
						{this.renderPositions()}
					</fieldset>
				}

				{results.locations && results.locations.totalCount > 0 &&
					<fieldset>
						<legend>Locations</legend>
						{this.renderLocations()}
					</fieldset>
				}

				{results.poams && results.poams.totalCount > 0 &&
					<fieldset>
						<legend>PoAMs</legend>
						{this.renderPoams()}
					</fieldset>
				}

				{this.renderSaveModal()}

		)
	}

	renderPeople() {
		return

					Name
					Position
					Org

				{Person.map(this.state.results.people.list, person =>

							<LinkTo person={person}>{person.rank} {person.name}</LinkTo>

						{person.phoneNumber}
						{person.position && <LinkTo position={person.position} />}
						{person.position && person.position.organization && <LinkTo organization={person.position.organization} />}

				)}

	}

	renderOrgs() {
		return

					Name
					Description
					Type

				{Organization.map(this.state.results.organizations.list, org =>

						<LinkTo organization={org} />
						{org.longName}
						{org.type}

				)}

	}

	renderPositions() {
		return

					Name
					Org
					Current Occupant

				{Position.map(this.state.results.positions.list, pos =>

							<LinkTo position={pos} >{pos.code} {pos.name}</LinkTo>

						{pos.organization && <LinkTo organization={pos.organization} />}
						{pos.person && <LinkTo person={pos.person} />}

				)}

	}

	renderLocations() {
		return

					Name

				{this.state.results.locations.list.map(loc =>

						<LinkTo location={loc} />

				)}

	}

	renderPoams() {
		return

					Name

				{Poam.map(this.state.results.poams.list, poam =>

						<LinkTo poam={poam} >{poam.shortName} {poam.longName}</LinkTo>

				)}

	}

	renderSaveModal() {
		return <Modal show={this.state.saveSearch.show} onHide={this.closeSaveModal}>
			<Modal.Header closeButton>
				<Modal.Title>Save search</Modal.Title>
			</Modal.Header>

			<Modal.Body>
				<Form formFor={this.state.saveSearch} onChange={this.onChangeSaveSearch}
					onSubmit={this.onSubmitSaveSearch} submitText={false}>
					<Form.Field id="name" placeholder="Give this saved search a name" />
					<Button type="submit" bsStyle="primary">Save</Button>
				</Form>
			</Modal.Body>
		</Modal>
	}

	@autobind
	onChangeSaveSearch() {
		let search = this.state.saveSearch;
		this.setState({saveSearch: search})
	}

	@autobind
	onSubmitSaveSearch(event) {
		event.stopPropagation()
		event.preventDefault()

		let search = Object.without(this.state.saveSearch, "show")
		search.query = this.props.location.query.text

		API.send('/api/savedSearches/new', search, {disableSubmits: true})
			.then(response => {
				if (response.code) throw response.code
				this.setState({
					success: "Search successfully saved!",
					saveSearch: {show: false}
				})
				window.scrollTo(0, 0)
			}).catch(response => {
				this.setState({
					error: response,
					saveSearch: {show: false}
				})
				window.scrollTo(0, 0)
			})
	}

	@autobind
	showSaveModal() {
		this.setState({saveSearch: {show: true, name: ''}})
	}

	@autobind
	closeSaveModal() {
		this.setState({saveSearch: {show: false}})
	}

	@autobind
	goToReportsPage(reportsPageNum) {
		this.setState({reportsPageNum}, () => {this.fetchData(this.props)})
	}
}
<commit_msg>Fix simple text searches<commit_after>import React from 'react'
import Page from 'components/Page'
import autobind from 'autobind-decorator'

import {Alert, Table, Modal, Button, Nav, NavItem, Badge} from 'react-bootstrap'
import {Link} from 'react-router'

import {ContentForNav} from 'components/Nav'
import Breadcrumbs from 'components/Breadcrumbs'
import LinkTo from 'components/LinkTo'
import ReportCollection from 'components/ReportCollection'
import Form from 'components/Form'
import Messages from 'components/Messages'

import API from 'api'
import {Person, Organization, Position, Poam} from 'models'

import REPORTS_ICON from 'resources/reports.png'
import PEOPLE_ICON from 'resources/people.png'
import LOCATIONS_ICON from 'resources/locations.png'
import POSITIONS_ICON from 'resources/positions.png'
import ORGANIZATIONS_ICON from 'resources/organizations.png'

const QUERY_STRINGS = {
	reports: {
		pendingApprovalOf: "reports pending your approval",
		authorOrgId: "reports recently authored by your organization",
		authorId: "reports you recently authored",
	},
	organizations: "Organizations TODO",
	people: "People TODO",
}

const SEARCH_CONFIG = {
	"reports" : {
		listName : "reports: reportList",
		variableType: "ReportSearchQuery",
		fields : `id, intent, engagementDate, keyOutcomes, nextSteps, cancelledReason,
			author { id, name }
			primaryAdvisor { id, name, role, position { organization { id, shortName}}},
			primaryPrincipal { id, name, role, position { organization { id, shortName}}},
			advisorOrg { id, shortName},
			principalOrg { id, shortName},
			location { id, name, lat, lng},
			poams {id, shortName, longName}`
	},
	"persons" : {
		listName : "people: peopleList",
		variableType: "PersonSearchQuery",
		fields: "id, name, rank, emailAddress, role , position { id, name, organization { id, shortName} }"
	},
	"positions" : {
		listName: "positions: positionList",
		variableType: "PositionSearchQuery",
		fields: "id , name, type, organization { id, shortName}, person { id, name }"
	},
	"poams" : {
		listName: "poams: poamList",
		variableType: "PoamSearchQuery",
		fields: "id, shortName, longName"
	},
	"locations" : {
		listName: "locations: locationList",
		variableType: "LocationSearchQuery",
		fields : "id, name, lat, lng"
	},
	"organizations" : {
		listName: "organizations: organizationList",
		variableType: "OrganizationSearchQuery",
		fields: "id, shortName, longName"
	}
};

export default class Search extends Page {
	constructor(props) {
		super(props)

		this.state = {
			query: props.location.query.text,
			saveSearch: {show: false},
			reportsPageNum: 0,
			results: {
				reports: null,
				people: null,
				organizations: null,
				positions: null,
				location: null,
				poams: null
			},
			error: null,
			success: null
		}
	}

	fetchData(props) {
		let type = props.location.query.type
		let text = props.location.query.text

		//Any query with a field other than 'text' and 'type' is an advanced query.
		let advQuery = Object.without(props.location.query, "type", "text")
		let isAdvQuery = Object.keys(advQuery).length
		advQuery.text = text

		if (isAdvQuery) {
			// FIXME currently you have to pass page params in the query object
			// instead of the query variables
			advQuery.pageSize = 10
			advQuery.pageNum = this.state.reportsPageNum

			let config = SEARCH_CONFIG[type]
			API.query(/* GraphQL */`
					${config.listName} (f:search, query:$query) {
						pageNum, pageSize, totalCount, list { ${config.fields} }
					}
				`,
				{query: advQuery}, `($query: ${config.variableType})`
			).then(data => {
				this.setState({results: data})
			}).catch(response =>
				this.setState({error: response})
			)
		} else {
			//TODO: escape query in the graphQL query
			API.query(/* GraphQL */`
				searchResults(f:search, q:"${text}") {
					reports { pageNum, pageSize, totalCount, list { ${SEARCH_CONFIG.reports.fields}} }
					people { pageNum, pageSize, totalCount, list { ${SEARCH_CONFIG.persons.fields}} }
					positions { pageNum, pageSize, totalCount, list { ${SEARCH_CONFIG.positions.fields} }}
					poams { pageNum, pageSize, totalCount, list { ${SEARCH_CONFIG.poams.fields} }}
					locations { pageNum, pageSize, totalCount, list { ${SEARCH_CONFIG.locations.fields} }}
					organizations { pageNum, pageSize, totalCount, list { ${SEARCH_CONFIG.organizations.fields} }}
				}
			`).then(data =>
				this.setState({results: data.searchResults})
			).catch(response => {
				this.setState({error: response})
			})
		}
	}

	render() {
		let results = this.state.results
		let error = this.state.error
		let success = this.state.success

		let numReports = results.reports ? results.reports.totalCount : 0
		let numPeople = results.people ? results.people.totalCount : 0
		let numPositions = results.positions ? results.positions.totalCount : 0
		let numLocations = results.locations ? results.locations.totalCount : 0
		let numOrganizations = results.organizations ? results.organizations.totalCount : 0

		let numResults = numReports + numPeople + numPositions + numLocations + numOrganizations
		let noResults = numResults === 0

		let query = this.props.location.query
		let queryString = QUERY_STRINGS[query.type] || query.text || "TODO"

		if (typeof queryString === 'object') {
			queryString = queryString[Object.keys(query)[1]]
		}

		return (

				<Breadcrumbs items={[['Searching for ' + queryString, '/search']]} />

				<ContentForNav>

<Link to="/">< Return to previous page</Link>

							<NavItem eventKey="reports" disabled={!numReports}>
								 Reports
								{!!numReports && <Badge pullRight>{numReports}</Badge>}
							</NavItem>
							<NavItem eventKey="people" disabled={!numPeople}>
								 People
								{!!numPeople && <Badge pullRight>{numPeople}</Badge>}
							</NavItem>
							<NavItem eventKey="positions" disabled={!numPositions}>
								 Positions
								{!!numPositions && <Badge pullRight>{numPositions}</Badge>}
							</NavItem>
							<NavItem eventKey="locations" disabled={!numLocations}>
								 Locations
								{!!numLocations && <Badge pullRight>{numLocations}</Badge>}
							</NavItem>
							<NavItem eventKey="organizations" disabled={!numOrganizations}>
								 Organizations
								{!!numOrganizations && <Badge pullRight>{numOrganizations}</Badge>}
							</NavItem>

				</ContentForNav>

				<Messages error={error} success={success} />

				{noResults &&
					<Alert bsStyle="warning">
						No search results found!
					</Alert>
				}

					{this.props.location.query.text && <Button onClick={this.showSaveModal}>Save search</Button>}

				{results.reports && results.reports.totalCount > 0 &&
					<fieldset>
						<legend>Reports</legend>
						<ReportCollection paginatedReports={results.reports} goToPage={this.goToReportsPage} />
					</fieldset>
				}

				{results.people && results.people.totalCount > 0 &&
					<fieldset>
						<legend>People</legend>
						{this.renderPeople()}
					</fieldset>
				}

				{results.organizations && results.organizations.totalCount > 0 &&
					<fieldset>
						<legend>Organizations</legend>
						{this.renderOrgs()}
					</fieldset>
				}

				{results.positions && results.positions.totalCount > 0 &&
					<fieldset>
						<legend>Positions</legend>
						{this.renderPositions()}
					</fieldset>
				}

				{results.locations && results.locations.totalCount > 0 &&
					<fieldset>
						<legend>Locations</legend>
						{this.renderLocations()}
					</fieldset>
				}

				{results.poams && results.poams.totalCount > 0 &&
					<fieldset>
						<legend>PoAMs</legend>
						{this.renderPoams()}
					</fieldset>
				}

				{this.renderSaveModal()}

		)
	}

	renderPeople() {
		return

					Name
					Position
					Org

				{Person.map(this.state.results.people.list, person =>

							<LinkTo person={person}>{person.rank} {person.name}</LinkTo>

						{person.phoneNumber}
						{person.position && <LinkTo position={person.position} />}
						{person.position && person.position.organization && <LinkTo organization={person.position.organization} />}

				)}

	}

	renderOrgs() {
		return

					Name
					Description
					Type

				{Organization.map(this.state.results.organizations.list, org =>

						<LinkTo organization={org} />
						{org.longName}
						{org.type}

				)}

	}

	renderPositions() {
		return

					Name
					Org
					Current Occupant

				{Position.map(this.state.results.positions.list, pos =>

							<LinkTo position={pos} >{pos.code} {pos.name}</LinkTo>

						{pos.organization && <LinkTo organization={pos.organization} />}
						{pos.person && <LinkTo person={pos.person} />}

				)}

	}

	renderLocations() {
		return

					Name

				{this.state.results.locations.list.map(loc =>

						<LinkTo location={loc} />

				)}

	}

	renderPoams() {
		return

					Name

				{Poam.map(this.state.results.poams.list, poam =>

						<LinkTo poam={poam} >{poam.shortName} {poam.longName}</LinkTo>

				)}

	}

	renderSaveModal() {
		return <Modal show={this.state.saveSearch.show} onHide={this.closeSaveModal}>
			<Modal.Header closeButton>
				<Modal.Title>Save search</Modal.Title>
			</Modal.Header>

			<Modal.Body>
				<Form formFor={this.state.saveSearch} onChange={this.onChangeSaveSearch}
					onSubmit={this.onSubmitSaveSearch} submitText={false}>
					<Form.Field id="name" placeholder="Give this saved search a name" />
					<Button type="submit" bsStyle="primary">Save</Button>
				</Form>
			</Modal.Body>
		</Modal>
	}

	@autobind
	onChangeSaveSearch() {
		let search = this.state.saveSearch;
		this.setState({saveSearch: search})
	}

	@autobind
	onSubmitSaveSearch(event) {
		event.stopPropagation()
		event.preventDefault()

		let search = Object.without(this.state.saveSearch, "show")
		search.query = this.props.location.query.text

		API.send('/api/savedSearches/new', search, {disableSubmits: true})
			.then(response => {
				if (response.code) throw response.code
				this.setState({
					success: "Search successfully saved!",
					saveSearch: {show: false}
				})
				window.scrollTo(0, 0)
			}).catch(response => {
				this.setState({
					error: response,
					saveSearch: {show: false}
				})
				window.scrollTo(0, 0)
			})
	}

	@autobind
	showSaveModal() {
		this.setState({saveSearch: {show: true, name: ''}})
	}

	@autobind
	closeSaveModal() {
		this.setState({saveSearch: {show: false}})
	}

	@autobind
	goToReportsPage(reportsPageNum) {
		this.setState({reportsPageNum}, () => {this.fetchData(this.props)})
	}
}
<|endoftext|>


<commit_before>var config = require('config');
var FeedbackModal = require('feedback-modal');
var FilterView = require('filter-view');
var HelpMeChoose = require('help-me-choose-view');
var LeafletTransitiveLayer = require('Leaflet.TransitiveLayer');
var LocationsView = require('locations-view');
var log = require('./client/log')('planner-page');
var showMapView = require('map-view');
var OptionsView = require('options-view');
var PlannerNav = require('planner-nav');
var querystring = require('querystring');
var scrollbarSize = require('scrollbar-size');
var scrolling = require('scrolling');
var session = require('session');
var textModal = require('text-modal');
//var transitive = require('transitive');
var ua = require('user-agent');
var view = require('view');
var showWelcomeWizard = require('welcome-flow');
var showPlannerWalkthrough = require('planner-walkthrough');
var geocode = require('geocode');

var FROM = config.geocode().start_address;
var TO = config.geocode().end_address;
var isMobile = window.innerWidth <= 480;
var center = config.geocode().center.split(',').map(parseFloat);

var View = view(require('./template.html'), function(view, model) {
  view.scrollable = view.find('.scrollable');
  view.panelFooter = view.find('.footer');

  if (scrollbarSize > 0) {
    if (ua.os.name === 'Windows' || ua.browser.name !== 'Chrome')
      view.scrollable.style.marginRight = -scrollbarSize + 'px';

    // Scrollbars are fun and implemented the same on every OS/Browser...right
    if (ua.os.name === 'Windows' && ua.browser.name === 'Chrome')
      view.scrollable.style.paddingRight = scrollbarSize + 'px';
  }
});

/**
 * Expose `render`
 */

module.exports = function(ctx, next) {
  log('render');

  var plan = ctx.plan;
  var query = querystring.parse(window.location.search);

  // Set up the views
  var views = {
    'filter-view': new FilterView(plan),
    'locations-view': new LocationsView(plan),
    'options-view': new OptionsView(plan),
    'planner-nav': new PlannerNav(session)
  };

  ctx.view = new View(views);
  ctx.view.on('rendered', function() {
    // Set plan to loading
    plan.loading(true);

    for (var key in views) {
      views[key].emit('rendered', views[key]);
    }

    // Show the map
    var map = showMapView(ctx.view.find('.MapView'));

    console.log("map ->", map);

    // Create the transitive layer
    //var transitiveLayer = new LeafletTransitiveLayer(transitive);

    // Set the transitive layer
    //map.addLayer(transitiveLayer);

    // Update map on plan change
    updateMapOnPlanChange(plan, map);

    //map.on('click', function (e) {
    //      var from = plan.from_ll();
    //      var to = plan.to_ll();
    //      if (!plan.coordinateIsValid(from)) {
    //        plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: (plan.to_ll() ? plan.to_ll().lat : 0),
    //          place_lon: (plan.to_ll() ? plan.to_ll().lng : 0),
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('from', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      } else if (!plan.coordinateIsValid(to)) {
    //    plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: plan.from_ll().lat,
    //          place_lon: plan.from_ll().lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('to', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      }
    //});

    // Clear plan & cookies for now, plan will re-save automatically on save
      var from = plan.from_ll();
      var to = plan.to_ll();
      //plan.clearStore();

    // If it's a shared URL or welcome is complete skip the welcome screen
    console.log("query ->", query);
    if ((query.from && query.to)) {
      showQuery(query);
    } else {
      console.log("plan.coordinateIsValid(from)", plan.coordinateIsValid(from));
      console.log("plan.coordinateIsValid(to)", plan.coordinateIsValid(to));

      if (plan.coordinateIsValid(from) && plan.coordinateIsValid(to)) {
          plan.setAddresses(
            from.lng + ',' + from.lat, // from
            to.lng + ',' + to.lat, // to
            function (err, res) {
              plan.updateRoutes();
              console.log("aqui la data del plan 4 ->", plan.dataplan);
            }
          );
          plan.updateRoutes();
          console.log("aqui la data del plan 3 ->", plan.dataplan);
      } else {
          console.log(from);
          console.log(to);
          plan.loading(false);
      }
    }
  });

  plan.on('updating options', function() {
    ctx.view.panelFooter.classList.add('hidden');
  });

  plan.on('updating options complete', function(res) {
    if (res && !res.err) ctx.view.panelFooter.classList.remove('hidden');
  });

  next();
};

/**
 * Reverse Commute
 */

View.prototype.reverseCommute = function(e) {
  e.preventDefault();
  var plan = session.plan();
  plan.set({
    from: plan.to(),
    from_id: plan.to_id(),
    from_ll: plan.to_ll(),
    to: plan.from(),
    to_id: plan.from_id(),
    to_ll: plan.from_ll()
  });

  plan.updateRoutes();

  console.log("aqui la data del plan 5 ->", plan.dataplan);
};

/**
 * Scroll
 */

View.prototype.scroll = function(e) {
  e.preventDefault();
  this.scrollable.scrollTop += (this.scrollable.scrollHeight / 5);
};

/**
 * On submit
 */

View.prototype.onsubmit = function(e) {
  e.preventDefault();
};

/**
 * Help Me Choose
 */

View.prototype.helpMeChoose = function(e) {
  HelpMeChoose(session.plan().options()).show();
};

/**
 * Show feedback modal
 */
View.prototype.feedback = function(e) {
  e.preventDefault();
  FeedbackModal().show();
};

/**
 * Hide Side Panel
 */

View.prototype.hideSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(' + width + 'px, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding': '0'
  });

  setTimeout(function () {
    map.invalidateSize();
  }, 2100)
};

/**
 * Show Side Panel
 */

View.prototype.showSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(0, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding-right': '320px'
  });

  setTimeout(function () {
    var plan = session.plan();
    map.invalidateSize();

    plan = session.plan();
    plan.updateRoutes();
    //transitive.updateData(plan.journey());
  }, 2100)
};

/**
 * Show Journey
 */

function showQuery(query) {
  var plan = session.plan();
  // If no querystring, see if we have them in the plan already
  var from = query.from || plan.from() || FROM;
  var to = query.to || plan.to() || TO;
  var sameAddresses = from === plan.from() && to === plan.to();

  // Set plan from querystring
  if (query.modes) plan.setModes(query.modes);
  if (query.start_time !== undefined) plan.start_time(parseInt(query.start_time, 10));
  if (query.end_time !== undefined) plan.end_time(parseInt(query.end_time, 10));
  if (query.days !== undefined) plan.days(query.days);

  // If has valid coordinates, load
  if (plan.validCoordinates() && sameAddresses) {
    plan.journey({
      places: plan.generatePlaces()
    });
    plan.updateRoutes();

    console.log("aqui la data del plan 1 ->", plan.dataplan);
  } else {
      if (!plan.validCoordinates()) {
	  plan.loading(false);
	  return;
      } else {
    // Set addresses and update the routes
    plan.setAddresses(from, to, function(err) {
      if (err) {
        log.error('%e', err);
      } else {
        plan.journey({
          places: plan.generatePlaces()
        });
        plan.updateRoutes();

        console.log("aqui la data del plan 2 ->", plan.dataplan);
      }
    });
}
  }
}

/**
 * Update Map on plan change
 */

function updateMapOnPlanChange(plan, map) {
  // Register plan update events
    /*
    for (i in map._layers) {
        if (map._layers[i].options.format == undefined) {
            try {
                map.removeLayer(map._layers[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }
        }
    }
    */

    //map.removeLayer(polyline);
/*

  for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }
  */

  plan.on('change journey', function(journey) {

  var polyline_creadas = showMapView.getpolyline_creadas();
    //console.log("poliline credas ->", polyline_creadas);
    //console.log("llamamos sin evento ->", showMapView.polyline_creadas);

    for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }

    showMapView.polyline_creadas = [];
    if (journey && !isMobile) {
      try {

        log('updating data');

        var datajourney = journey;
        if (!(plan.dataplan === undefined)) {
            var itineraries = plan.dataplan.itineraries;
            showMapView.marker_map([plan.dataplan.from.lat,plan.dataplan.from.lon],[plan.dataplan.to.lat,plan.dataplan.to.lon], map);
            for (i = 0; i < itineraries.length; i++) {
                for (ii=0; ii < itineraries[i].legs.length; ii++) {
                  var circle = [itineraries[i].legs[ii].to.lat, itineraries[i].legs[ii].to.lon, itineraries[i].legs[ii].to.name];
                  console.log("circle", circle);
                  showMapView.marker_map_point(circle, map);
                  showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                }
            }
          console.log("entre if ")
        }else{
            var sesion_plan = JSON.parse(localStorage.getItem('dataplan'));
            if(!(sesion_plan === null)) {
                var itineraries = sesion_plan.itineraries;

                showMapView.marker_map([sesion_plan.from.lat,sesion_plan.from.lon],[sesion_plan.to.lat,sesion_plan.to.lon], map);

                for (i = 0; i < itineraries.length; i++) {
                    for (ii=0; ii < itineraries[i].legs.length; ii++) {
                      showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                    }
                }
            }

        }
      } catch (e) {
        console.log("entre cath")
	    map.setView([center[1], center[0]], config.geocode().zoom);
      }

    }
  });
}
<commit_msg>adding html layer color<commit_after>var config = require('config');
var FeedbackModal = require('feedback-modal');
var FilterView = require('filter-view');
var HelpMeChoose = require('help-me-choose-view');
var LeafletTransitiveLayer = require('Leaflet.TransitiveLayer');
var LocationsView = require('locations-view');
var log = require('./client/log')('planner-page');
var showMapView = require('map-view');
var OptionsView = require('options-view');
var PlannerNav = require('planner-nav');
var querystring = require('querystring');
var scrollbarSize = require('scrollbar-size');
var scrolling = require('scrolling');
var session = require('session');
var textModal = require('text-modal');
//var transitive = require('transitive');
var ua = require('user-agent');
var view = require('view');
var showWelcomeWizard = require('welcome-flow');
var showPlannerWalkthrough = require('planner-walkthrough');
var geocode = require('geocode');

var FROM = config.geocode().start_address;
var TO = config.geocode().end_address;
var isMobile = window.innerWidth <= 480;
var center = config.geocode().center.split(',').map(parseFloat);

var View = view(require('./template.html'), function(view, model) {
  view.scrollable = view.find('.scrollable');
  view.panelFooter = view.find('.footer');

  if (scrollbarSize > 0) {
    if (ua.os.name === 'Windows' || ua.browser.name !== 'Chrome')
      view.scrollable.style.marginRight = -scrollbarSize + 'px';

    // Scrollbars are fun and implemented the same on every OS/Browser...right
    if (ua.os.name === 'Windows' && ua.browser.name === 'Chrome')
      view.scrollable.style.paddingRight = scrollbarSize + 'px';
  }
});

/**
 * Expose `render`
 */

module.exports = function(ctx, next) {
  log('render');

  var plan = ctx.plan;
  var query = querystring.parse(window.location.search);

  // Set up the views
  var views = {
    'filter-view': new FilterView(plan),
    'locations-view': new LocationsView(plan),
    'options-view': new OptionsView(plan),
    'planner-nav': new PlannerNav(session)
  };

  ctx.view = new View(views);
  ctx.view.on('rendered', function() {
    // Set plan to loading
    plan.loading(true);

    for (var key in views) {
      views[key].emit('rendered', views[key]);
    }

    // Show the map
    var map = showMapView(ctx.view.find('.MapView'));

    console.log("map ->", map);

    // Create the transitive layer
    //var transitiveLayer = new LeafletTransitiveLayer(transitive);

    // Set the transitive layer
    //map.addLayer(transitiveLayer);

    // Update map on plan change
    updateMapOnPlanChange(plan, map);

    //map.on('click', function (e) {
    //      var from = plan.from_ll();
    //      var to = plan.to_ll();
    //      if (!plan.coordinateIsValid(from)) {
    //        plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: (plan.to_ll() ? plan.to_ll().lat : 0),
    //          place_lon: (plan.to_ll() ? plan.to_ll().lng : 0),
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('from', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      } else if (!plan.coordinateIsValid(to)) {
    //    plan.journey({
    //      places: [
    //        {
    //          place_id: 'from',
    //          place_lat: plan.from_ll().lat,
    //          place_lon: plan.from_ll().lng,
    //          place_name: 'From'
    //        },
    //        {
    //          place_id: 'to',
    //          place_lat: e.latlng.lat,
    //          place_lon: e.latlng.lng,
    //          place_name: 'To'
    //        }
    //      ]
    //    });
    //    plan.setAddress('to', e.latlng.lng + ',' + e.latlng.lat, function (err, res) {
    //        plan.updateRoutes();
    //    });
    //      }
    //});

    // Clear plan & cookies for now, plan will re-save automatically on save
      var from = plan.from_ll();
      var to = plan.to_ll();
      //plan.clearStore();

    // If it's a shared URL or welcome is complete skip the welcome screen
    console.log("query ->", query);
    if ((query.from && query.to)) {
      showQuery(query);
    } else {
      console.log("plan.coordinateIsValid(from)", plan.coordinateIsValid(from));
      console.log("plan.coordinateIsValid(to)", plan.coordinateIsValid(to));

      if (plan.coordinateIsValid(from) && plan.coordinateIsValid(to)) {
          plan.setAddresses(
            from.lng + ',' + from.lat, // from
            to.lng + ',' + to.lat, // to
            function (err, res) {
              plan.updateRoutes();
              console.log("aqui la data del plan 4 ->", plan.dataplan);
            }
          );
          plan.updateRoutes();
          console.log("aqui la data del plan 3 ->", plan.dataplan);
      } else {
          console.log(from);
          console.log(to);
          plan.loading(false);
      }
    }
  });

  plan.on('updating options', function() {
    ctx.view.panelFooter.classList.add('hidden');
  });

  plan.on('updating options complete', function(res) {
    if (res && !res.err) ctx.view.panelFooter.classList.remove('hidden');
  });

  next();
};

/**
 * Reverse Commute
 */

View.prototype.reverseCommute = function(e) {
  e.preventDefault();
  var plan = session.plan();
  plan.set({
    from: plan.to(),
    from_id: plan.to_id(),
    from_ll: plan.to_ll(),
    to: plan.from(),
    to_id: plan.from_id(),
    to_ll: plan.from_ll()
  });

  plan.updateRoutes();

  console.log("aqui la data del plan 5 ->", plan.dataplan);
};

/**
 * Scroll
 */

View.prototype.scroll = function(e) {
  e.preventDefault();
  this.scrollable.scrollTop += (this.scrollable.scrollHeight / 5);
};

/**
 * On submit
 */

View.prototype.onsubmit = function(e) {
  e.preventDefault();
};

/**
 * Help Me Choose
 */

View.prototype.helpMeChoose = function(e) {
  HelpMeChoose(session.plan().options()).show();
};

/**
 * Show feedback modal
 */
View.prototype.feedback = function(e) {
  e.preventDefault();
  FeedbackModal().show();
};

/**
 * Hide Side Panel
 */

View.prototype.hideSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(' + width + 'px, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding': '0'
  });

  setTimeout(function () {
    map.invalidateSize();
  }, 2100)
};

/**
 * Show Side Panel
 */

View.prototype.showSidePanel = function (e) {
  var sidePanel = $('.SidePanel');
  var fullscreen = $('.fullscreen');
  var width = sidePanel.width();
  var map = showMapView.getMap();

  sidePanel.css({
    'transition': 'transform 2s',
    '-webkit-transition': '-webkit-transform 2s',
    'transform': 'translate3d(0, 0, 0)'
  });

  fullscreen.css({
    'transition': 'padding 2s',
    'padding-right': '320px'
  });

  setTimeout(function () {
    var plan = session.plan();
    map.invalidateSize();

    plan = session.plan();
    plan.updateRoutes();
    //transitive.updateData(plan.journey());
  }, 2100)
};

/**
 * Show Journey
 */

function showQuery(query) {
  var plan = session.plan();
  // If no querystring, see if we have them in the plan already
  var from = query.from || plan.from() || FROM;
  var to = query.to || plan.to() || TO;
  var sameAddresses = from === plan.from() && to === plan.to();

  // Set plan from querystring
  if (query.modes) plan.setModes(query.modes);
  if (query.start_time !== undefined) plan.start_time(parseInt(query.start_time, 10));
  if (query.end_time !== undefined) plan.end_time(parseInt(query.end_time, 10));
  if (query.days !== undefined) plan.days(query.days);

  // If has valid coordinates, load
  if (plan.validCoordinates() && sameAddresses) {
    plan.journey({
      places: plan.generatePlaces()
    });
    plan.updateRoutes();

    console.log("aqui la data del plan 1 ->", plan.dataplan);
  } else {
      if (!plan.validCoordinates()) {
	  plan.loading(false);
	  return;
      } else {
    // Set addresses and update the routes
    plan.setAddresses(from, to, function(err) {
      if (err) {
        log.error('%e', err);
      } else {
        plan.journey({
          places: plan.generatePlaces()
        });
        plan.updateRoutes();

        console.log("aqui la data del plan 2 ->", plan.dataplan);
      }
    });
}
  }
}

/**
 * Update Map on plan change
 */

function updateMapOnPlanChange(plan, map) {
  // Register plan update events
    /*
    for (i in map._layers) {
        if (map._layers[i].options.format == undefined) {
            try {
                map.removeLayer(map._layers[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }
        }
    }
    */

    //map.removeLayer(polyline);
/*

  for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }
  */

  plan.on('change journey', function(journey) {

  var polyline_creadas = showMapView.getpolyline_creadas();
    //console.log("poliline credas ->", polyline_creadas);
    //console.log("llamamos sin evento ->", showMapView.polyline_creadas);

    for (i in polyline_creadas) {
        try {
                map.removeLayer(polyline_creadas[i]);
            } catch (e) {
                console.log("problem with " + e + map._layers[i]);
            }

  }

    showMapView.polyline_creadas = [];
    if (journey && !isMobile) {
      try {

        log('updating data');

        var datajourney = journey;
        if (!(plan.dataplan === undefined)) {
            var itineraries = plan.dataplan.itineraries;
            showMapView.marker_map([plan.dataplan.from.lat,plan.dataplan.from.lon],[plan.dataplan.to.lat,plan.dataplan.to.lon], map);
            for (i = 0; i < itineraries.length; i++) {
                for (ii=0; ii < itineraries[i].legs.length; ii++) {
                  console.log("itineraries[i].legs[ii]", itineraries[i].legs[ii]);
                  var circle = [itineraries[i].legs[ii].to.lat, itineraries[i].legs[ii].to.lon, itineraries[i].legs[ii].to.name];
                  console.log("circle", circle);
                  showMapView.marker_map_point(circle, map);
                  showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                }
            }
          console.log("entre if ")
        }else{
            var sesion_plan = JSON.parse(localStorage.getItem('dataplan'));
            if(!(sesion_plan === null)) {
                var itineraries = sesion_plan.itineraries;

                showMapView.marker_map([sesion_plan.from.lat,sesion_plan.from.lon],[sesion_plan.to.lat,sesion_plan.to.lon], map);

                for (i = 0; i < itineraries.length; i++) {
                    for (ii=0; ii < itineraries[i].legs.length; ii++) {
                      showMapView.drawRouteAmigo(itineraries[i].legs[ii].legGeometry.points, itineraries[i].legs[ii].mode);
                    }
                }
            }

        }
      } catch (e) {
        console.log("entre cath")
	    map.setView([center[1], center[0]], config.geocode().zoom);
      }

    }
  });
}
<|endoftext|>


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

// copies the resources into the webapp directory.
//

// Languages are listed manually so we can choose when to include
// a translation in the app (because having a translation with only
// 3 strings translated is just frustrating)
// This could readily be automated, but it's nice to explicitly
// control when new languages are available.
const INCLUDE_LANGS = [
    {'value': 'bg', 'label': 'Български'},
    {'value': 'ca', 'label': 'Català'},
    {'value': 'cs', 'label': 'čeština'},
    {'value': 'da', 'label': 'Dansk'},
    {'value': 'de_DE', 'label': 'Deutsch'},
    {'value': 'el', 'label': 'Ελληνικά'},
    {'value': 'en_EN', 'label': 'English'},
    {'value': 'en_US', 'label': 'English (US)'},
    {'value': 'eo', 'label': 'Esperanto'},
    {'value': 'es', 'label': 'Español'},
    {'value': 'eu', 'label': 'Euskara'},
    {'value': 'fi', 'label': 'Suomi'},
    {'value': 'fr', 'label': 'Français'},
    {'value': 'gl', 'label': 'Galego'},
    {'value': 'hu', 'label': 'Magyar'},
    {'value': 'ko', 'label': '한국어'},
    {'value': 'lv', 'label': 'Latviešu'},
    {'value': 'nb_NO', 'label': 'Norwegian Bokmål'},
    {'value': 'nl', 'label': 'Nederlands'},
    {'value': 'pl', 'label': 'Polski'},
    {'value': 'pt', 'label': 'Português'},
    {'value': 'pt_BR', 'label': 'Português do Brasil'},
    {'value': 'ru', 'label': 'Русский'},
    {'value': 'sk', 'label': 'Slovenčina'},
    {'value': 'sr', 'label': 'српски'},
    {'value': 'sv', 'label': 'Svenska'},
    {'value': 'te', 'label': 'తెలుగు'},
    {'value': 'th', 'label': 'ไทย'},
    {'value': 'tr', 'label': 'Türk'},
    {'value': 'zh_Hans', 'label': '简体中文'}, // simplified chinese
    {'value': 'zh_Hant', 'label': '繁體中文'}, // traditional chinese
];

// cpx includes globbed parts of the filename in the destination, but excludes
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
// "dest/b/...".
const COPY_LIST = [
    ["res/manifest.json", "webapp"],
    ["res/home.html", "webapp"],
    ["res/home-status.html", "webapp"],
    ["res/home/**", "webapp/home"],
    ["res/vector-icons/**", "webapp/vector-icons"],
    ["node_modules/matrix-react-sdk/res/{fonts,img,themes}/**", "webapp"],
    ["res/themes/**", "webapp/themes"],
    ["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
    ["node_modules/emojione/assets/png/*", "webapp/emojione/png/"],
    ["./config.json", "webapp", { directwatch: 1 }],
];

INCLUDE_LANGS.forEach(function(l) {
    COPY_LIST.push([
        l.value, "webapp/i18n/", { lang: 1 },
    ]);
});

const parseArgs = require('minimist');
const Cpx = require('cpx');
const chokidar = require('chokidar');
const fs = require('fs');
const rimraf = require('rimraf');

const argv = parseArgs(
    process.argv.slice(2), {}
);

var watch = argv.w;
var verbose = argv.v;

function errCheck(err) {
    if (err) {
        console.error(err.message);
        process.exit(1);
    }
}

// Check if webapp exists
if (!fs.existsSync('webapp')) {
    fs.mkdirSync('webapp');
}
// Check if i18n exists
if (!fs.existsSync('webapp/i18n/')) {
    fs.mkdirSync('webapp/i18n/');
}

function next(i, err) {
    errCheck(err);

    if (i >= COPY_LIST.length) {
        return;
    }

    const ent = COPY_LIST[i];
    const source = ent[0];
    const dest = ent[1];
    const opts = ent[2] || {};
    let cpx = undefined;

    if (!opts.lang) {
        cpx = new Cpx.Cpx(source, dest);
    }

    if (verbose && cpx) {
        cpx.on("copy", (event) => {
            console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`);
        });
        cpx.on("remove", (event) => {
            console.log(`Removed: ${event.path}`);
        });
    }

    const cb = (err) => { next(i + 1, err) };

    if (watch) {
        if (opts.directwatch) {
            // cpx -w creates a watcher for the parent of any files specified,
            // which in the case of config.json is '.', which inevitably takes
            // ages to crawl. So we create our own watcher on the files
            // instead.
            const copy = () => { cpx.copy(errCheck) };
            chokidar.watch(source)
                .on('add', copy)
                .on('change', copy)
                .on('ready', cb)
                .on('error', errCheck);
        } else if (opts.lang) {
            const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + source + '.json';
            const riotWebFile = 'src/i18n/strings/' + source + '.json';

            // XXX: Use a debounce because for some reason if we read the language
            // file immediately after the FS event is received, the file contents
            // appears empty. Possibly https://github.com/nodejs/node/issues/6112
            let makeLangDebouncer;
            const makeLang = () => {
                if (makeLangDebouncer) {
                    clearTimeout(makeLangDebouncer);
                }
                makeLangDebouncer = setTimeout(() => {
                    genLangFile(source, dest);
                }, 500);
            };

            [reactSdkFile, riotWebFile].forEach(function(f) {
                chokidar.watch(f)
                    .on('add', makeLang)
                    .on('change', makeLang)
                    //.on('ready', cb)  We'd have to do this when both files are ready
                    .on('error', errCheck);
            });
            next(i + 1, err);
        } else {
            cpx.on('watch-ready', cb);
            cpx.on("watch-error", cb);
            cpx.watch();
        }
    } else if (opts.lang) {
        genLangFile(source, dest);
        next(i + 1, err);
    } else {
        cpx.copy(cb);
    }
}

function genLangFile(lang, dest) {
    const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json';
    const riotWebFile = 'src/i18n/strings/' + lang + '.json';

    let translations = {};
    [reactSdkFile, riotWebFile].forEach(function(f) {
        if (fs.existsSync(f)) {
            try {
                Object.assign(
                    translations,
                    JSON.parse(fs.readFileSync(f).toString())
                );
            } catch (e) {
                console.error("Failed: " + f, e);
                throw e;
            }
        }
    });

    translations = weblateToCounterpart(translations);

    fs.writeFileSync(dest + lang + '.json', JSON.stringify(translations, null, 4));
    if (verbose) {
        console.log("Generated language file: " + lang);
    }
}

function genLangList() {
    const languages = {};
    INCLUDE_LANGS.forEach(function(lang) {
        const normalizedLanguage = lang.value.toLowerCase().replace("_", "-");
        const languageParts = normalizedLanguage.split('-');
        if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
            languages[languageParts[0]] = {'fileName': lang.value + '.json', 'label': lang.label};
        } else {
            languages[normalizedLanguage] = {'fileName': lang.value + '.json', 'label': lang.label};
        }
    });
    fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4), function(err) {
        if (err) {
            console.error("Copy Error occured: " + err);
            throw new Error("Failed to generate languages.json");
        }
    });
    if (verbose) {
        console.log("Generated languages.json");
    }
}

/**
 * Convert translation key from weblate format
 * (which only supports a single level) to counterpart
 * which requires object values for 'count' translations.
 *
 * eg.
 *     "there are %(count)s badgers|one": "a badger",
 *     "there are %(count)s badgers|other": "%(count)s badgers"
 *   becomes
 *     "there are %(count)s badgers": {
 *         "one": "a badger",
 *         "other": "%(count)s badgers"
 *     }
 */
function weblateToCounterpart(inTrs) {
    const outTrs = {};

    for (const key of Object.keys(inTrs)) {
        const keyParts = key.split('|', 2);
        if (keyParts.length === 2) {
            let obj = outTrs[keyParts[0]];
            if (obj === undefined) {
                obj = {};
                outTrs[keyParts[0]] = obj;
            }
            obj[keyParts[1]] = inTrs[key];
        } else {
            outTrs[key] = inTrs[key];
        }
    }

    return outTrs;
}

genLangList();
next(0);
<commit_msg>Copy media from react-sdk<commit_after>#!/usr/bin/env node

// copies the resources into the webapp directory.
//

// Languages are listed manually so we can choose when to include
// a translation in the app (because having a translation with only
// 3 strings translated is just frustrating)
// This could readily be automated, but it's nice to explicitly
// control when new languages are available.
const INCLUDE_LANGS = [
    {'value': 'bg', 'label': 'Български'},
    {'value': 'ca', 'label': 'Català'},
    {'value': 'cs', 'label': 'čeština'},
    {'value': 'da', 'label': 'Dansk'},
    {'value': 'de_DE', 'label': 'Deutsch'},
    {'value': 'el', 'label': 'Ελληνικά'},
    {'value': 'en_EN', 'label': 'English'},
    {'value': 'en_US', 'label': 'English (US)'},
    {'value': 'eo', 'label': 'Esperanto'},
    {'value': 'es', 'label': 'Español'},
    {'value': 'eu', 'label': 'Euskara'},
    {'value': 'fi', 'label': 'Suomi'},
    {'value': 'fr', 'label': 'Français'},
    {'value': 'gl', 'label': 'Galego'},
    {'value': 'hu', 'label': 'Magyar'},
    {'value': 'ko', 'label': '한국어'},
    {'value': 'lv', 'label': 'Latviešu'},
    {'value': 'nb_NO', 'label': 'Norwegian Bokmål'},
    {'value': 'nl', 'label': 'Nederlands'},
    {'value': 'pl', 'label': 'Polski'},
    {'value': 'pt', 'label': 'Português'},
    {'value': 'pt_BR', 'label': 'Português do Brasil'},
    {'value': 'ru', 'label': 'Русский'},
    {'value': 'sk', 'label': 'Slovenčina'},
    {'value': 'sr', 'label': 'српски'},
    {'value': 'sv', 'label': 'Svenska'},
    {'value': 'te', 'label': 'తెలుగు'},
    {'value': 'th', 'label': 'ไทย'},
    {'value': 'tr', 'label': 'Türk'},
    {'value': 'zh_Hans', 'label': '简体中文'}, // simplified chinese
    {'value': 'zh_Hant', 'label': '繁體中文'}, // traditional chinese
];

// cpx includes globbed parts of the filename in the destination, but excludes
// common parents. Hence, "res/{a,b}/**": the output will be "dest/a/..." and
// "dest/b/...".
const COPY_LIST = [
    ["res/manifest.json", "webapp"],
    ["res/home.html", "webapp"],
    ["res/home-status.html", "webapp"],
    ["res/home/**", "webapp/home"],
    ["res/vector-icons/**", "webapp/vector-icons"],
    ["node_modules/matrix-react-sdk/res/{fonts,img,themes,media}/**", "webapp"],
    ["res/themes/**", "webapp/themes"],
    ["node_modules/emojione/assets/svg/*", "webapp/emojione/svg/"],
    ["node_modules/emojione/assets/png/*", "webapp/emojione/png/"],
    ["./config.json", "webapp", { directwatch: 1 }],
];

INCLUDE_LANGS.forEach(function(l) {
    COPY_LIST.push([
        l.value, "webapp/i18n/", { lang: 1 },
    ]);
});

const parseArgs = require('minimist');
const Cpx = require('cpx');
const chokidar = require('chokidar');
const fs = require('fs');
const rimraf = require('rimraf');

const argv = parseArgs(
    process.argv.slice(2), {}
);

var watch = argv.w;
var verbose = argv.v;

function errCheck(err) {
    if (err) {
        console.error(err.message);
        process.exit(1);
    }
}

// Check if webapp exists
if (!fs.existsSync('webapp')) {
    fs.mkdirSync('webapp');
}
// Check if i18n exists
if (!fs.existsSync('webapp/i18n/')) {
    fs.mkdirSync('webapp/i18n/');
}

function next(i, err) {
    errCheck(err);

    if (i >= COPY_LIST.length) {
        return;
    }

    const ent = COPY_LIST[i];
    const source = ent[0];
    const dest = ent[1];
    const opts = ent[2] || {};
    let cpx = undefined;

    if (!opts.lang) {
        cpx = new Cpx.Cpx(source, dest);
    }

    if (verbose && cpx) {
        cpx.on("copy", (event) => {
            console.log(`Copied: ${event.srcPath} --> ${event.dstPath}`);
        });
        cpx.on("remove", (event) => {
            console.log(`Removed: ${event.path}`);
        });
    }

    const cb = (err) => { next(i + 1, err) };

    if (watch) {
        if (opts.directwatch) {
            // cpx -w creates a watcher for the parent of any files specified,
            // which in the case of config.json is '.', which inevitably takes
            // ages to crawl. So we create our own watcher on the files
            // instead.
            const copy = () => { cpx.copy(errCheck) };
            chokidar.watch(source)
                .on('add', copy)
                .on('change', copy)
                .on('ready', cb)
                .on('error', errCheck);
        } else if (opts.lang) {
            const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + source + '.json';
            const riotWebFile = 'src/i18n/strings/' + source + '.json';

            // XXX: Use a debounce because for some reason if we read the language
            // file immediately after the FS event is received, the file contents
            // appears empty. Possibly https://github.com/nodejs/node/issues/6112
            let makeLangDebouncer;
            const makeLang = () => {
                if (makeLangDebouncer) {
                    clearTimeout(makeLangDebouncer);
                }
                makeLangDebouncer = setTimeout(() => {
                    genLangFile(source, dest);
                }, 500);
            };

            [reactSdkFile, riotWebFile].forEach(function(f) {
                chokidar.watch(f)
                    .on('add', makeLang)
                    .on('change', makeLang)
                    //.on('ready', cb)  We'd have to do this when both files are ready
                    .on('error', errCheck);
            });
            next(i + 1, err);
        } else {
            cpx.on('watch-ready', cb);
            cpx.on("watch-error", cb);
            cpx.watch();
        }
    } else if (opts.lang) {
        genLangFile(source, dest);
        next(i + 1, err);
    } else {
        cpx.copy(cb);
    }
}

function genLangFile(lang, dest) {
    const reactSdkFile = 'node_modules/matrix-react-sdk/src/i18n/strings/' + lang + '.json';
    const riotWebFile = 'src/i18n/strings/' + lang + '.json';

    let translations = {};
    [reactSdkFile, riotWebFile].forEach(function(f) {
        if (fs.existsSync(f)) {
            try {
                Object.assign(
                    translations,
                    JSON.parse(fs.readFileSync(f).toString())
                );
            } catch (e) {
                console.error("Failed: " + f, e);
                throw e;
            }
        }
    });

    translations = weblateToCounterpart(translations);

    fs.writeFileSync(dest + lang + '.json', JSON.stringify(translations, null, 4));
    if (verbose) {
        console.log("Generated language file: " + lang);
    }
}

function genLangList() {
    const languages = {};
    INCLUDE_LANGS.forEach(function(lang) {
        const normalizedLanguage = lang.value.toLowerCase().replace("_", "-");
        const languageParts = normalizedLanguage.split('-');
        if (languageParts.length == 2 && languageParts[0] == languageParts[1]) {
            languages[languageParts[0]] = {'fileName': lang.value + '.json', 'label': lang.label};
        } else {
            languages[normalizedLanguage] = {'fileName': lang.value + '.json', 'label': lang.label};
        }
    });
    fs.writeFile('webapp/i18n/languages.json', JSON.stringify(languages, null, 4), function(err) {
        if (err) {
            console.error("Copy Error occured: " + err);
            throw new Error("Failed to generate languages.json");
        }
    });
    if (verbose) {
        console.log("Generated languages.json");
    }
}

/**
 * Convert translation key from weblate format
 * (which only supports a single level) to counterpart
 * which requires object values for 'count' translations.
 *
 * eg.
 *     "there are %(count)s badgers|one": "a badger",
 *     "there are %(count)s badgers|other": "%(count)s badgers"
 *   becomes
 *     "there are %(count)s badgers": {
 *         "one": "a badger",
 *         "other": "%(count)s badgers"
 *     }
 */
function weblateToCounterpart(inTrs) {
    const outTrs = {};

    for (const key of Object.keys(inTrs)) {
        const keyParts = key.split('|', 2);
        if (keyParts.length === 2) {
            let obj = outTrs[keyParts[0]];
            if (obj === undefined) {
                obj = {};
                outTrs[keyParts[0]] = obj;
            }
            obj[keyParts[1]] = inTrs[key];
        } else {
            outTrs[key] = inTrs[key];
        }
    }

    return outTrs;
}

genLangList();
next(0);
<|endoftext|>


<commit_before>import React from 'react';
import Button from '@material-ui/core/Button';
import { compose, withState, withHandlers } from 'recompose';
import { Redirect } from 'react-router';
import { withApollo, graphql } from 'react-apollo';
import UserQuery from '../components/UserQuery';
import SIGNUP_MUTATION from '../graphql/SignupMutation.graphql';
import LOGIN_MUTATION from '../graphql/LoginMutation.graphql';
import { AUTH_TOKEN } from '../constants';

const Login = ({
  name,
  onChangeName,
  password,
  onChangePassword,
  onLogin,
  onSignup,
}) => {
  return localStorage.getItem(AUTH_TOKEN) ? (
    <UserQuery network={true}>{() => <Redirect to="/" />}</UserQuery>
  ) : (
    <div>
      <input
        placeholder="username"
        value={name}
        onChange={onChangeName}
        type="text"
        style={{
          color: '#000000',
          maxWidth: '80px',
        }}
      />
      <input
        placeholder="password"
        value={password}
        onChange={onChangePassword}
        type="password"
        style={{
          color: '#000000',
          maxWidth: '80px',
        }}
      />
      <Button size="small" onClick={onLogin}>
        Login
      </Button>
      <Button size="small" onClick={onSignup}>
        Sign Up
      </Button>
    </div>
  );
};

const enhanced = compose(
  withApollo,
  graphql(SIGNUP_MUTATION, { name: 'signupMutation' }),
  graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
  withState('name', 'changeName', ''),
  withState('password', 'changePassword', ''),
  withHandlers({
    onChangeName: ({ changeName }) => e => changeName(e.target.value),
    onChangePassword: ({ changePassword }) => e =>
      changePassword(e.target.value),
    onLogin: ({
      name,
      password,
      changeName,
      changePassword,
      loginMutation,
    }) => async () => {
      const result = await loginMutation({
        variables: {
          name,
          password,
        },
      });
      localStorage.setItem(AUTH_TOKEN, result.data.login.token);
      changeName('');
      changePassword('');
    },
    onSignup: ({
      name,
      password,
      changeName,
      changePassword,
      signupMutation,
    }) => async () => {
      const result = await signupMutation({
        variables: {
          name,
          password,
        },
      });
      localStorage.setItem(AUTH_TOKEN, result.data.login.token);
      changeName('');
      changePassword('');
    },
  })
)(Login);

export default enhanced;
<commit_msg>make login page pretty<commit_after>import React from 'react';
import styled from 'styled-components';
import Button from '@material-ui/core/Button';
import TextField from '@material-ui/core/TextField';
import { compose, withState, withHandlers } from 'recompose';
import { Redirect } from 'react-router';
import { withApollo, graphql } from 'react-apollo';
import UserQuery from '../components/UserQuery';
import SIGNUP_MUTATION from '../graphql/SignupMutation.graphql';
import LOGIN_MUTATION from '../graphql/LoginMutation.graphql';
import { AUTH_TOKEN } from '../constants';

const Container = styled.div`
  display: flex;
  flex-direction: column;
  height: 50%;
  width: 30%;
  justify-content: space-around;
`;

const Login = ({
  name,
  onChangeName,
  password,
  onChangePassword,
  onLogin,
  onSignup,
}) => {
  return localStorage.getItem(AUTH_TOKEN) ? (
    <UserQuery network={true}>{() => <Redirect to="/" />}</UserQuery>
  ) : (
    <Container>
      <TextField label="Username" value={name} onChange={onChangeName} />
      <TextField
        label="Password"
        type="password"
        value={password}
        onChange={onChangePassword}
      />
      <Button
        size="large"
        variant="contained"
        color="primary"
        onClick={onLogin}
      >
        Login
      </Button>
      <Button
        size="large"
        variant="contained"
        color="primary"
        onClick={onSignup}
      >
        Sign Up
      </Button>
    </Container>
  );
};

const enhanced = compose(
  withApollo,
  graphql(SIGNUP_MUTATION, { name: 'signupMutation' }),
  graphql(LOGIN_MUTATION, { name: 'loginMutation' }),
  withState('name', 'changeName', ''),
  withState('password', 'changePassword', ''),
  withHandlers({
    onChangeName: ({ changeName }) => e => changeName(e.target.value),
    onChangePassword: ({ changePassword }) => e =>
      changePassword(e.target.value),
    onLogin: ({
      name,
      password,
      changeName,
      changePassword,
      loginMutation,
    }) => async () => {
      const result = await loginMutation({
        variables: {
          name,
          password,
        },
      });
      localStorage.setItem(AUTH_TOKEN, result.data.login.token);
      changeName('');
      changePassword('');
    },
    onSignup: ({
      name,
      password,
      changeName,
      changePassword,
      signupMutation,
    }) => async () => {
      const result = await signupMutation({
        variables: {
          name,
          password,
        },
      });
      localStorage.setItem(AUTH_TOKEN, result.data.login.token);
      changeName('');
      changePassword('');
    },
  })
)(Login);

export default enhanced;
<|endoftext|>