<commit_before>const logger = require('logger');
const appConstants = require('app.constants');
const EndpointModel = require('models/endpoint.model');
const VersionModel = require('models/version.model');
const url = require('url');
const EndpointNotFound = require('errors/endpointNotFound');
const NotAuthenticated = require('errors/notAuthenticated');
const FilterError = require('errors/filterError');
const pathToRegexp = require('path-to-regexp');
const requestPromise = require('request-promise');
const fs = require('fs');

const ALLOWED_HEADERS = [
    'cache-control',
    'charset',
    'location',
    'host',
];

const CACHE = {
    endpoints: [],
    version: null
};

class Dispatcher {

    static getLoggedUser(ctx) {
        if (ctx.state) {
            if (ctx.state.user) {
                return ctx.state.user;
            } else if (ctx.state.microservice) {
                return ctx.state.microservice;
            }
        }
        if (ctx.req && ctx.req.user) {
            return ctx.req.user;
        }
        return null;
    }

    static async buildUrl(sourcePath, redirectEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[key] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(redirectEndpoint.path);
        const buildUrl = url.resolve(redirectEndpoint.url, toPath(keys));
        logger.debug(`Final url  ${buildUrl}`);
        return buildUrl;
    }

    static buildPathFilter(sourcePath, filterEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[filterEndpoint.params[key]] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(filterEndpoint.path);
        const path = toPath(keys);
        logger.debug(`Final path  ${path}`);
        return path;
    }

    static searchFilterValue(filter, filterValues) {
        logger.debug('Searching filterValue to filter', filter.name);

        if (filterValues) {
            for (let i = 0, length = filterValues.length; i < length; i++) {
                if (filterValues[i].name === filter.name && filterValues[i].path === filter.path &&
                    filterValues[i].method === filter.method && filterValues[i].result.correct) {
                    return filterValues[i].result.data;
                }
            }
        }
        logger.warn('Not find filter value to filter', filter.name);
        return null;
    }

    static checkCompare(compare, dataFilter, condition = 'AND') {
        logger.debug('Check compare filter to filter', compare, 'and dataFilter', dataFilter);
        if (compare && dataFilter) {
            if (compare instanceof Array) {
                for (let j = 0, lengthCompare = compare.length; j < lengthCompare; j++) {
                    const match = Dispatcher.checkCompare(compare[j], dataFilter, condition);
                    if (match && condition === 'OR') {
                        return true;
                    } else if (!match && condition === 'AND') {
                        return false;
                    }
                }
            } else {
                const compareKeys = Object.keys(compare);

                for (let i = 0, length = compareKeys.length; i < length; i++) {
                    const key = compareKeys[i];
                    if (typeof compare[key] === 'object') {
                        logger.debug('IS A OBJECT');
                        const match = Dispatcher.checkCompare(compare[key], dataFilter[key], condition);
                        if (!match) {
                            return false;
                        }
                    } else if (compare[key] !== dataFilter[key]) {
                        return false;
                    }
                }
                return true;
            }
        }
        if (condition === 'OR') {
            return false;
        } else if (condition === 'AND') {
            return true;
        }
        return false;
    }

    static checkValidRedirects(redirects, filters) {
        logger.debug('Checking redirects with filters');
        const validRedirects = [];
        for (let i = 0, length = redirects.length; i < length; i++) {
            const redirect = redirects[i];
            let valid = true;
            if (redirect.filters) {
                for (let j = 0, lengthRF = redirect.filters.length; j < lengthRF; j++) {
                    const filterValue = Dispatcher.searchFilterValue(redirect.filters[j], filters);
                    if (!filterValue || !Dispatcher.checkCompare(redirect.filters[j].compare, filterValue, redirect.filters[j].condition)) {
                        logger.warn('Not valid filter');
                        valid = false;
                        break;
                    }
                    if (!redirect.data) {
                        redirect.data = {};
                    }
                    redirect.data[redirect.filters[j].name] = filterValue;
                }
            }
            if (valid) {
                validRedirects.push(redirect);
            }
        }
        return validRedirects;
    }

    static async checkFilters(sourcePath, endpoint) {
        logger.debug('Checking filters in endpoint', endpoint);
        let filters = [];
        for (let i = 0, length = endpoint.redirect.length; i < length; i++) {
            if (endpoint.redirect[i].filters) {
                filters = filters.concat(endpoint.redirect[i].filters);
            }
        }
        if (!filters || filters.length === 0) {
            logger.debug('Not contain filters. All redirect are valids');
            return endpoint;
        }
        logger.debug('Obtaining data to check filters');
        const promisesRequest = [];
        let filter = null;
        let path = null;
        for (let i = 0, length = filters.length; i < length; i++) {
            filter = filters[i];
            path = await Dispatcher.buildPathFilter(sourcePath, filter, endpoint);
            const request = await Dispatcher.getRequest({
                request: {
                    url: path,
                    method: filter.method,
                    body: {},
                },
            });
            logger.debug('Config request', request);
            request.configRequest.json = true;
            promisesRequest.push(requestPromise(request.configRequest));

        }
        if (!promisesRequest || promisesRequest.length === 0) {
            return endpoint;
        }
        try {
            logger.debug('Doing requests');
            const results = await Promise.all(promisesRequest);
            // TODO: Add support to serveral filter by each endpoint
            for (let i = 0, length = results.length; i < length; i++) {
                if (results[i].statusCode === 200) {
                    filters[i].result = {
                        data: results[i].body,
                        correct: true,
                    };
                } else {
                    filters[i].result = {
                        correct: false,
                    };
                }
            }
            logger.debug('Checking valid filters');
            const validRedirects = Dispatcher.checkValidRedirects(endpoint.redirect, filters);
            endpoint.redirect = validRedirects;
        } catch (err) {
            logger.error(err);
            throw new FilterError('Error resolving filters');
        }
        return endpoint;
    }

    static getHeadersFromRequest(headers) {
        const validHeaders = {};
        const keys = Object.keys(headers);
        for (let i = 0, length = keys.length; i < length; i++) {
            if (ALLOWED_HEADERS.indexOf(keys[i].toLowerCase()) > -1) {
                validHeaders[keys[i]] = headers[keys[i]];
            }
        }
        return validHeaders;
    }

    static async reloadEndpoints(version) {
        logger.info('Reloading endpoints');
        CACHE.endpoints = await EndpointModel.find({
            version,
        });
        CACHE.version = version;

    }

    static async getEndpoint(pathname, method) {
        logger.debug('Obtaining version');
        const version = await VersionModel.findOne({
            name: appConstants.ENDPOINT_VERSION,
        });
        logger.debug('Version found ', version);
        if (CACHE.version !== version.version || process.env.NODE_ENV === 'dev') {
            await Dispatcher.reloadEndpoints(version.version);
        }
        logger.debug('Searching endpoints');
        if (!CACHE.endpoints || CACHE.endpoints.length === 0) {
            return null;
        }
        return CACHE.endpoints.find(endpoint => endpoint.method === method && endpoint.pathRegex && endpoint.pathRegex.test(pathname));

    }

    static async getRequest(ctx) {
        logger.info(`Searching endpoint where redirect url ${ctx.request.url}
            and method ${ctx.request.method}`);
        const parsedUrl = url.parse(ctx.request.url);
        let endpoint = await Dispatcher.getEndpoint(parsedUrl.pathname, ctx.request.method);

        if (!endpoint) {
            throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
        } else {
            logger.debug('Endpoint found');
            logger.debug('Checking if is necesary authentication');
            if (endpoint.authenticated && !Dispatcher.getLoggedUser(ctx)) {
                logger.info('Is necesary authentication but the request is not authenticated');
                throw new NotAuthenticated();
            }
            let redirectEndpoint = null;
            endpoint = await Dispatcher.checkFilters(parsedUrl.pathname, endpoint);
            if (endpoint && endpoint.redirect.length === 0) {
                logger.error('Not exist redirects');
                throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
            }

            if (endpoint.redirect && endpoint.redirect.length > 1) {
                logger.debug(`Find several redirect endpoints (num: ${endpoint.redirect.length}).
                Obtaining final endpoint with random`);
                const pos = Math.floor(Math.random() * endpoint.redirect.length);
                logger.debug(`Position choose ${pos}`);
                redirectEndpoint = endpoint.redirect[pos];
            } else {
                logger.debug('Only contain one redirect');
                redirectEndpoint = endpoint.redirect[0];
            }
            logger.info('Dispathing request from %s to %s%s private endpoint.',
                parsedUrl.pathname, redirectEndpoint.url, redirectEndpoint.path);
            logger.debug('endpoint', endpoint);
            const finalUrl = await Dispatcher.buildUrl(parsedUrl.pathname, redirectEndpoint, endpoint);
            let configRequest = { // eslint-disable-line prefer-const
                uri: finalUrl,
                method: redirectEndpoint.method,
                // https://github.com/request/request-promise#user-content-get-a-rejection-only-if-the-request-failed-for-technical-reasons
                simple: false,
                resolveWithFullResponse: true,
                binary: endpoint.binary,
            };
            if (ctx.request.query) {
                logger.debug('Adding query params');
                configRequest.qs = ctx.request.query;
            }

            logger.debug('Create request to %s', configRequest.uri);
            if (configRequest.method === 'POST' || configRequest.method === 'PATCH' ||
                configRequest.method === 'PUT') {
                logger.debug('Method is %s. Adding body', configRequest.method);
                if (ctx.request.body.fields) {
                    logger.debug('Is a form-data request');
                    configRequest.body = ctx.request.body.fields;
                } else {
                    configRequest.body = ctx.request.body;
                }
            }
            logger.debug('Adding logged user if it is logged');
            redirectEndpoint.data = Object.assign({}, redirectEndpoint.data, {
                loggedUser: Dispatcher.getLoggedUser(ctx),
            });
            if (redirectEndpoint.data) {
                logger.debug('Adding data');
                if (configRequest.method === 'GET' || configRequest.method === 'DELETE') {
                    configRequest.qs = configRequest.qs || {};
                    const keys = Object.keys(redirectEndpoint.data);
                    for (let i = 0, length = keys.length; i < length; i++) {
                        configRequest.qs[keys[i]] = JSON.stringify(redirectEndpoint.data[keys[i]]);
                    }
                } else {
                    configRequest.body = Object.assign({}, configRequest.body, redirectEndpoint.data);
                }
            }
            if (ctx.request.body.files) {
                logger.debug('Adding files', ctx.request.body.files);
                const files = ctx.request.body.files;
                let formData = {}; // eslint-disable-line prefer-const
                for (const key in files) { // eslint-disable-line no-restricted-syntax
                    if ({}.hasOwnProperty.call(files, key)) {
                        formData[key] = {
                            value: fs.createReadStream(files[key].path),
                            options: {
                                filename: files[key].name,
                                contentType: files[key].type
                            }
                        };
                    }
                }
                if (configRequest.body) {
                    const body = {};
                    // convert values to string because form-data is required that all values are string
                    for (const key in configRequest.body) { // eslint-disable-line no-restricted-syntax
                        if (key !== 'files') {
                            if (configRequest.body[key] !== null && configRequest.body[key] !== undefined) {
                                if (typeof configRequest.body[key] === 'object') {
                                    body[key] = JSON.stringify(configRequest.body[key]);
                                } else {
                                    body[key] = configRequest.body[key];
                                }
                            } else {
                                body[key] = 'null';
                            }
                        }
                    }
                    configRequest.body = Object.assign(body, formData);
                } else {
                    configRequest.body = formData;
                }

                configRequest.multipart = true;

            }
            if (ctx.request.headers) {
                logger.debug('Adding headers');
                configRequest.headers = Dispatcher.getHeadersFromRequest(ctx.request.headers);
            }

            logger.debug('Checking if is json or formdata request');
            if (configRequest.multipart) {
                logger.debug('Is FormData request');
                configRequest.formData = configRequest.body;
                delete configRequest.body;
                delete configRequest.multipart;
            } else {
                logger.debug('Is JSON request');
                configRequest.json = true;
                delete configRequest.multipart;
            }
            configRequest.encoding = null; // all request have encoding null

            logger.debug('Returning config', configRequest);
            return {
                configRequest,
                endpoint,
            };
        }
    }

}

module.exports = Dispatcher;
<commit_msg>remove cache<commit_after>const logger = require('logger');
const appConstants = require('app.constants');
const EndpointModel = require('models/endpoint.model');
const VersionModel = require('models/version.model');
const url = require('url');
const EndpointNotFound = require('errors/endpointNotFound');
const NotAuthenticated = require('errors/notAuthenticated');
const FilterError = require('errors/filterError');
const pathToRegexp = require('path-to-regexp');
const requestPromise = require('request-promise');
const utils = require('utils');
const fs = require('fs');

const ALLOWED_HEADERS = [
    'cache-control',
    'charset',
    'location',
    'host',
];

class Dispatcher {

    static getLoggedUser(ctx) {
        if (ctx.state) {
            if (ctx.state.user) {
                return ctx.state.user;
            } else if (ctx.state.microservice) {
                return ctx.state.microservice;
            }
        }
        if (ctx.req && ctx.req.user) {
            return ctx.req.user;
        }
        return null;
    }

    static async buildUrl(sourcePath, redirectEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[key] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(redirectEndpoint.path);
        const buildUrl = url.resolve(redirectEndpoint.url, toPath(keys));
        logger.debug(`Final url  ${buildUrl}`);
        return buildUrl;
    }

    static buildPathFilter(sourcePath, filterEndpoint, endpoint) {
        logger.debug('Building url');
        const result = endpoint.pathRegex.exec(sourcePath);
        let keys = {}; // eslint-disable-line prefer-const
        endpoint.pathKeys.map((key, i) => (
            keys[filterEndpoint.params[key]] = result[i + 1]
        ));
        const toPath = pathToRegexp.compile(filterEndpoint.path);
        const path = toPath(keys);
        logger.debug(`Final path  ${path}`);
        return path;
    }

    static searchFilterValue(filter, filterValues) {
        logger.debug('Searching filterValue to filter', filter.name);

        if (filterValues) {
            for (let i = 0, length = filterValues.length; i < length; i++) {
                if (filterValues[i].name === filter.name && filterValues[i].path === filter.path &&
                    filterValues[i].method === filter.method && filterValues[i].result.correct) {
                    return filterValues[i].result.data;
                }
            }
        }
        logger.warn('Not find filter value to filter', filter.name);
        return null;
    }

    static checkCompare(compare, dataFilter, condition = 'AND') {
        logger.debug('Check compare filter to filter', compare, 'and dataFilter', dataFilter);
        if (compare && dataFilter) {
            if (compare instanceof Array) {
                for (let j = 0, lengthCompare = compare.length; j < lengthCompare; j++) {
                    const match = Dispatcher.checkCompare(compare[j], dataFilter, condition);
                    if (match && condition === 'OR') {
                        return true;
                    } else if (!match && condition === 'AND') {
                        return false;
                    }
                }
            } else {
                const compareKeys = Object.keys(compare);

                for (let i = 0, length = compareKeys.length; i < length; i++) {
                    const key = compareKeys[i];
                    if (typeof compare[key] === 'object') {
                        logger.debug('IS A OBJECT');
                        const match = Dispatcher.checkCompare(compare[key], dataFilter[key], condition);
                        if (!match) {
                            return false;
                        }
                    } else if (compare[key] !== dataFilter[key]) {
                        return false;
                    }
                }
                return true;
            }
        }
        if (condition === 'OR') {
            return false;
        } else if (condition === 'AND') {
            return true;
        }
        return false;
    }

    static checkValidRedirects(redirects, filters) {
        logger.debug('Checking redirects with filters');
        const validRedirects = [];
        for (let i = 0, length = redirects.length; i < length; i++) {
            const redirect = redirects[i];
            let valid = true;
            if (redirect.filters) {
                for (let j = 0, lengthRF = redirect.filters.length; j < lengthRF; j++) {
                    const filterValue = Dispatcher.searchFilterValue(redirect.filters[j], filters);
                    if (!filterValue || !Dispatcher.checkCompare(redirect.filters[j].compare, filterValue, redirect.filters[j].condition)) {
                        logger.warn('Not valid filter');
                        valid = false;
                        break;
                    }
                    if (!redirect.data) {
                        redirect.data = {};
                    }
                    redirect.data[redirect.filters[j].name] = filterValue;
                }
            }
            if (valid) {
                validRedirects.push(redirect);
            }
        }
        return validRedirects;
    }

    static async checkFilters(sourcePath, endpoint) {
        logger.debug('Checking filters in endpoint', endpoint);
        let filters = [];
        for (let i = 0, length = endpoint.redirect.length; i < length; i++) {
            if (endpoint.redirect[i].filters) {
                filters = filters.concat(endpoint.redirect[i].filters);
            }
        }
        if (!filters || filters.length === 0) {
            logger.debug('Not contain filters. All redirect are valids');
            return endpoint;
        }
        logger.debug('Obtaining data to check filters');
        const promisesRequest = [];
        let filter = null;
        let path = null;
        for (let i = 0, length = filters.length; i < length; i++) {
            filter = filters[i];
            path = await Dispatcher.buildPathFilter(sourcePath, filter, endpoint);
            const request = await Dispatcher.getRequest({
                request: {
                    url: path,
                    method: filter.method,
                    body: {},
                },
            });
            logger.debug('Config request', request);
            request.configRequest.json = true;
            promisesRequest.push(requestPromise(request.configRequest));

        }
        if (!promisesRequest || promisesRequest.length === 0) {
            return endpoint;
        }
        try {
            logger.debug('Doing requests');
            const results = await Promise.all(promisesRequest);
            // TODO: Add support to serveral filter by each endpoint
            for (let i = 0, length = results.length; i < length; i++) {
                if (results[i].statusCode === 200) {
                    filters[i].result = {
                        data: results[i].body,
                        correct: true,
                    };
                } else {
                    filters[i].result = {
                        correct: false,
                    };
                }
            }
            logger.debug('Checking valid filters');
            const validRedirects = Dispatcher.checkValidRedirects(endpoint.redirect, filters);
            endpoint.redirect = validRedirects;
        } catch (err) {
            logger.error(err);
            throw new FilterError('Error resolving filters');
        }
        return endpoint;
    }

    static getHeadersFromRequest(headers) {
        let validHeaders = {};
        const keys = Object.keys(headers);
        for (let i = 0, length = keys.length; i < length; i++) {
            if (ALLOWED_HEADERS.indexOf(keys[i].toLowerCase()) > -1) {
                validHeaders[keys[i]] = headers[keys[i]];
            }
        }
        return validHeaders;
    }

    static async getRequest(ctx) {
        logger.info(`Searching endpoint where redirect url ${ctx.request.url}
            and method ${ctx.request.method}`);
        logger.debug('Obtaining version');
        const version = await VersionModel.findOne({
            name: appConstants.ENDPOINT_VERSION,
        });
        logger.debug('Version found ', version);
        const parsedUrl = url.parse(ctx.request.url);
        logger.debug('Searching endpoints');
        let endpoint = await EndpointModel.findOne({
            $where: `this.pathRegex && this.pathRegex.test('${parsedUrl.pathname}')`,
            method: ctx.request.method,
            version: version.version,
        });

        if (!endpoint) {
            throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
        } else {
            logger.debug('Endpoint found');
            logger.debug('Checking if is necesary authentication');
            if (endpoint.authenticated && !Dispatcher.getLoggedUser(ctx)) {
                logger.info('Is necesary authentication but the request is not authenticated');
                throw new NotAuthenticated();
            }
            let redirectEndpoint = null;
            endpoint = await Dispatcher.checkFilters(parsedUrl.pathname, endpoint);
            if (endpoint && endpoint.redirect.length === 0) {
                logger.error('Not exist redirects');
                throw new EndpointNotFound(`${parsedUrl.pathname} not found`);
            }

            if (endpoint.redirect && endpoint.redirect.length > 1) {
                logger.debug(`Find several redirect endpoints (num: ${endpoint.redirect.length}).
                Obtaining final endpoint with random`);
                const pos = Math.floor(Math.random() * endpoint.redirect.length);
                logger.debug(`Position choose ${pos}`);
                redirectEndpoint = endpoint.redirect[pos];
            } else {
                logger.debug('Only contain one redirect');
                redirectEndpoint = endpoint.redirect[0];
            }
            logger.info('Dispathing request from %s to %s%s private endpoint.',
                parsedUrl.pathname, redirectEndpoint.url, redirectEndpoint.path);
            logger.debug('endpoint', endpoint);
            const finalUrl = await Dispatcher.buildUrl(parsedUrl.pathname, redirectEndpoint, endpoint);
            let configRequest = { // eslint-disable-line prefer-const
                uri: finalUrl,
                method: redirectEndpoint.method,
                // https://github.com/request/request-promise#user-content-get-a-rejection-only-if-the-request-failed-for-technical-reasons
                simple: false,
                resolveWithFullResponse: true,
                binary: endpoint.binary,
            };
            if (ctx.request.query) {
                logger.debug('Adding query params');
                configRequest.qs = ctx.request.query;
            }

            logger.debug('Create request to %s', configRequest.uri);
            if (configRequest.method === 'POST' || configRequest.method === 'PATCH' ||
                configRequest.method === 'PUT') {
                logger.debug('Method is %s. Adding body', configRequest.method);
                if (ctx.request.body.fields) {
                    logger.debug('Is a form-data request');
                    configRequest.body = ctx.request.body.fields;
                } else {
                    configRequest.body = ctx.request.body;
                }
            }
            logger.debug('Adding logged user if it is logged');
            redirectEndpoint.data = Object.assign({}, redirectEndpoint.data, {
                loggedUser: Dispatcher.getLoggedUser(ctx),
            });
            if (redirectEndpoint.data) {
                logger.debug('Adding data');
                if (configRequest.method === 'GET' || configRequest.method === 'DELETE') {
                    configRequest.qs = configRequest.qs || {};
                    const keys = Object.keys(redirectEndpoint.data);
                    for (let i = 0, length = keys.length; i < length; i++) {
                        configRequest.qs[keys[i]] = JSON.stringify(redirectEndpoint.data[keys[i]]);
                    }
                } else {
                    configRequest.body = Object.assign({}, configRequest.body, redirectEndpoint.data);
                }
            }
            if (ctx.request.body.files) {
                logger.debug('Adding files', ctx.request.body.files);
                const files = ctx.request.body.files;
                let formData = {}; // eslint-disable-line prefer-const
                for (const key in files) { // eslint-disable-line no-restricted-syntax
                    if ({}.hasOwnProperty.call(files, key)) {
                        formData[key] = {
                            value: fs.createReadStream(files[key].path),
                            options: {
                                filename: files[key].name,
                                contentType: files[key].type
                            }
                        };
                    }
                }
                if (configRequest.body) {
                    const body = {};
                    // convert values to string because form-data is required that all values are string
                    for (const key in configRequest.body) { // eslint-disable-line no-restricted-syntax
                        if (key !== 'files') {
                            if (configRequest.body[key] !== null && configRequest.body[key] !== undefined) {
                                if(typeof configRequest.body[key] === 'object') {
                                    body[key] = JSON.stringify(configRequest.body[key]);
                                } else {
                                    body[key] = configRequest.body[key];
                                }
                            } else {
                                body[key] = 'null';
                            }
                        }
                    }
                    configRequest.body = Object.assign(body, formData);
                } else {
                    configRequest.body = formData;
                }

                configRequest.multipart = true;

            }
            if (ctx.request.headers) {
                logger.debug('Adding headers');
                configRequest.headers = Dispatcher.getHeadersFromRequest(ctx.request.headers);
            }

            logger.debug('Checking if is json or formdata request');
            if (configRequest.multipart) {
                logger.debug('Is FormData request');
                configRequest.formData = configRequest.body;
                delete configRequest.body;
                delete configRequest.multipart;
            } else {
                logger.debug('Is JSON request');
                configRequest.json = true;
                delete configRequest.multipart;
            }
            configRequest.encoding = null; // all request have encoding null

            logger.debug('Returning config', configRequest);
            return {
                configRequest,
                endpoint,
            };
        }
    }

}

module.exports = Dispatcher;
<|endoftext|>


<commit_before>'use strict';
const app = require('app');
const BrowserWindow = require('browser-window');

const YoutubeApi = require('./youtubeapi');

const Hapi = require('hapi');
const isOnline = require('is-online');

// Create the Hapi Web Server
const server = new Hapi.Server();
server.connection({
  host: 'localhost',
  port: '@@PORT'
});

// Start the server
server.start((err) => {
  if (err) {
    throw err;
  }

  console.log('Server running at:', server.info.uri);
});

const AUTH_WINDOW = 'auth';
const MAIN_WINDOW = 'main';

const io = require('socket.io')(server.listener);

// report crashes to the Electron project
require('crash-reporter').start();

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();

// prevent window being garbage collected
let windows = {};

function onClosed(windowName) {
  // dereference the window
  windows[windowName] = null;
}

function createMainWindow() {
  const win = new BrowserWindow({
    width: 1200,
    height: 700
  });

  win.loadUrl('file://' + __dirname + '/client/index.html');
  win.on('closed', onClosed.bind(MAIN_WINDOW));

  return win;
}

function createLogInWindow(url) {
  const win = new BrowserWindow({
    width: 500,
    height: 600
  });

  win.loadUrl(url);
  win.on('closed', onClosed.bind('auth'));

  return win;
}

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate-with-no-open-windows', () => {
  if (!windows[MAIN_WINDOW]) {
    windows[MAIN_WINDOW] = createMainWindow();
  }
});

app.on('ready', () => {
  windows[MAIN_WINDOW] = createMainWindow();

  io.on('connection', (socket) => {
    socket.on('youtube/auth', () => {
      socket.emit('youtube/waiting');

      YoutubeApi.getAuthUrl((url) => {
        socket.emit('youtube/waitingforuser')
        windows[AUTH_WINDOW] = createLogInWindow(url);
      });
    });

    socket.on('subscriptions/list', () => {
      YoutubeApi.getSubscriptions((err, subscriptions) => {
        if (err) {
          console.log(err);
        } else {
          socket.emit('subscriptions/list', subscriptions);
        }
      });
    });

    socket.on('video/cue', (video) => {
      console.log('Cueing video: ', video.id);
      socket.emit('video/cue', video.id);

      if (!currentPlaylist[video.id]) {
        currentPlaylist[video.id] = video;
      }
      socket.emit('playlist/update', currentPlaylist);
    });

    socket.on('video/start', (id) => {
      console.log('Video started: ', id);
    });

    socket.on('video/pause', (id) => {
      console.log('Video paused: ', id);
    });

    socket.on('video/buffer', (id) => {
      console.log('Video buffering: ', id);
    });

    socket.on('video/end', (id) => {
      console.log('Video ended: ', id);
    });

    function launchApp() {
      if (isOnline((err, online) => {
        if (err || !online) {
          return socket.emit('internet/notconnected');
        }

        YoutubeApi.tryStoredAccessToken((noValidAccessToken, token) => {
          if (noValidAccessToken) {
            socket.emit('youtube/notauthenticated');
          } else {
            socket.emit('youtube/callback', token);
          }
        });
      }));
    }

    socket.on('internet/reconnect', launchApp);

    let currentPlaylist = {};
    launchApp();
  });

  server.route({
    method: 'GET',
    path:'/youtube/callback',
    handler: function (request, reply) {
      io.emit('youtube/waiting');
      YoutubeApi.getToken(request.query.code, function (token) {
        io.emit('youtube/callback', token);

        windows[AUTH_WINDOW].close();
      });
    }
  });
});
<commit_msg>Add the window sizes in the config file<commit_after>'use strict';

const CONFIG = require('./config');

const app = require('app');
const BrowserWindow = require('browser-window');

const YoutubeApi = require('./youtubeapi');

const Hapi = require('hapi');
const isOnline = require('is-online');

// Create the Hapi Web Server
const server = new Hapi.Server();
server.connection({
  host: 'localhost',
  port: '@@PORT'
});

// Start the server
server.start((err) => {
  if (err) {
    throw err;
  }

  console.log('Server running at:', server.info.uri);
});

const AUTH_WINDOW = 'auth';
const MAIN_WINDOW = 'main';

const io = require('socket.io')(server.listener);

// report crashes to the Electron project
require('crash-reporter').start();

// adds debug features like hotkeys for triggering dev tools and reload
require('electron-debug')();

// prevent window being garbage collected
let windows = {};

function onClosed(windowName) {
  // dereference the window
  windows[windowName] = null;
}

function createMainWindow() {
  const win = new BrowserWindow({
    width: CONFIG.MAIN_WINDOW.WIDTH,
    height: CONFIG.MAIN_WINDOW.HEIGHT
  });

  win.loadUrl('file://' + __dirname + '/client/index.html');
  win.on('closed', onClosed.bind(MAIN_WINDOW));

  return win;
}

function createLogInWindow(url) {
  const win = new BrowserWindow({
    width: CONFIG.AUTH_WINDOW.WIDTH,
    height: CONFIG.AUTH_WINDOW.HEIGHT
  });

  win.loadUrl(url);
  win.on('closed', onClosed.bind('auth'));

  return win;
}

app.on('window-all-closed', () => {
  if (process.platform !== 'darwin') {
    app.quit();
  }
});

app.on('activate-with-no-open-windows', () => {
  if (!windows[MAIN_WINDOW]) {
    windows[MAIN_WINDOW] = createMainWindow();
  }
});

app.on('ready', () => {
  windows[MAIN_WINDOW] = createMainWindow();

  io.on('connection', (socket) => {
    socket.on('youtube/auth', () => {
      socket.emit('youtube/waiting');

      YoutubeApi.getAuthUrl((url) => {
        socket.emit('youtube/waitingforuser')
        windows[AUTH_WINDOW] = createLogInWindow(url);
      });
    });

    socket.on('subscriptions/list', () => {
      YoutubeApi.getSubscriptions((err, subscriptions) => {
        if (err) {
          console.log(err);
        } else {
          socket.emit('subscriptions/list', subscriptions);
        }
      });
    });

    socket.on('video/cue', (video) => {
      console.log('Cueing video: ', video.id);
      socket.emit('video/cue', video.id);

      if (!currentPlaylist[video.id]) {
        currentPlaylist[video.id] = video;
      }
      socket.emit('playlist/update', currentPlaylist);
    });

    socket.on('video/start', (id) => {
      console.log('Video started: ', id);
    });

    socket.on('video/pause', (id) => {
      console.log('Video paused: ', id);
    });

    socket.on('video/buffer', (id) => {
      console.log('Video buffering: ', id);
    });

    socket.on('video/end', (id) => {
      console.log('Video ended: ', id);
    });

    function launchApp() {
      if (isOnline((err, online) => {
        if (err || !online) {
          return socket.emit('internet/notconnected');
        }

        YoutubeApi.tryStoredAccessToken((noValidAccessToken, token) => {
          if (noValidAccessToken) {
            socket.emit('youtube/notauthenticated');
          } else {
            socket.emit('youtube/callback', token);
          }
        });
      }));
    }

    socket.on('internet/reconnect', launchApp);

    let currentPlaylist = {};
    launchApp();
  });

  server.route({
    method: 'GET',
    path:'/youtube/callback',
    handler: function (request, reply) {
      io.emit('youtube/waiting');
      YoutubeApi.getToken(request.query.code, function (token) {
        io.emit('youtube/callback', token);

        windows[AUTH_WINDOW].close();
      });
    }
  });
});
<|endoftext|>


<commit_before>import MasterdataView from '../../views/masterdata/index';
import CountriesView from '../../views/masterdata/country';

const routes = [
    {
        path: 'admin/masterdata',
        component: MasterdataView,
        childRoutes: [
            {
                path: 'countries',
                component: CountriesView
            },

            {
                path: 'movietype'
                // component:
            },
            {
                path: 'gender'
                // component:
            }
        ]
    }
];

export default routes;
<commit_msg>Updating router with the new routes and adding movies router<commit_after><|endoftext|>


<commit_before>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                let parameters = response.result.parameters;

                if (action != null){
                    try {
                        var misc = require('./'+ action);
                        console.log(misc.addX(JSON.stringify(parameters)));
                    } catch(e) {
                        console.error(action +" is not found");
                    }
                }else{
                    console.error("no action");
                }

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we split message if needed
                    var splittedText = splitResponse(responseText);

                    for (var i = 0; i < splittedText.length; i++) {
                        sendFBMessage(sender, {text: splittedText[i]});
                    }
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320)
    {
        return [str];
    }

    var result = chunkString(str, 300);

    return result;

}

function chunkString(s, len)
{
    var curr = len, prev = 0;

    var output = [];

    while(s[curr]) {
        if(s[curr++] == ' ') {
            output.push(s.substring(prev,curr));
            prev = curr;
            curr += len;
        }
        else
        {
            var currReverse = curr;
            do {
                if(s.substring(currReverse - 1, currReverse) == ' ')
                {
                    output.push(s.substring(prev,currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while(currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    return output;
}

function sendFBMessage(sender, messageData) {
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<commit_msg>Update app.js<commit_after>'use strict';

const apiai = require('apiai');
const express = require('express');
const bodyParser = require('body-parser');
const uuid = require('node-uuid');
const request = require('request');

const REST_PORT = (process.env.PORT || 5000);
const APIAI_ACCESS_TOKEN = process.env.APIAI_ACCESS_TOKEN;
const APIAI_LANG = process.env.APIAI_LANG || 'en';
const FB_VERIFY_TOKEN = process.env.FB_VERIFY_TOKEN;
const FB_PAGE_ACCESS_TOKEN = process.env.FB_PAGE_ACCESS_TOKEN;

const apiAiService = apiai(APIAI_ACCESS_TOKEN, {language: APIAI_LANG, requestSource: "fb"});
const sessionIds = new Map();

function processEvent(event) {
    var sender = event.sender.id;

    if (event.message && event.message.text) {
        var text = event.message.text;
        // Handle a text message from this sender

        if (!sessionIds.has(sender)) {
            sessionIds.set(sender, uuid.v1());
        }

        console.log("Text", text);

        let apiaiRequest = apiAiService.textRequest(text,
            {
                sessionId: sessionIds.get(sender)
            });

        apiaiRequest.on('response', (response) => {
            if (isDefined(response.result)) {
                let responseText = response.result.fulfillment.speech;
                let responseData = response.result.fulfillment.data;
                let action = response.result.action;
                let parameters = response.result.parameters;

                if (action){
                    try {
                        var misc = require('./'+ action);
                        console.log(misc.addX(JSON.stringify(parameters)));
                    } catch(e) {
                        console.error(action +" is not found");
                    }
                }else{
                    console.error("no action");
                }

                if (isDefined(responseData) && isDefined(responseData.facebook)) {
                    try {
                        console.log('Response as formatted message');
                        sendFBMessage(sender, responseData.facebook);
                    } catch (err) {
                        sendFBMessage(sender, {text: err.message });
                    }
                } else if (isDefined(responseText)) {
                    console.log('Response as text message');
                    // facebook API limit for text length is 320,
                    // so we split message if needed
                    var splittedText = splitResponse(responseText);

                    for (var i = 0; i < splittedText.length; i++) {
                        sendFBMessage(sender, {text: splittedText[i]});
                    }
                }

            }
        });

        apiaiRequest.on('error', (error) => console.error(error));
        apiaiRequest.end();
    }
}

function splitResponse(str) {
    if (str.length <= 320)
    {
        return [str];
    }

    var result = chunkString(str, 300);

    return result;

}

function chunkString(s, len)
{
    var curr = len, prev = 0;

    var output = [];

    while(s[curr]) {
        if(s[curr++] == ' ') {
            output.push(s.substring(prev,curr));
            prev = curr;
            curr += len;
        }
        else
        {
            var currReverse = curr;
            do {
                if(s.substring(currReverse - 1, currReverse) == ' ')
                {
                    output.push(s.substring(prev,currReverse));
                    prev = currReverse;
                    curr = currReverse + len;
                    break;
                }
                currReverse--;
            } while(currReverse > prev)
        }
    }
    output.push(s.substr(prev));
    return output;
}

function sendFBMessage(sender, messageData) {
    request({
        url: 'https://graph.facebook.com/v2.6/me/messages',
        qs: {access_token: FB_PAGE_ACCESS_TOKEN},
        method: 'POST',
        json: {
            recipient: {id: sender},
            message: messageData
        }
    }, function (error, response, body) {
        if (error) {
            console.log('Error sending message: ', error);
        } else if (response.body.error) {
            console.log('Error: ', response.body.error);
        }
    });
}

function doSubscribeRequest() {
    request({
            method: 'POST',
            uri: "https://graph.facebook.com/v2.6/me/subscribed_apps?access_token=" + FB_PAGE_ACCESS_TOKEN
        },
        function (error, response, body) {
            if (error) {
                console.error('Error while subscription: ', error);
            } else {
                console.log('Subscription result: ', response.body);
            }
        });
}

function isDefined(obj) {
    if (typeof obj == 'undefined') {
        return false;
    }

    if (!obj) {
        return false;
    }

    return obj != null;
}

const app = express();
app.use(bodyParser.json());
app.all('*', function (req, res, next) {
    // res.header("Access-Control-Allow-Origin", '*');
    // res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, content-type, accept");
    next();
});

app.get('/webhook/', function (req, res) {
    if (req.query['hub.verify_token'] == FB_VERIFY_TOKEN) {
        res.send(req.query['hub.challenge']);

        setTimeout(function () {
            doSubscribeRequest();
        }, 3000);
    } else {
        res.send('Error, wrong validation token');
    }
});

app.post('/webhook/', function (req, res) {
    try {
        var messaging_events = req.body.entry[0].messaging;
        for (var i = 0; i < messaging_events.length; i++) {
            var event = req.body.entry[0].messaging[i];
            processEvent(event);
        }
        return res.status(200).json({
            status: "ok"
        });
    } catch (err) {
        return res.status(400).json({
            status: "error",
            error: err
        });
    }

});

app.listen(REST_PORT, function () {
    console.log('Rest service ready on port ' + REST_PORT);
});

doSubscribeRequest();
<|endoftext|>


<commit_before>/*globals exports */

'use strict';

exports.format = format;

function format (result) {
    return createElementWithAttributes(
        0,
        'project',
        'xmlns="" xml:lang="en" timestamp="' +
            Date.now() +
            '" first-order-denisty="' +
            result.firstOrderDensity +
            '" change-cost="' +
            result.changeCost +
            '" core-size="' +
            result.coreSize + '"',
        true,
        result.reports.reduce(function (formatted, report) {
            return formatted + formatModule(4, report);
        }, '')
    );
}

function createElementWithAttributes (indentation, tag, attributes, linebreak, content) {
    return createElementWithTags(indentation, tag + ' ' + attributes, tag, linebreak, content);
}

function createElementWithTags (indentation, openingTag, closingTag, linebreak, content) {
    return indent('<', indentation) + openingTag + '>' +
        (linebreak ? '\n' : '') + content +
        (linebreak ? indent('</', indentation) : '</') + closingTag + '>\n';
}

function indent (string, indentation) {
    return (new Array(indentation + 1)).join(' ') + string;
}

function formatModule (indentation, report) {
    var i, functions = '', nextIndentation = incrementIndentation(indentation);

    for (i = 0; i < report.functions.length; i += 1) {
        functions += formatFunction(nextIndentation, report.functions[i]);
    }

    return createElementWithAttributes(
        indentation, 'module', 'path="' + report.path + '"', true,
        createElement(nextIndentation, 'maintainability', false, report.maintainability) +
            formatAggregate(nextIndentation, report.aggregate) + functions
    );
}

function incrementIndentation (indentation) {
    return indentation + 2;
}

function formatFunction (indentation, data) {
    var nextIndentation = incrementIndentation(indentation);

    return createElementWithAttributes(
        indentation, 'function', 'name="' + data.name + '"', true,
        createElement(nextIndentation, 'line', false, data.line) +
            formatSlocComplexity(nextIndentation, data.sloc) +
                formatParameterComplexity(nextIndentation, data.params) +
                formatCyclomaticComplexity(nextIndentation, data.cyclomatic) +
                formatCyclomaticDensity(nextIndentation, data.cyclomaticDensity) +
                formatHalsteadComplexity(nextIndentation, data.halstead)
    );
}

function createElement (indentation, tag, linebreak, content) {
    return createElementWithTags(indentation, tag, tag, linebreak, content);
}

function formatSlocComplexity (indentation, data) {
    return createElement(
        indentation, 'sloc', true,
        formatSlocMetrics(incrementIndentation(indentation), data)
    );
}

function formatSlocMetrics (indentation, data) {
    return createElement(indentation, 'physical', false, data.physical) +
        createElement(indentation, 'logical', false, data.logical);
}

function formatParameterComplexity (indentation, data) {
    return createElement(indentation, 'parameters', false, data);
}

function formatCyclomaticComplexity (indentation, data) {
    return createElement(indentation, 'cyclomatic', false, data);
}

function formatCyclomaticDensity (indentation, data) {
    return createElement(indentation, 'cyclomatic-density', false, data);
}

function formatHalsteadComplexity (indentation, data) {
    return createElement(
        indentation, 'halstead', true,
        formatHalsteadMetrics(incrementIndentation(indentation), data)
    );
}

function formatHalsteadMetrics (indentation, data) {
    return createElement(indentation, 'length', false, data.length) +
        createElement(indentation, 'vocabulary', false, data.vocabulary) +
        createElement(indentation, 'difficulty', false, data.difficulty) +
        createElement(indentation, 'volume', false, data.volume) +
        createElement(indentation, 'effort', false, data.effort) +
        createElement(indentation, 'bugs', false, data.bugs) +
        createElement(indentation, 'time', false, data.time);
}

function formatAggregate (indentation, data) {
    var nextIndentation = incrementIndentation(indentation);

    return createElement(
        indentation, 'aggregate', true,
        formatSlocComplexity(nextIndentation, data.sloc) +
            formatParameterComplexity(nextIndentation, data.params) +
            formatCyclomaticComplexity(nextIndentation, data.cyclomatic) +
            formatCyclomaticDensity(nextIndentation, data.cyclomaticDensity) +
            formatHalsteadComplexity(nextIndentation, data.halstead)
    );
}

<commit_msg>Fix XML indentation.<commit_after>/*globals exports */

'use strict';

exports.format = format;

function format (result) {
    return createElementWithAttributes(
        0,
        'project',
        'xmlns="" xml:lang="en" timestamp="' +
            Date.now() +
            '" first-order-denisty="' +
            result.firstOrderDensity +
            '" change-cost="' +
            result.changeCost +
            '" core-size="' +
            result.coreSize + '"',
        true,
        result.reports.reduce(function (formatted, report) {
            return formatted + formatModule(4, report);
        }, '')
    );
}

function createElementWithAttributes (indentation, tag, attributes, linebreak, content) {
    return createElementWithTags(indentation, tag + ' ' + attributes, tag, linebreak, content);
}

function createElementWithTags (indentation, openingTag, closingTag, linebreak, content) {
    return indent('<', indentation) + openingTag + '>' +
        (linebreak ? '\n' : '') + content +
        (linebreak ? indent('</', indentation) : '</') + closingTag + '>\n';
}

function indent (string, indentation) {
    return (new Array(indentation + 1)).join(' ') + string;
}

function formatModule (indentation, report) {
    var i, functions = '', nextIndentation = incrementIndentation(indentation);

    for (i = 0; i < report.functions.length; i += 1) {
        functions += formatFunction(nextIndentation, report.functions[i]);
    }

    return createElementWithAttributes(
        indentation, 'module', 'path="' + report.path + '"', true,
        createElement(nextIndentation, 'maintainability', false, report.maintainability) +
            formatAggregate(nextIndentation, report.aggregate) + functions
    );
}

function incrementIndentation (indentation) {
    return indentation + 4;
}

function formatFunction (indentation, data) {
    var nextIndentation = incrementIndentation(indentation);

    return createElementWithAttributes(
        indentation, 'function', 'name="' + data.name + '"', true,
        createElement(nextIndentation, 'line', false, data.line) +
            formatSlocComplexity(nextIndentation, data.sloc) +
                formatParameterComplexity(nextIndentation, data.params) +
                formatCyclomaticComplexity(nextIndentation, data.cyclomatic) +
                formatCyclomaticDensity(nextIndentation, data.cyclomaticDensity) +
                formatHalsteadComplexity(nextIndentation, data.halstead)
    );
}

function createElement (indentation, tag, linebreak, content) {
    return createElementWithTags(indentation, tag, tag, linebreak, content);
}

function formatSlocComplexity (indentation, data) {
    return createElement(
        indentation, 'sloc', true,
        formatSlocMetrics(incrementIndentation(indentation), data)
    );
}

function formatSlocMetrics (indentation, data) {
    return createElement(indentation, 'physical', false, data.physical) +
        createElement(indentation, 'logical', false, data.logical);
}

function formatParameterComplexity (indentation, data) {
    return createElement(indentation, 'parameters', false, data);
}

function formatCyclomaticComplexity (indentation, data) {
    return createElement(indentation, 'cyclomatic', false, data);
}

function formatCyclomaticDensity (indentation, data) {
    return createElement(indentation, 'cyclomatic-density', false, data);
}

function formatHalsteadComplexity (indentation, data) {
    return createElement(
        indentation, 'halstead', true,
        formatHalsteadMetrics(incrementIndentation(indentation), data)
    );
}

function formatHalsteadMetrics (indentation, data) {
    return createElement(indentation, 'length', false, data.length) +
        createElement(indentation, 'vocabulary', false, data.vocabulary) +
        createElement(indentation, 'difficulty', false, data.difficulty) +
        createElement(indentation, 'volume', false, data.volume) +
        createElement(indentation, 'effort', false, data.effort) +
        createElement(indentation, 'bugs', false, data.bugs) +
        createElement(indentation, 'time', false, data.time);
}

function formatAggregate (indentation, data) {
    var nextIndentation = incrementIndentation(indentation);

    return createElement(
        indentation, 'aggregate', true,
        formatSlocComplexity(nextIndentation, data.sloc) +
            formatParameterComplexity(nextIndentation, data.params) +
            formatCyclomaticComplexity(nextIndentation, data.cyclomatic) +
            formatCyclomaticDensity(nextIndentation, data.cyclomaticDensity) +
            formatHalsteadComplexity(nextIndentation, data.halstead)
    );
}

<|endoftext|>


<commit_before>// constants
import { RETRIEVE_ATHLETE_DETAILS } from '../../constants/actionTypes';

const initialState = {};

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case RETRIEVE_ATHLETE_DETAILS:

      return Object.assign({}, state,
        action.details,
      );

    // ...other actions

    default:
      return state;
  }
}
<commit_msg>update athlete reducer.<commit_after>// constants
import {
    RETRIEVE_ATHLETE_DETAILS,
    RETRIEVE_ATHLETE_ACTIVITIES,
    RETRIEVE_ATHLETE_CLUBS,
    RETRIEVE_ATHLETE_GEAR,
} from '../../constants/actionTypes';

const initialState = {};

export default function reducer(state = initialState, action) {
  switch (action.type) {
    case RETRIEVE_ATHLETE_DETAILS:

      return Object.assign({}, state,
            action.details,
        );

    case RETRIEVE_ATHLETE_ACTIVITIES:

      return Object.assign({}, state,
            action.activities,
        );

    case RETRIEVE_ATHLETE_CLUBS:

      return Object.assign({}, state,
            action.clubs,
        );

    case RETRIEVE_ATHLETE_GEAR:

      return Object.assign({}, state,
            action.gear,
        );

    // ...other actions

    default:
      return state;
  }
}
<|endoftext|>


<commit_before>/*
 * Natural Language Processing Library for JavaScript
 *
 * A client-side NLP utility library for web applications
 *
 * Copyright 2015 Intel Corporation
 *
 * 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.
 *
 *
 *
 * Authors:
 *   Elliot Smith <elliot.smith@intel.com>
 *   Max Waterman <max.waterman@intel.com>
 *   Plamena Manolova <plamena.manolova@intel.com>
 */

(function (_, ArrayUtils) {
  'use strict';

  var EMPTY = 0;
  var FULL = 1;

  /*
  a grid data structure is used throughout, which is an array like:

  [
    [EMPTY, FULL, EMPTY, FULL],
    [FULL, FULL, EMPTY, FULL],
    ...
  ]

  each element is a row; and each element in a row is a column
  */

  // grid: array representation of a grid
  // width: number of cells in the row
  var addEmptyRow = function (grid, width) {
    var row = [];

    for (var i = 0; i < width; i++) {
      row.push(EMPTY);
    }

    grid.push(row);

    return grid;
  };

  // find all sequences in <arr> of length <length> whose elements
  // return true when passed to fn, e.g.
  // var fn = function (elt) { return elt === EMPTY; }
  // findSequences([FULL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FULL, EMPTY, EMPTY, EMPTY], fn, 3)
  // should return [ [1, 2, 3], [2, 3, 4], [3, 4, 5], [7, 8, 9] ]
  // (i.e. all sub-arrays of length 3 where all the elements === EMPTY)
  var findSequences = function (arr, startIndex, fn, length) {
    // final sequences of length <length>
    var sequences = [];

    var completeSequences = function (seq) {
      return seq.length === length;
    };

    /* never used
    var incompleteSequences = function (seq) {
      return seq.length < length;
    };
    */

    // sequences currently in progress
    var inProgress = [];

    for (var index = startIndex; index < arr.length; index++) {
      var item = arr[index];

      if (fn(item)) {
        // start a new sequence
        inProgress.push([]);

        // append this item to all existing sequences
        _.each(inProgress, function (seq) {
          seq.push({index: index, item: item});
        });
      }
      else {
        // remove all sequences from inProgress
        inProgress = [];
      }

      // add all sequences of correct length to output sequences
      sequences = sequences.concat(_.remove(inProgress, completeSequences));
    }

    return sequences;
  };

  // find all continuous sequences of EMPTY cells in row
  // with length <width>
  var findColumnSequences = function (row, width) {
    var startColumn = 0;
    return findSequences(row, startColumn, function (item) { return !item; }, width);
  };

  // find a sequence of row numbers in <grid> with the same length as
  // <height>; each row included must have at least one EMPTY cell;
  // this provides candidate groups of rows which can be tested for
  // EMPTY sequences of columns
  var findRowSequences = function (grid, height) {
    // HACK: only consider a fraction of all the rows in the grid,
    // to reduce the search space; this produces a significant
    // performance increase at the expense of a few gaps in the layout;
    // 5 is an arbitrary number: increasing it makes the algorithm
    // consider more of the grid; decreasing it to 0 would make the
    // algorithm only consider the last row of the grid
    var lastGridRow = grid.length - 1;
    var startRow = Math.max(0, lastGridRow - (height * 4));

    return findSequences(grid, startRow, function (row) {
      var emptyCell = _.find(row, function (cell) {
        return cell === EMPTY;
      });

      return emptyCell === EMPTY;
    }, height);
  };

  /*
  output:

  [
    { rows: [ 2, 3, 4 ], columns: [ 2, 3 ] },
    { rows: [ 2, 3, 4 ], columns: [ 3, 4 ] },
    { rows: [ 3, 4, 5 ], columns: [ 3, 4 ] },
    { rows: [ 7, 8, 9 ], columns: [ 0, 1 ] }
    { rows: [ 8, 9, 10 ], columns: [ 0, 1 ] }
  ]
  */
  var findSpaces = function (grid, width, height) {
    // first get row sequences for height; these are continuous groups
    // of rows which may contain the empty cells we want
    var rowSequences = findRowSequences(grid, height);

    // this contains all possible row+column combinations which could
    // fit width x height
    var candidates = [];

    // for each row sequence, get the column sequences for each of its rows
    for (var i = 0; i < rowSequences.length; i++) {
      var rowSequence = _.map(rowSequences[i], function (item) {
        return item.index;
      });

      var columnSequencesByRow = {};

      for (var j = 0; j < rowSequence.length; j++) {
        var rowNum = rowSequence[j];
        var row = grid[rowNum];
        var columnSequencesForRow = findColumnSequences(row, width);
        columnSequencesByRow[rowNum] = _.map(columnSequencesForRow, function (item) {
          return _.map(item, function (subitem) {
            return subitem.index;
          });
        });
      }

      // sequences of columns common across all of the rows
      var commonColumnSequences = ArrayUtils.intersect(_.values(columnSequencesByRow));

      // data structure looks like this:
      // { rows: [ 0, 1, 2 ], columns: [ [ 3, 4 ], [ 4, 5 ] ] }
      // meaning "(columns 3 and 4) or (columns 4 and 5) in rows 0, 1 and
      // 2 provide enough space to fit width x height"
      _.each(commonColumnSequences, function (seq) {
        candidates.push({
          rows: _.reduce(columnSequencesByRow, function (memo, val, key) {
            memo.push(parseInt(key, 10));
            return memo;
          }, []),
          columns: seq
        });
      });
    }

    return candidates;
  };

  // Fill the cells in the grid which are occupied by <shape>
  // shape: one item from the array which is output by findSpaces;
  // contains "rows" and "columns" properties which describe the rows
  // it occupies and the columns on each of those rows
  var fillCells = function (grid, shape) {
    var rowsToFill = shape.rows;
    var columnsToFill = shape.columns;

    _.each(rowsToFill, function (row) {
      _.each(columnsToFill, function (col) {
        grid[row][col] = FULL;
      });
    });

    return grid;
  };

  /*
  Find a packing for <shapes> in a grid with max width <width>;
  rows of width <width> are added to the grid if a shape won't fit
  into the grid's current rows.

  shapes: array of shapes with form {width: w, height: h};
  width and height are expressed in number of columns and number of
  rows respectively

  returns a layout object like this:

  {
    grid: <grid with FULL/EMPTY cells>,
    placements: [
      {shape: <shape to place>, position: {rows: [], columns: []}}
    ]
  }

  position describes the rows, and the columns in those rows, which the
  shape will occupy; both are zero-indexed
  */
  var findLayout = function (shapes, gridWidth, grid, placements) {
    grid = grid || [];
    placements = placements || [];

    var shape;
    var possiblePositions;
    for (var i = 0; i < shapes.length; i++) {
      shape = shapes[i];
      possiblePositions = findSpaces(grid, shape.width, shape.height);

      if (!possiblePositions.length) {
        // shape can't fit into the grid as is, so add a row and try again
        grid = addEmptyRow(grid, gridWidth);
        var layout = findLayout([shapes[i]], gridWidth, grid, placements);
        grid = layout.grid;
        placements = layout.placements;
      }
      else {
        // found one or more positions, so fill the grid using the first one
        // and continue with the remaining shapes;
        // NB this assumes that the first position found, which will
        // be the closest to the top-left corner, is the best
        grid = fillCells(grid, possiblePositions[0]);
        placements.push({shape: shape, position: possiblePositions[0]});
      }
    }

    return {
      grid: grid,
      placements: placements
    };
  };

  var LayoutGenerator = function () {};
  LayoutGenerator.prototype.generate = findLayout;

  /* globals module:true */
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = LayoutGenerator;
  }
  else {
    window.LayoutGenerator = LayoutGenerator;
  }
})(
  /* globals require:true */
  /* globals ArrayUtils:true */
  typeof _ === 'undefined' ? require('../bower_components/lodash/dist/lodash') : _,
  typeof ArrayUtils === 'undefined' ? require('./cp-array-utils') : ArrayUtils
);
<commit_msg>Don't make functions within a loop.<commit_after>/*
 * Natural Language Processing Library for JavaScript
 *
 * A client-side NLP utility library for web applications
 *
 * Copyright 2015 Intel Corporation
 *
 * 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.
 *
 *
 *
 * Authors:
 *   Elliot Smith <elliot.smith@intel.com>
 *   Max Waterman <max.waterman@intel.com>
 *   Plamena Manolova <plamena.manolova@intel.com>
 */

(function (_, ArrayUtils) {
  'use strict';

  var EMPTY = 0;
  var FULL = 1;

  /*
  a grid data structure is used throughout, which is an array like:

  [
    [EMPTY, FULL, EMPTY, FULL],
    [FULL, FULL, EMPTY, FULL],
    ...
  ]

  each element is a row; and each element in a row is a column
  */

  // grid: array representation of a grid
  // width: number of cells in the row
  var addEmptyRow = function (grid, width) {
    var row = [];

    for (var i = 0; i < width; i++) {
      row.push(EMPTY);
    }

    grid.push(row);

    return grid;
  };

  // find all sequences in <arr> of length <length> whose elements
  // return true when passed to fn, e.g.
  // var fn = function (elt) { return elt === EMPTY; }
  // findSequences([FULL, EMPTY, EMPTY, EMPTY, EMPTY, EMPTY, FULL, EMPTY, EMPTY, EMPTY], fn, 3)
  // should return [ [1, 2, 3], [2, 3, 4], [3, 4, 5], [7, 8, 9] ]
  // (i.e. all sub-arrays of length 3 where all the elements === EMPTY)
  var findSequences = function (arr, startIndex, fn, length) {
    // final sequences of length <length>
    var sequences = [];

    var completeSequences = function (seq) {
      return seq.length === length;
    };

    /* never used
    var incompleteSequences = function (seq) {
      return seq.length < length;
    };
    */

    // sequences currently in progress
    var inProgress = [];

    var makeAppendToSequenceFunction = function (index, item) {
      return function(seq) {
        seq.push({index: index, item: item});
      };
    };

    for (var index = startIndex; index < arr.length; index++) {
      var item = arr[index];

      if (fn(item)) {
        // start a new sequence
        inProgress.push([]);

        // append this item to all existing sequences
        _.each(inProgress, makeAppendToSequenceFunction(index, item));
      }
      else {
        // remove all sequences from inProgress
        inProgress = [];
      }

      // add all sequences of correct length to output sequences
      sequences = sequences.concat(_.remove(inProgress, completeSequences));
    }

    return sequences;
  };

  // find all continuous sequences of EMPTY cells in row
  // with length <width>
  var findColumnSequences = function (row, width) {
    var startColumn = 0;
    return findSequences(row, startColumn, function (item) { return !item; }, width);
  };

  // find a sequence of row numbers in <grid> with the same length as
  // <height>; each row included must have at least one EMPTY cell;
  // this provides candidate groups of rows which can be tested for
  // EMPTY sequences of columns
  var findRowSequences = function (grid, height) {
    // HACK: only consider a fraction of all the rows in the grid,
    // to reduce the search space; this produces a significant
    // performance increase at the expense of a few gaps in the layout;
    // 5 is an arbitrary number: increasing it makes the algorithm
    // consider more of the grid; decreasing it to 0 would make the
    // algorithm only consider the last row of the grid
    var lastGridRow = grid.length - 1;
    var startRow = Math.max(0, lastGridRow - (height * 4));

    return findSequences(grid, startRow, function (row) {
      var emptyCell = _.find(row, function (cell) {
        return cell === EMPTY;
      });

      return emptyCell === EMPTY;
    }, height);
  };

  /*
  output:

  [
    { rows: [ 2, 3, 4 ], columns: [ 2, 3 ] },
    { rows: [ 2, 3, 4 ], columns: [ 3, 4 ] },
    { rows: [ 3, 4, 5 ], columns: [ 3, 4 ] },
    { rows: [ 7, 8, 9 ], columns: [ 0, 1 ] }
    { rows: [ 8, 9, 10 ], columns: [ 0, 1 ] }
  ]
  */
  var findSpaces = function (grid, width, height) {
    // first get row sequences for height; these are continuous groups
    // of rows which may contain the empty cells we want
    var rowSequences = findRowSequences(grid, height);

    // this contains all possible row+column combinations which could
    // fit width x height
    var candidates = [];

    var makeMappingFunction = function() {
      return function (item) {
        return _.map(item, function (subitem) {
          return subitem.index;
        });
      };
    };

    var makeReduceFunction = function() {
      return function (memo, val, key) {
        memo.push(parseInt(key, 10));
        return memo;
      };
    };

    var makeEachFunction = function(candidates, columnSequencesByRow) {
      return function (seq) {
        candidates.push({
          rows: _.reduce(columnSequencesByRow, makeReduceFunction(), []),
          columns: seq
        });
      };
    };

    // for each row sequence, get the column sequences for each of its rows
    for (var i = 0; i < rowSequences.length; i++) {
      var rowSequence = _.map(rowSequences[i], function (item) {
        return item.index;
      });

      var columnSequencesByRow = {};

      for (var j = 0; j < rowSequence.length; j++) {
        var rowNum = rowSequence[j];
        var row = grid[rowNum];
        var columnSequencesForRow = findColumnSequences(row, width);
        columnSequencesByRow[rowNum] = _.map(columnSequencesForRow, makeMappingFunction());
      }

      // sequences of columns common across all of the rows
      var commonColumnSequences = ArrayUtils.intersect(_.values(columnSequencesByRow));

      // data structure looks like this:
      // { rows: [ 0, 1, 2 ], columns: [ [ 3, 4 ], [ 4, 5 ] ] }
      // meaning "(columns 3 and 4) or (columns 4 and 5) in rows 0, 1 and
      // 2 provide enough space to fit width x height"
      _.each(commonColumnSequences, makeEachFunction(candidates, columnSequencesByRow));
    }

    return candidates;
  };

  // Fill the cells in the grid which are occupied by <shape>
  // shape: one item from the array which is output by findSpaces;
  // contains "rows" and "columns" properties which describe the rows
  // it occupies and the columns on each of those rows
  var fillCells = function (grid, shape) {
    var rowsToFill = shape.rows;
    var columnsToFill = shape.columns;

    _.each(rowsToFill, function (row) {
      _.each(columnsToFill, function (col) {
        grid[row][col] = FULL;
      });
    });

    return grid;
  };

  /*
  Find a packing for <shapes> in a grid with max width <width>;
  rows of width <width> are added to the grid if a shape won't fit
  into the grid's current rows.

  shapes: array of shapes with form {width: w, height: h};
  width and height are expressed in number of columns and number of
  rows respectively

  returns a layout object like this:

  {
    grid: <grid with FULL/EMPTY cells>,
    placements: [
      {shape: <shape to place>, position: {rows: [], columns: []}}
    ]
  }

  position describes the rows, and the columns in those rows, which the
  shape will occupy; both are zero-indexed
  */
  var findLayout = function (shapes, gridWidth, grid, placements) {
    grid = grid || [];
    placements = placements || [];

    var shape;
    var possiblePositions;
    for (var i = 0; i < shapes.length; i++) {
      shape = shapes[i];
      possiblePositions = findSpaces(grid, shape.width, shape.height);

      if (!possiblePositions.length) {
        // shape can't fit into the grid as is, so add a row and try again
        grid = addEmptyRow(grid, gridWidth);
        var layout = findLayout([shapes[i]], gridWidth, grid, placements);
        grid = layout.grid;
        placements = layout.placements;
      }
      else {
        // found one or more positions, so fill the grid using the first one
        // and continue with the remaining shapes;
        // NB this assumes that the first position found, which will
        // be the closest to the top-left corner, is the best
        grid = fillCells(grid, possiblePositions[0]);
        placements.push({shape: shape, position: possiblePositions[0]});
      }
    }

    return {
      grid: grid,
      placements: placements
    };
  };

  var LayoutGenerator = function () {};
  LayoutGenerator.prototype.generate = findLayout;

  /* globals module:true */
  if (typeof module !== 'undefined' && module.exports) {
    module.exports = LayoutGenerator;
  }
  else {
    window.LayoutGenerator = LayoutGenerator;
  }
})(
  /* globals require:true */
  /* globals ArrayUtils:true */
  typeof _ === 'undefined' ? require('../bower_components/lodash/dist/lodash') : _,
  typeof ArrayUtils === 'undefined' ? require('./cp-array-utils') : ArrayUtils
);
<|endoftext|>


<commit_before>var React = require('react');

var menuItems = [
    "About",
    "Blog",
    "Trips",
    "Leaders",
    "Projects",
    "Resources"
];

var MenuItem = React.createClass({
    render: function() {
        return (

                    {this.props.name}

        )
    }
})

var Menu = React.createClass({
    render: function() {
        var itemNodes = menuItems.map(function (item) {
            return <MenuItem name={item} />;
        });

        return (

                Menu

                            {itemNodes}

        );
    }
})

module.exports = Menu;
<commit_msg>Removed duplicated js file<commit_after><|endoftext|>


<commit_before>/**
 *
 * Extension Type B:: Through app.Extend.module (mananger)
 *
 * Note that, since we are using the '.' notations in the keys, we need to quote them.
 *
 * You DO NOT need to worry about nested attributes like View.xx.events, it is taken
 * cared of inside app.Extend (the extension manager module).
 *
 * Two types of extension are supported:
 * 1. Override: to override a given attribute, e.g A.B.c, use
 *     'A.B' : {*         c : ...
 *     }
 *
 * 2. Extend: to extend a given attribute, e.g A.B.c, use
 *     'A.B.c' : {*         ... : ...
 *     }
 *
 * =======
 * WARNING
 * =======
 * Do not extend a non-existing attribute, if you do, an infinite loop will occur.
 *
 *
 * @author Tim.Liu
 * @update Mon Jul 22 2013 15:25:38 GMT+0800 (中国标准时间)
 *
 */

(function(app) {
    var module = app['Comment'];
    if (!module) {
        app.error('Can NOT extend undefined module: ', 'Comment');
    }

    app.Extend.module('Comment', {
        'View.Form.events': { //Todo::

        },
        'View.Form': {
            onRenderPlus: function(view) { //Todo::
            }

        },
        'View.Extension.DataGrid.ActionCell': { //Todo::

        },
        'View.Extension.DataGrid': { //Todo:: your customized cell definition goes here...

        },
        'View.DataGrid.cells': { //Todo:: field:cell type mapping

        },
        'View.DataGrid.events': { //Todo::

            'click i.icon-filter' : 'filtColumn',
            'focusout input.columFilter' : 'closeFilt',
        },
        'View.DataGrid': { //Todo::
            //mode: undefined/editor
            onRenderPlus: function(view, mode) { //Todo::
                if(mode && view.options.mode === 'subDoc'){
                    view.$el.find('th').off();
                }
                //a. apply the client side search filter
                var fields = _.pluck(view.columns, 'name');
                fields.pop();fields.shift();//get the _select_, _action_ columns out;

                    //add more fields? You can :))

                view.filter = new Backgrid.Extension.ClientSideFilter({
                  collection: view.collection,
                  fields: fields,
                });

                    //render it to the datagrid header ct
                view.$el.find('.datagrid-header-container').append(view.filter.render().el);
                view.filter.$el.find('a.close').replaceWith('');

                //b. add filter icon to headers
                view.$el.find('th').each(function(index, el){
                    var $el = $(el);
                    if($el.find('a').text().length>0){
                        $el.append('<input class="columFilter" style="float:left;display:none;position:absolute;">');
                    }
                });

            },

            filtColumn: function(e){
                var $el = $(e.currentTarget);
                var $searchBox = $el.prev().toggle();
                if($searchBox.offset()){
                    $searchBox.focus().width($el.parent().width()).position({
                        of:$el.parent(),
                    });
                }

            },

            closeFilt: function(e){
                var $el = $(e.currentTarget);
                $el.hide();
            }
        },
    });
})(Application);
<commit_msg>Updated column filter experiment in comment.extension.js<commit_after>/**
 *
 * Extension Type B:: Through app.Extend.module (mananger)
 *
 * Note that, since we are using the '.' notations in the keys, we need to quote them.
 *
 * You DO NOT need to worry about nested attributes like View.xx.events, it is taken
 * cared of inside app.Extend (the extension manager module).
 *
 * Two types of extension are supported:
 * 1. Override: to override a given attribute, e.g A.B.c, use
 *     'A.B' : {*         c : ...
 *     }
 *
 * 2. Extend: to extend a given attribute, e.g A.B.c, use
 *     'A.B.c' : {*         ... : ...
 *     }
 *
 * =======
 * WARNING
 * =======
 * Do not extend a non-existing attribute, if you do, an infinite loop will occur.
 *
 *
 * @author Tim.Liu
 * @update Mon Jul 22 2013 15:25:38 GMT+0800 (中国标准时间)
 *
 */

(function(app) {
    var module = app['Comment'];
    if (!module) {
        app.error('Can NOT extend undefined module: ', 'Comment');
    }

    app.Extend.module('Comment', {
        'View.Form.events': { //Todo::

        },
        'View.Form': {
            onRenderPlus: function(view) { //Todo::
            }

        },
        'View.Extension.DataGrid.ActionCell': { //Todo::

        },
        'View.Extension.DataGrid': { //Todo:: your customized cell definition goes here...

        },
        'View.DataGrid.cells': { //Todo:: field:cell type mapping

        },
        'View.DataGrid.events': { //Todo::

            'click i.icon-filter' : 'showColumnFilter',
            'focusout input.columnFilter' : 'closeColumnFilter',
            'keyup input.columnFilter' : 'applyFilter',
            'click .filter-val' : 'showColumnFilter',
        },
        'View.DataGrid': { //Todo::
            //mode: undefined/editor
            onRenderPlus: function(view, mode) { //Todo::
                if(mode && view.options.mode === 'subDoc'){
                    view.$el.find('th').off();
                }
                //a. apply the client side search filter
                var fields = _.pluck(view.columns, 'name');
                fields.pop();fields.shift();//get the _select_, _action_ columns out;

                    //add more fields? You can :))

                view.filter = new Backgrid.Extension.ClientSideFilter({
                  collection: view.collection,
                  fields: fields,
                });

                    //render it to the datagrid header ct
                view.$el.find('.datagrid-header-container').append(view.filter.render().el);
                view.filter.$el.find('a.close').replaceWith('');

                //b. add filter icon to headers
                view.$el.find('th').each(function(index, el){
                    var $el = $(el);
                    if($el.find('a').text().length>0){
                        $el.append('<input class="columnFilter hide" style="position:absolute;">');
                    }
                });
                    //add a column filter recovery gap
                view.$el.find('.datagrid-body-container').prepend('

');

            },

            showColumnFilter: function(e){
                var $el = $(e.currentTarget);
                var $searchBox = $el.parent().find('.columnFilter').toggle();
                if($searchBox.offset()){
                    $searchBox.focus().width($el.parent().width()).position({
                        of:$el.parent(),
                    });
                }

            },

            closeColumnFilter: function(e){
                var $el = $(e.currentTarget);
                var val = $el.val();
                if(val){
                    if($el.data().filter){
                        $el.data().filter.text(val);
                    }else {
                        var $filter = $('').text(val).appendTo($el.parent());
                        $el.data('filter', $filter);
                    }
                    $el.data().filter.position({
                        my: 'right bottom',
                        at: 'right top',
                        of: $el.parent()
                    });
                }else {
                    if($el.data().filter) $el.data().filter.remove();
                    delete $el.data().filter;
                }
                $el.hide();
            },

            applyFilter: function(e){
                if(e.keyCode === 13){
                    $(e.currentTarget).focusout();
                    //TBI
                }
            }
        },
    });
})(Application);
<|endoftext|>