<commit_before>'use strict';

const _ = require('lodash');
const dotty = require('dotty');
const traverse = require('traverse');
const TransformUtil = require('./transform-util');

class JsonMapper {
  /**
   * @param sourceObject Object for source data
   * @param mappingObject Object that defines new object structure
   * @param transformSource Source for transform and conditional functions
   * @param preProcess (optional) Function that preprocesses all mapped values
   */
  constructor(sourceObject, mappingObject, transformSource, preProcess) {
    if (!_.isObject(sourceObject)) {
      throw new Error('No source object provided');
    }
    if (!_.isObject(mappingObject)) {
      throw new Error('No mapping provided');
    }
    this.sourceObject = sourceObject;
    this.mappingObject = mappingObject;
    this.preProcess = preProcess;
    this.transformUtil = new TransformUtil(transformSource);
  }

  /**
   * @returns new JSON object based on the given mapping structure
   */
  map() {
    // Traverse has a different context
    const self = this;
    const replaceWithMappedValue = function (value) {
      const valueIsObject = _.isObject(value);
      const valueHasStringSource = valueIsObject && _.isString(value._source || value._sources);
      const valueHasArraySource = valueIsObject && _.isArray(value._source || value._sources);
      if (valueHasStringSource || valueHasArraySource) {
        this.update(self._mapValue(value));
      }
    };
    // First step: replace all _source tags in parameters/conditions/defaults
    // This is necessary so the function parameters are resolved, e.g.
    // { _source: "key1", _transform: { func: [{ _source: "key2" }] } }
    // In this case _source for key2 has to be replaced before transforming key1
    const mappingObjectWithResolvedParameters = traverse.map(this.mappingObject, function (value) {
      if (this.path.indexOf('_condition') !== -1 || this.path.indexOf('_conditions') !== -1 ||
        this.path.indexOf('_transform') !== -1 || this.path.indexOf('_transforms') !== -1 ||
        this.path.indexOf('_default') !== -1) {
        replaceWithMappedValue.bind(this)(value);
      }
    });
    return traverse.map(mappingObjectWithResolvedParameters, function (value) {
      replaceWithMappedValue.bind(this)(value);
    });
  }

  _mapValue(valueMapping) {
    const conditionFunctions = valueMapping._condition || valueMapping._conditions;
    const defaultValue = valueMapping._default;
    const sourceValues = this._resolveSource(valueMapping._source || valueMapping._sources);
    const transformFunctions = this.transformUtil.resolveTransformConditions(sourceValues,
      valueMapping._transform || valueMapping._transforms);

    // Condition not met -> ignore transforms and return default immediately
    if (conditionFunctions && !this.transformUtil.checkCondition(sourceValues,
        conditionFunctions)) {
      return defaultValue;
    }

    let mappedValue = sourceValues;
    if (_.isFunction(this.preProcess)) {
      // For multiple source values, preprocess all independently
      if (_.isArray(sourceValues)) {
        mappedValue = sourceValues.map(sourceValue => this.preProcess(sourceValue));
      } else {
        mappedValue = this.preProcess(sourceValues);
      }
    }
    // If source value (or preprocessed value) is undefined, ignore transforms
    if (transformFunctions && !_.isUndefined(mappedValue)) {
      mappedValue = this.transformUtil.transformValue(mappedValue, transformFunctions);
    }
    // Default value is returned when ->
    // 1) source value is undefined and no preprocess is defined
    // 2) preprocessed value is undefined
    // 3) result of transforms is undefined or throws error
    return _.isUndefined(mappedValue) ? defaultValue : mappedValue;
  }

  _resolveSource(sourceKeyPath) {
    if (_.isArray(sourceKeyPath)) {
      const sourceValues = sourceKeyPath.map(keyPath => this._resolveKeyPath(keyPath));
      // Undefined values are kept in the array (to match indexes of source array)
      // If all array values are undefined, undefined is returned (and the default value is used)
      return sourceValues.every(_.isUndefined) ? undefined : sourceValues;
    }
    return this._resolveKeyPath(sourceKeyPath);
  }

  _resolveKeyPath(keyPath) {
    // Use dotty.search is the path contains wildcards
    if (keyPath.indexOf('*') !== -1) {
      const result = dotty
        .search(this.sourceObject, keyPath)
        .filter(searchResult => searchResult !== undefined);
      if (result.length === 0) return undefined;
      // If there is only a single result, return it directly
      if (result.length === 1) return result[0];
      return result;
    }
    return dotty.get(this.sourceObject, keyPath);
  }
}

module.exports.map = (sourceObject, mappingObject, transformSource, preProcess) => {
  const jsonMapper = new JsonMapper(sourceObject, mappingObject, transformSource, preProcess);
  return jsonMapper.map();
};
<commit_msg>Refactor traverse<commit_after>'use strict';

const _ = require('lodash');
const dotty = require('dotty');
const traverse = require('traverse');
const TransformUtil = require('./transform-util');

class JsonMapper {
  /**
   * @param sourceObject Object for source data
   * @param mappingObject Object that defines new object structure
   * @param transformSource Source for transform and conditional functions
   * @param preProcess (optional) Function that preprocesses all mapped values
   */
  constructor(sourceObject, mappingObject, transformSource, preProcess) {
    if (!_.isObject(sourceObject)) {
      throw new Error('No source object provided');
    }
    if (!_.isObject(mappingObject)) {
      throw new Error('No mapping provided');
    }
    this.sourceObject = sourceObject;
    this.mappingObject = mappingObject;
    this.preProcess = preProcess;
    this.transformUtil = new TransformUtil(transformSource);
  }

  /**
   * @returns new JSON object based on the given mapping structure
   */
  map() {
    // Traverse has a different context
    const self = this;
    const replaceWithMappedValue = function (value) {
      const valueIsObject = _.isObject(value);
      const valueHasStringSource = valueIsObject && _.isString(value._source || value._sources);
      const valueHasArraySource = valueIsObject && _.isArray(value._source || value._sources);
      if (valueHasStringSource || valueHasArraySource) {
        this.update(self._mapValue(value));
      }
    };
    // First step: replace all _source tags in parameters/conditions/defaults
    // This is necessary so the function parameters are resolved, e.g.
    // { _source: "key1", _transform: { func: [{ _source: "key2" }] } }
    // In this case _source for key2 has to be replaced before transforming key1
    // TODO: This only works for nesting of one level,
    //       ideally the traverse would start on the deepest level (not supported by traverse-js)
    const keysToResolve = ['_condition', '_conditions', '_transform', '_transforms', '_default'];
    const mappingObjectWithResolvedParameters = traverse.map(this.mappingObject, function (value) {
      if (_.intersection(this.path, keysToResolve).length > 0) {
        replaceWithMappedValue.bind(this)(value);
      }
    });
    return traverse.map(mappingObjectWithResolvedParameters, function (value) {
      replaceWithMappedValue.bind(this)(value);
    });
  }

  _mapValue(valueMapping) {
    const conditionFunctions = valueMapping._condition || valueMapping._conditions;
    const defaultValue = valueMapping._default;
    const sourceValues = this._resolveSource(valueMapping._source || valueMapping._sources);
    const transformFunctions = this.transformUtil.resolveTransformConditions(sourceValues,
      valueMapping._transform || valueMapping._transforms);

    // Condition not met -> ignore transforms and return default immediately
    if (conditionFunctions && !this.transformUtil.checkCondition(sourceValues,
        conditionFunctions)) {
      return defaultValue;
    }

    let mappedValue = sourceValues;
    if (_.isFunction(this.preProcess)) {
      // For multiple source values, preprocess all independently
      if (_.isArray(sourceValues)) {
        mappedValue = sourceValues.map(sourceValue => this.preProcess(sourceValue));
      } else {
        mappedValue = this.preProcess(sourceValues);
      }
    }
    // If source value (or preprocessed value) is undefined, ignore transforms
    if (transformFunctions && !_.isUndefined(mappedValue)) {
      mappedValue = this.transformUtil.transformValue(mappedValue, transformFunctions);
    }
    // Default value is returned when ->
    // 1) source value is undefined and no preprocess is defined
    // 2) preprocessed value is undefined
    // 3) result of transforms is undefined or throws error
    return _.isUndefined(mappedValue) ? defaultValue : mappedValue;
  }

  _resolveSource(sourceKeyPath) {
    if (_.isArray(sourceKeyPath)) {
      const sourceValues = sourceKeyPath.map(keyPath => this._resolveKeyPath(keyPath));
      // Undefined values are kept in the array (to match indexes of source array)
      // If all array values are undefined, undefined is returned (and the default value is used)
      return sourceValues.every(_.isUndefined) ? undefined : sourceValues;
    }
    return this._resolveKeyPath(sourceKeyPath);
  }

  _resolveKeyPath(keyPath) {
    // Use dotty.search if the path contains wildcards
    if (keyPath.indexOf('*') !== -1) {
      const result = dotty
        .search(this.sourceObject, keyPath)
        .filter(searchResult => searchResult !== undefined);
      if (result.length === 0) return undefined;
      // If there is only a single result, return it directly
      if (result.length === 1) return result[0];
      return result;
    }
    return dotty.get(this.sourceObject, keyPath);
  }
}

module.exports.map = (sourceObject, mappingObject, transformSource, preProcess) => {
  const jsonMapper = new JsonMapper(sourceObject, mappingObject, transformSource, preProcess);
  return jsonMapper.map();
};
<|endoftext|>


<commit_before>
/** Contains code which handles creation of new polls on the client-side.*/

'use strict';

(function () {

    var optionList = document.querySelector("#options-list");
    var createButton = document.querySelector("#create-button");
    var addButton = document.querySelector("#add-option-button");
    var pollNameInput = document.querySelector("#poll-name-input");
    var optionNameInput = document.querySelector("#option-name-input");
    var apiUrl = appUrl + '/polls/create';
    //
    //

    // Returns the option parameters for a poll
    var getOptParams = function() {
        var options = document.getElementsByClassName("poll-option");
        //var res = "options=";
        var res = "";
        for (var i = 0; i < options.length; i++) {
            res += "options=" + options[i].innerHTML;
            if (i < options.length-1) res += "&";
        }
        return res;
    };

    createButton.addEventListener("click", function() {
        var params = "";
        var optParams = getOptParams();
        var pollName = pollNameInput.value;
        params += "name=" + pollName + "&" + optParams;
        console.log("Params are: " + params);
        ajaxFunctions.ajaxRequest('POST', apiUrl, function (data) {}, params);
    });

    addButton.addEventListener("click", function() {
        console.log("Poll name is " + pollNameInput.value);
        var optElem = document.createElement("li");
        optElem.setAttribute("class", "poll-option");
        optElem.innerHTML = optionNameInput.value;
        optionList.appendChild(optElem);
        optionNameInput.value = "";
    });

})();
<commit_msg>Added post callback.<commit_after>
/** Contains code which handles creation of new polls on the client-side.*/

'use strict';

(function () {

    var optionList      = document.querySelector("#options-list");
    var createButton    = document.querySelector("#create-button");
    var addButton       = document.querySelector("#add-option-button");
    var pollNameInput   = document.querySelector("#poll-name-input");
    var optionNameInput = document.querySelector("#option-name-input");
    var pollCreateMsg   = document.querySelector("#poll-create-message");

    var apiUrl = appUrl + '/polls/create';

    // Returns the option parameters for a poll
    var getOptParams = function() {
        var options = document.getElementsByClassName("poll-option");
        var res = "";
        for (var i = 0; i < options.length; i++) {
            res += "options=" + options[i].innerHTML;
            if (i < options.length-1) res += "&";
        }
        return res;
    };

    /** Send a new poll to the server using POST.*/
    createButton.addEventListener("click", function() {
        var params    = "";
        var optParams = getOptParams();
        var pollName  = pollNameInput.value;

        params += "name=" + pollName + "&" + optParams;
        console.log("Params are: " + params);

        // Callback called after POST finishes
        var postCb = function(data) {
            if (data) {
                var json = JSON.parse(data);
                pollCreateMsg.innerHTML = json.msg;
            }
        };

        ajaxFunctions.ajaxRequest('POST', apiUrl, postCb, params);
    });

    // When clicked, adds a new option to the Poll
    addButton.addEventListener("click", function() {
        console.log("Poll name is " + pollNameInput.value);
        var optElem = document.createElement("li");
        optElem.setAttribute("class", "poll-option");
        optElem.innerHTML = optionNameInput.value;
        optionList.appendChild(optElem);
        optionNameInput.value = "";
    });

})();
<|endoftext|>


<commit_before>
var models = require('../models');
var _ = require('lodash');
var cache = require('../cache');
var sass = require('node-sass');
var browserify = require('browserify');
var path = require('path');
var uuid = require('node-uuid');
var resumer = require('resumer');
var tasks = require('../../tasks');

// function protectRequire(str) {
//     var protectedVars = ['define', 'require'];
//     var initialCode = ';';
//     var postCode = ';';
//     _.each(protectedVars, function(v) {
//         initialCode += 'window._' + v + ' = window.' + v + ';';
//         initialCode += 'window.' + v + ' = undefined;';

//         postCode += 'window.' + v + ' = window._' + v + ';';
//     });

//     return initialCode + str;// + postCode;

// }

exports.index = function (req, res, next) {

    models.VisualizationType.findAll()
        .then(function(types) {
            return res.json(types);
        }).error(next);
};

exports.show = function (req, res, next) {
    models.VisualizationType.findAll({
            order: '"name" ASC'
        })
        .then(function(types) {

            return res.render('viz-types/show', {
                vizTypes: types
            });

        }).error(next);
};

exports.fetchDefaults = function (req, res, next) {

    tasks.getDefaultVisualizations(function() {
        return res.redirect('/visualization-types');
    });
};

exports.create = function (req, res, next) {

    models.VisualizationType
        .create(_.pick(req.body, 'name', 'initialDataField', 'javascript', 'styles', 'markup', 'sampleData', 'sampleOptions'))
        .then(function(type) {
            return res.json(type);
        }).error(function(err) {
            return res.status(500).send();
        });

};

exports.edit = function (req, res, next) {

    console.log('editing');

    models.VisualizationType
        .find(req.params.vid)
        .success(function(vizType) {
            return vizType.updateAttributes(_.pick(req.body, 'name', 'initialDataField', 'javascript', 'styles', 'markup'));
        })
        .success(function(vizType) {
            setTimeout(function() {
                _.each(cache.keys(), function(key) {

                    console.log(key);
                    if(key.indexOf(vizType.name) > -1) {
                        console.log('deleting ' + key);
                        cache.del(key);
                    }
                });
            }, 0);
            return res.status(200).send();
        }).error(function() {
            return res.status(500).send();
        });
};

exports.delete = function (req, res, next) {

    var vizTypeId = req.params.vid;

    models.VisualizationType
        .find(vizTypeId)
        .then(function(vizType) {
            vizType.destroy().success(function() {
                return res.json(vizType);
            }).error(next);
        }).error(next);
};

exports.getDelete = function(req, res, next) {

    var vizTypeId = req.params.vid;

    models.VisualizationType
        .find(vizTypeId)
        .then(function(vizType) {
            vizType.destroy().success(function() {
                return res.redirect('/visualization-types/');
            }).error(next);
        }).error(next);
};

exports.preview = function(req, res, next) {

    var url = req.query.url;
    var file = req.query.file;

    var tmpPath = path.resolve(__dirname + '/../../tmp/js-build/' + uuid.v4() + '/viz/');

    req.session.lastBundlePath = tmpPath;

    var vizTypePromise;

    if(req.query.url) {
        var url = req.query.url;
        var name = url;
        if(req.query.path) {
            name += '/' + req.query.path;
        }
        vizTypePromise = models.VisualizationType
            .createFromRepoURL(url, { name: name }, {preview: true, path: req.query.path});
    } else if(req.query.path && process.env.NODE_ENV !== 'production') {
        var p = path.resolve(req.query.path);
        vizTypePromise = models.VisualizationType
            .createFromFolder(p, { name: p}, {preview: true});
    }

    vizTypePromise
        .then(function(vizType) {

            console.log('created viz preview');

            vizType.exportToFS(tmpPath)
                .spread(function() {
                    var b = browserify();
                    var stream = resumer().queue(vizType.javascript).end();
                    b.require(stream, {
                        basedir: tmpPath,
                        expose: 'viz/' + vizType.name
                    });

                    b.bundle(function(err, buf) {

                        if(err) {
                            return next(err);
                        }

                        // var javascript = protectRequire(buf.toString('utf8'));
                        var javascript = buf.toString('utf8');

                        if(vizType.styles) {
                            var scssData = '#lightning-body {\n';
                            scssData += vizType.styles + '\n';
                            scssData += '\n}';
                            sass.render({
                                data: scssData,
                                success: function(css) {

                                    return res.render('viz-types/preview-editor', {
                                        vizType: vizType,
                                        javascript: javascript,
                                        css: css
                                    });

                                }
                            });
                        } else {

                            return res.render('viz-types/preview-editor', {
                                vizType: vizType,
                                javascript: javascript,
                                css: ''
                            });
                        }

                    });

                });

        }).fail(function(err) {
            next(err);
        });

};

exports.importViz = function(req, res, next) {

    var backURL = req.header('Referer');
    var name = req.body.name;
    var url = req.body.url;

    console.log(name);
    console.log(url);

    models.VisualizationType
        .createFromRepoURL(url, { name: name})
        .then(function() {
            return res.redirect(backURL);
        }).fail(function(err) {
            next(err);
        });
};

exports.editor = function (req, res, next) {

    models.VisualizationType.find(req.params.vid)
        .then(function(type) {

            return res.render('viz-types/editor', {
                vizType: type
            });

        }).error(next);
};

<commit_msg>revert change to viztype controller<commit_after>var models = require('../models');
var _ = require('lodash');
var cache = require('../cache');
var sass = require('node-sass');
var browserify = require('browserify');
var path = require('path');
var uuid = require('node-uuid');
var resumer = require('resumer');
var tasks = require('../../tasks');

// function protectRequire(str) {
//     var protectedVars = ['define', 'require'];
//     var initialCode = ';';
//     var postCode = ';';
//     _.each(protectedVars, function(v) {
//         initialCode += 'window._' + v + ' = window.' + v + ';';
//         initialCode += 'window.' + v + ' = undefined;';

//         postCode += 'window.' + v + ' = window._' + v + ';';
//     });

//     return initialCode + str;// + postCode;

// }

exports.index = function (req, res, next) {

    models.VisualizationType.findAll()
        .then(function(types) {
            return res.json(types);
        }).error(next);
};

exports.show = function (req, res, next) {
    models.VisualizationType.findAll()
        .then(function(types) {

            return res.render('viz-types/show', {
                vizTypes: types
            });

        }).error(next);
};

exports.fetchDefaults = function (req, res, next) {

    tasks.getDefaultVisualizations(function() {
        return res.redirect('/visualization-types');
    });
};

exports.create = function (req, res, next) {

    models.VisualizationType
        .create(_.pick(req.body, 'name', 'initialDataField', 'javascript', 'styles', 'markup', 'sampleData', 'sampleOptions'))
        .then(function(type) {
            return res.json(type);
        }).error(function(err) {
            return res.status(500).send();
        });

};

exports.edit = function (req, res, next) {

    console.log('editing');

    models.VisualizationType
        .find(req.params.vid)
        .success(function(vizType) {
            return vizType.updateAttributes(_.pick(req.body, 'name', 'initialDataField', 'javascript', 'styles', 'markup'));
        })
        .success(function(vizType) {
            setTimeout(function() {
                _.each(cache.keys(), function(key) {

                    console.log(key);
                    if(key.indexOf(vizType.name) > -1) {
                        console.log('deleting ' + key);
                        cache.del(key);
                    }
                });
            }, 0);
            return res.status(200).send();
        }).error(function() {
            return res.status(500).send();
        });
};

exports.delete = function (req, res, next) {

    var vizTypeId = req.params.vid;

    models.VisualizationType
        .find(vizTypeId)
        .then(function(vizType) {
            vizType.destroy().success(function() {
                return res.json(vizType);
            }).error(next);
        }).error(next);
};

exports.getDelete = function(req, res, next) {

    var vizTypeId = req.params.vid;

    models.VisualizationType
        .find(vizTypeId)
        .then(function(vizType) {
            vizType.destroy().success(function() {
                return res.redirect('/visualization-types/');
            }).error(next);
        }).error(next);
};

exports.preview = function(req, res, next) {

    var url = req.query.url;
    var file = req.query.file;

    var tmpPath = path.resolve(__dirname + '/../../tmp/js-build/' + uuid.v4() + '/viz/');

    req.session.lastBundlePath = tmpPath;

    var vizTypePromise;

    if(req.query.url) {
        var url = req.query.url;
        var name = url;
        if(req.query.path) {
            name += '/' + req.query.path;
        }
        vizTypePromise = models.VisualizationType
            .createFromRepoURL(url, { name: name }, {preview: true, path: req.query.path});
    } else if(req.query.path && process.env.NODE_ENV !== 'production') {
        var p = path.resolve(req.query.path);
        vizTypePromise = models.VisualizationType
            .createFromFolder(p, { name: p}, {preview: true});
    }

    vizTypePromise
        .then(function(vizType) {

            console.log('created viz preview');

            vizType.exportToFS(tmpPath)
                .spread(function() {
                    var b = browserify();
                    var stream = resumer().queue(vizType.javascript).end();
                    b.require(stream, {
                        basedir: tmpPath,
                        expose: 'viz/' + vizType.name
                    });

                    b.bundle(function(err, buf) {

                        if(err) {
                            return next(err);
                        }

                        // var javascript = protectRequire(buf.toString('utf8'));
                        var javascript = buf.toString('utf8');

                        if(vizType.styles) {
                            var scssData = '#lightning-body {\n';
                            scssData += vizType.styles + '\n';
                            scssData += '\n}';
                            sass.render({
                                data: scssData,
                                success: function(css) {

                                    return res.render('viz-types/preview-editor', {
                                        vizType: vizType,
                                        javascript: javascript,
                                        css: css
                                    });

                                }
                            });
                        } else {

                            return res.render('viz-types/preview-editor', {
                                vizType: vizType,
                                javascript: javascript,
                                css: ''
                            });
                        }

                    });

                });

        }).fail(function(err) {
            next(err);
        });

};

exports.importViz = function(req, res, next) {

    var backURL = req.header('Referer');
    var name = req.body.name;
    var url = req.body.url;

    console.log(name);
    console.log(url);

    models.VisualizationType
        .createFromRepoURL(url, { name: name})
        .then(function() {
            return res.redirect(backURL);
        }).fail(function(err) {
            next(err);
        });
};

exports.editor = function (req, res, next) {

    models.VisualizationType.find(req.params.vid)
        .then(function(type) {

            return res.render('viz-types/editor', {
                vizType: type
            });

        }).error(next);
};

<|endoftext|>


<commit_before>define([
	'./km-control-group',
	'./km-date',
	'./km-document-validation',
	'./km-form-languages',
	'./km-form-std-buttons',
	'./km-form-material-buttons',
	'./km-inputtext-list',
	'./km-inputtext-ml',
	'./km-link',
	'./km-notes',
	'./km-reference',
	'./km-select',
	'./km-tab',
	'./km-terms-check',
	'./km-terms-radio',
	'./km-yes-no'
], {});
<commit_msg>added km-auto-complete-server-select into injection for km directives<commit_after>define([
	'./km-control-group',
	'./km-date',
	'./km-document-validation',
	'./km-form-languages',
	'./km-form-std-buttons',
	'./km-form-material-buttons',
	'./km-inputtext-list',
	'./km-inputtext-ml',
	'./km-link',
	'./km-notes',
	'./km-reference',
	'./km-select',
	'./km-tab',
	'./km-terms-check',
	'./km-terms-radio',
	'./km-yes-no',
	'./km-auto-complete-server-select'
], {});
<|endoftext|>


<commit_before>import find from 'lodash/find'
import merge from 'lodash/merge'

import { SET_LANGUAGE } from './store/module/events'
import localeHandler from './locale'

let instance

class RouterHandler {
  constructor (Vue, router, store) {
    this.$router = router
    this.$store = store
    this.$vue = Vue

    this.$localeHandler = localeHandler(Vue)
  }

  /**
   * Applies specific functionalities to handle language redirects and URL prefixing.
   * The application will be able to add the language urlPrefix property in its URL and
   * to change the application language based on that specific parameter.
   * If that urlPrefix provided via URL is not valid or it doesn't exist the application
   * will fallback to the default language.
   * VueRouter instance is required to unlock this feature.
   */
  register () {
    if (!this.$router) {
      return
    }

    this.$router.beforeEach((to, from, next) => {
      const {
        availableLanguages,
        currentLanguage,
        forceTranslation,
        languages
      } = this.$store.getters
      const urlPrefix = to.params.lang
      const languageList = forceTranslation ? languages : availableLanguages
      const urlLanguage = find(languageList, { urlPrefix })

      /**
       * In case the language is not provided or doesn't exists,
       * the default language will be used.
       * This will only be fired on landing, because most of the time
       * the URL doesn't contain a language prefix or the user typed
       * a different language on purpose and we need to check it.
       */
      if (!urlLanguage && (!from.name || urlPrefix)) {
        return next(this.localize({ name: to.name }))
      }

      /**
       * Check if the detected language in the URL is also the current
       * translated language, otherwise it needs to be updated.
       * Browser language has prioriry over the store state
       */
      const isDiff = urlLanguage && urlLanguage.urlPrefix !== currentLanguage.urlPrefix

      if (isDiff) {
        return this.$store.dispatch(SET_LANGUAGE, urlLanguage.code).then((translations) => {
          this.$localeHandler.update(urlLanguage.code, translations)
          next()
        })
      }

      next()
    })
  }

  /**
   * Includes language in the route
   * @param  {Object} route
   * @return {Object}
   */
  localize (route) {
    const { urlPrefix, defaultCode } = this.$store.getters

    return merge(route, {
      params: {
        lang: urlPrefix || defaultCode
      }
    })
  }

  updateURL () {
    const { currentRoute } = this.$router

    if (this.$router && currentRoute) {
      this.$router.replace(this.localize({ name: currentRoute.name }))
    }
  }
}

export default function (Vue, router, store) {
  if (!instance) {
    instance = new RouterHandler(Vue, router, store)
  }

  Vue.prototype.$localize = instance.localize.bind(instance)

  return instance
}

/**
 * Route parser takes the current routes object before is injected in the VueRouter instance
 * and it returns the necessary tree structure to enable language prefixing
 * @param  {Array} routes
 * @return {Array}
 */
export const routeParser = (routes) => {
  return [
    {
      path: '/:lang',
      name: 'root',
      component: {
        template: '<router-view></router-view>'
      },
      children: routes
    },
    {
      path: '/*',
      redirect: '/en'
    }
  ]
}
<commit_msg>fix(max call stack) error with language handling in the route<commit_after>import find from 'lodash/find'
import merge from 'lodash/merge'

import { SET_LANGUAGE } from './store/module/events'
import localeHandler from './locale'

let instance

class RouterHandler {
  constructor (Vue, router, store) {
    this.$router = router
    this.$store = store
    this.$vue = Vue

    this.$localeHandler = localeHandler(Vue)
  }

  /**
   * Applies specific functionalities to handle language redirects and URL prefixing.
   * The application will be able to add the language urlPrefix property in its URL and
   * to change the application language based on that specific parameter.
   * If that urlPrefix provided via URL is not valid or it doesn't exist the application
   * will fallback to the default language.
   * VueRouter instance is required to unlock this feature.
   */
  register () {
    if (!this.$router) {
      return
    }

    this.$router.beforeEach((to, from, next) => {
      const {
        availableLanguages,
        currentLanguage,
        forceTranslation,
        languages
      } = this.$store.getters
      const urlPrefix = to.params.lang
      const languageList = forceTranslation ? languages : availableLanguages
      const urlLanguage = find(languageList, { urlPrefix })

      /**
       * In case the language is not provided or doesn't exists,
       * the default language will be used.
       * This will only be fired on landing, because most of the time
       * the URL doesn't contain a language prefix or the user typed
       * a different language on purpose and we need to check it.
       */
      if (!urlLanguage && !from.name) {
        return next(this.localize({ name: to.name }))
      }

      /**
       * Check if the detected language in the URL is also the current
       * translated language, otherwise it needs to be updated.
       * Browser language has prioriry over the store state
       */
      const isDiff = urlLanguage && urlLanguage.urlPrefix !== currentLanguage.urlPrefix

      if (isDiff) {
        return this.$store.dispatch(SET_LANGUAGE, urlLanguage.code).then((translations) => {
          this.$localeHandler.update(urlLanguage.code, translations)
          next()
        })
      }

      next()
    })
  }

  /**
   * Includes language in the route
   * @param  {Object} route
   * @return {Object}
   */
  localize (route) {
    const { urlPrefix, defaultCode } = this.$store.getters

    return merge(route, {
      params: {
        lang: urlPrefix || defaultCode
      }
    })
  }

  updateURL () {
    const { currentRoute } = this.$router

    if (this.$router && currentRoute) {
      this.$router.replace(this.localize({ name: currentRoute.name }))
    }
  }
}

export default function (Vue, router, store) {
  if (!instance) {
    instance = new RouterHandler(Vue, router, store)
  }

  Vue.prototype.$localize = instance.localize.bind(instance)

  return instance
}

/**
 * Route parser takes the current routes object before is injected in the VueRouter instance
 * and it returns the necessary tree structure to enable language prefixing
 * @param  {Array} routes
 * @return {Array}
 */
export const routeParser = (routes) => {
  return [
    {
      path: '/:lang',
      name: 'root',
      component: {
        template: '<router-view></router-view>'
      },
      children: routes
    },
    {
      path: '/*',
      redirect: '/en'
    }
  ]
}
<|endoftext|>


<commit_before>'use strict';

const chalk = require('chalk');
const methods = require('methods');
const debug = require('./util')('router');
const { bind } = require('./util');

/**
 * The routing helper
 * @memberof module:nails
**/
class Router {
  /**
   * Create the router
  **/
  constructor() {
    this.scopes = [];
    this.routes = [];
    debug('creating router');
    methods.forEach(method => {
      this[method] = this.request.bind(this, method);
    });
    bind(this, ...methods, 'request', 'ws');
    bind(this, 'scope', '_url', 'debug');
  }

  /**
   * Custom `debug` handler that indents with each scope change.
   * @private
  **/
  debug(...args) {
    if (this.scopes.length === 0) {
      debug(...args);
    } else {
      debug('  '.repeat(this.scopes.length).slice(0, -1), ...args);
    }
  }

  /**
   * “Draw” the routes. This creates a new router,
   * passes it to the function, and returns the created routes.
   * @static
   * @param {Function} f The function to call to draw the routes.
   * @returns {Array} The created routes
  **/
  static draw(f) {
    const router = new this();
    router.debug('drawing routes...');
    f.call(router, router);
    router.debug('drew', router.routes.length, 'routes.');
    return router.routes;
  }

  /**
   * @func method
   * @memberof module:nails.Router
   * @instance
   * @description
   * `request()` with `method` prefilled as *method*
   * @param {string} path The path to match, matched using `path-to-regexp`
   * @param {?string} to The controller to call, represented as a string
   * @param {?object} options More values to include in the route
   * @returns {RouteJSON} The created route
   * @see {@link module:nails.Router#request}
  **/

  /**
   * Create a route for an HTTP request.
   * @param {string} method The HTTP verb to respond to
   * @param {string} path The path to match, matched using `path-to-regexp`
   * @param {?string} to The controller to call, represented as a string
   * @param {?object} options More values to include in the route
   * @returns {RouteJSON} The created route
  **/
  request(method, path, to, options) {
    options = this._processOptions(to, options);
    options.to = this._pathToJS(options.to, path);
    method = method.toUpperCase();
    const route = Object.assign({
      type: method,
      url: this._url(path),
    }, options);
    this.routes.push(route);
    this.debug('created', method === 'GET' ? chalk.gray(method) : chalk.bold(method), 'route', chalk.underline(path) || chalk.gray('<root>'), 'to', chalk.bold(options.to));
    return route;
  }
  /**
   * Create a route for the `m-search` HTTP method
   * @returns {RouteJSON} The created route
  **/
  mSearch(...args) {
    return this.request('m-search', ...args);
  }
  /**
   * @param {...string} scopes The scopes to push onto the router
   * @param {function(Router)} f The callback to call with the router
  **/
  scope(...args) {
    const scopes = args.slice(0, -1);
    const f = args[args.length - 1];
    this.debug('entering scope', chalk.underline(scopes.join('/')));
    this.scopes = this.scopes.concat(scopes);
    f.call(this, this);
    this.scopes.length -= scopes.length;
    this.debug('leaving scope', chalk.underline(scopes.join('/')));
  }

  /**
   * @param {string} path The path to match
   * @param {string} [to] The channel to call
   * @param {Object} [options] Additional options for the route
   * @returns {RouteJSON} The route
  **/
  ws(path, to, options) {
    options = this._processOptions(to, options);
    options.to = this._pathToJS(options.to, path);
    const route = Object.assign({
      ws: true,
      url: this._url(path),
    }, options);
    this.routes.push(route);
    this.debug('created websocket channel', chalk.underline(path) || chalk.gray('<root>'), 'to', chalk.bold(options.to));
    return route;
  }

  /**
   * Handle the optional `to` and `options` arguments to routing methods
   * @param {string} [to] The `to` parameter
   * @param {Object} [options] The `options` parameter
   * @returns {Object} The options
   * @private
  **/
  _processOptions(to, options) {
    if (typeof to === 'object' && !options) {
      options = to;
    } else {
      options = options || {};
      options.to = to;
    }
    return options;
  }
  /**
   * Create the final `path` param by prepending the scopes
   * @param {string} path The initial path
   * @returns {string} The actual path
   * @private
  **/
  _url(path) {
    return `${this.scopes.length > 0 ? '/' : ''}${this.scopes.join('/')}${path.length > 0 && path !== '/' ? '/' : ''}${path}` || '/';
  }
  /**
   * Convert the path to a JS channel/controller location
   * @param {string} name The `to` parameter
   * @param {string} path The path that the route responds to
   * @returns {string} The final path
   * @private
  **/
  _pathToJS(name, path) {
    if (path.endsWith('/')) {
      path += 'index';
    }
    if (!name || name.length === 0) {
      name = path.replace(/^\//, '').replace(/\//g, '.');
    }
    if (this.scopes.length > 0) {
      if (name) {
        return `${this.scopes.join('.')}.${name}`;
      }
      return this.scopes.join('.');
    }
    return name;
  }
}
exports = module.exports = Router;
<commit_msg>Better router docs<commit_after>'use strict';

const chalk = require('chalk');
const methods = require('methods');
const debug = require('./util')('router');
const { bind } = require('./util');

/**
 * The routing helper
 * @memberof module:nails
**/
class Router {
  /**
   * Create the router
  **/
  constructor() {
    this.scopes = [];
    this.routes = [];
    debug('creating router');
    methods.forEach(method => {
      this[method] = this.request.bind(this, method);
    });
    bind(this, ...methods, 'request', 'ws');
    bind(this, 'scope', '_url', 'debug');
  }

  /**
   * Custom `debug` handler that indents with each scope change.
   * @private
  **/
  debug(...args) {
    if (this.scopes.length === 0) {
      debug(...args);
    } else {
      debug('  '.repeat(this.scopes.length).slice(0, -1), ...args);
    }
  }

  /**
   * “Draw” the routes. This creates a new router,
   * passes it to the function, and returns the created routes.
   * @static
   * @param {Function} f The function to call to draw the routes.
   * @returns {Array} The created routes
  **/
  static draw(f) {
    const router = new this();
    router.debug('drawing routes...');
    f.call(router, router);
    router.debug('drew', router.routes.length, 'routes.');
    return router.routes;
  }

  /**
   * @func method
   * @memberof module:nails.Router
   * @instance
   * @description
   * `request()` with `method` prefilled as *method*
   * @param {string} path The path to match, matched using `path-to-regexp`
   * @param {?string} to The controller to call, represented as a string
   * @param {?object} options More values to include in the route
   * @example router.get('/', 'home:index')
   * @returns {RouteJSON} The created route
   * @see {@link module:nails.Router#request}
  **/

  /**
   * Create a route for an HTTP request.
   * @param {string} method The HTTP verb to respond to
   * @param {string} path The path to match, matched using `path-to-regexp`
   * @param {?string} to The controller to call, represented as a string
   * @param {?object} options More values to include in the route
   * @returns {RouteJSON} The created route
  **/
  request(method, path, to, options) {
    options = this._processOptions(to, options);
    options.to = this._pathToJS(options.to, path);
    method = method.toUpperCase();
    const route = Object.assign({
      type: method,
      url: this._url(path),
    }, options);
    this.routes.push(route);
    this.debug('created', method === 'GET' ? chalk.gray(method) : chalk.bold(method), 'route', chalk.underline(path) || chalk.gray('<root>'), 'to', chalk.bold(options.to));
    return route;
  }
  /**
   * Create a route for the `m-search` HTTP method
   * @param {string} path The path to match, matched using `path-to-regexp`
   * @param {?string} to The controller to call, represented as a string
   * @param {?object} options More values to include in the route
   * @returns {RouteJSON} The created route
  **/
  mSearch(...args) {
    return this.request('m-search', ...args);
  }
  /**
   * @param {...string} scopes The scopes to push onto the router
   * @param {function(Router)} f The callback to call with the router
  **/
  scope(...args) {
    const scopes = args.slice(0, -1);
    const f = args[args.length - 1];
    this.debug('entering scope', chalk.underline(scopes.join('/')));
    this.scopes = this.scopes.concat(scopes);
    f.call(this, this);
    this.scopes.length -= scopes.length;
    this.debug('leaving scope', chalk.underline(scopes.join('/')));
  }

  /**
   * @param {string} path The path to match
   * @param {string} [to] The channel to call
   * @param {Object} [options] Additional options for the route
   * @returns {RouteJSON} The route
  **/
  ws(path, to, options) {
    options = this._processOptions(to, options);
    options.to = this._pathToJS(options.to, path);
    const route = Object.assign({
      ws: true,
      url: this._url(path),
    }, options);
    this.routes.push(route);
    this.debug('created websocket channel', chalk.underline(path) || chalk.gray('<root>'), 'to', chalk.bold(options.to));
    return route;
  }

  /**
   * Handle the optional `to` and `options` arguments to routing methods
   * @param {string} [to] The `to` parameter
   * @param {Object} [options] The `options` parameter
   * @returns {Object} The options
   * @private
  **/
  _processOptions(to, options) {
    if (typeof to === 'object' && !options) {
      options = to;
    } else {
      options = options || {};
      options.to = to;
    }
    return options;
  }
  /**
   * Create the final `path` param by prepending the scopes
   * @param {string} path The initial path
   * @returns {string} The actual path
   * @private
  **/
  _url(path) {
    return `${this.scopes.length > 0 ? '/' : ''}${this.scopes.join('/')}${path.length > 0 && path !== '/' ? '/' : ''}${path}` || '/';
  }
  /**
   * Convert the path to a JS channel/controller location
   * @param {string} name The `to` parameter
   * @param {string} path The path that the route responds to
   * @returns {string} The final path
   * @private
  **/
  _pathToJS(name, path) {
    if (path.endsWith('/')) {
      path += 'index';
    }
    if (!name || name.length === 0) {
      name = path.replace(/^\//, '').replace(/\//g, '.');
    }
    if (this.scopes.length > 0) {
      if (name) {
        return `${this.scopes.join('.')}.${name}`;
      }
      return this.scopes.join('.');
    }
    return name;
  }
}
exports = module.exports = Router;
<|endoftext|>


<commit_before>import store from 'store';

import About from 'components/About.vue';
import Main from 'components/Main.vue';
import NotFound from 'components/NotFound.vue';

import BadgeList from 'components/badges/List.vue';
import EventList from 'components/events/List.vue';

import Profile from 'components/users/profile/Profile.vue';

import EmailForm from 'components/authentication/EmailForm.vue';
import Reset from 'components/authentication/Reset.vue';
import ResetForm from 'components/authentication/ResetForm.vue';
import Login from 'components/authentication/Login.vue';
import Signup from 'components/authentication/Signup.vue';

import ClassList from 'components/shared/classes/List.vue';
import ClassDetail from 'components/shared/classes/ClassDetail.vue';
import ClassContainer from 'components/shared/classes/ClassContainer.vue';
import AttendanceList from 'components/shared/attendance/List.vue';

import Administration from 'components/administration/Administration.vue';
import AdministrationHome from 'components/administration/AdministrationHome.vue'
import AdminOfferings from 'components/administration/offerings/List.vue';
import AdminUsers from 'components/administration/users/List.vue';
import AdminApproval from 'components/administration/users/AwaitingApproval.vue';
import AdminPurchasables from 'components/administration/purchasables/List.vue';
import AdminScouts from 'components/administration/scouts/List.vue';
import AdminEvents from 'components/administration/events/EventsContainer.vue';
import AttendanceView from 'components/administration/attendance/AttendanceView.vue';
import ScoutContainer from 'components/administration/scouts/ScoutContainer.vue';
import ListAdmins from 'components/administration/users/admins/AdminUsersContainer.vue';
import CoordinatorDetail from 'components/administration/users/CoordinatorDetail.vue';
import UserContainer from 'components/administration/users/UserContainer.vue';

import ScoutDetails from 'components/scouts/ScoutDetail.vue';
import AttendanceDetails from 'components/stats/DetailView.vue';

import CoordinatorPage from 'components/coordinators/CoordinatorPage.vue';
import CoordinatorHome from 'components/coordinators/CoordinatorHome.vue';
import CoordinatorScouts from 'components/coordinators/scouts/List.vue';
import CoordinatorRegistration from 'components/coordinators/registrations/List.vue';
import CoordinatorAttendance from 'components/coordinators/attendance/List.vue';

import TeacherPage from 'components/teachers/TeacherPage.vue';
import TeacherHome from 'components/teachers/TeacherHome.vue';
import TeacherStats from 'components/teachers/stats/TeacherStats.vue';

import RegistrationTable from 'components/stats/RegistrationTable.vue';

export default [
  {
    path: '/',
    name: 'home',
    component: Main,
    meta: { title: 'MBU Online | Home' }
  }, {
    path: '/about',
    component: About,
    meta: { title: 'MBU Online | About' }
  }, {
    path: '/administration',
    component: Administration,
    beforeEnter: requireRole('admin'),
    redirect: 'administration/home',
    children: [
      {
        path: 'home',
        component: AdministrationHome,
        meta: { title: 'MBU Online | Administration' }
      }, {
        path: 'users',
        component: {
          render(component) { return component('router-view') }
        },
        children: [
          {
            path: 'current',
            component: UserContainer,
            redirect: 'current/all',
            children: [
              {
                path: 'all',
                component: AdminUsers,
                meta: { title: 'MBU Online | Current Users' }
              }, {
                path: ':id',
                component: CoordinatorDetail,
                meta: { title: 'MBU Online | User Detail' }
              }
            ]
          }, {
            path: 'approval',
            component: AdminApproval,
            meta: { title: 'MBU Online | Users Needing Approval' }
          }, {
            path: 'admins',
            component: ListAdmins,
            meta: { title: 'MBU Online | Administrative Users' }
          }
        ]
      }, {
        path: 'scouts',
        component: {
          render(component) { return component('router-view') }
        },
        children: [
          {
            path: 'list',
            component: ScoutContainer,
            redirect: 'list/all',
            children: [
              {
                path: 'all',
                component: AdminScouts,
                meta: { title: 'MBU Online | All Scouts' }
              }, {
                path: ':id',
                component: ScoutDetails,
                meta: { title: 'MBU Online | Scout Detail' }
              }
            ]
          }, {
            path: 'assignments',
            component: AttendanceView,
            meta: { title: 'MBU Online | Assignments' },
            redirect: 'assignments/list',
            children: [
              {
                path: 'list',
                component: RegistrationTable,
              }, {
                path: 'detail',
                component: AttendanceList
              }
            ]
          }
        ]
      }, {
        path: 'events',
        component: {
          render(component) { return component('router-view') }
        },
        children: [
          {
            path: 'all',
            component: AdminEvents,
            meta: { title: 'MBU Online | All Events' }
          }, {
            path: 'purchasables',
            component: AdminPurchasables,
            meta: { title: 'MBU Online | Items for Purchase' }
          }, {
            path: 'offerings',
            component: AdminOfferings,
            meta: { title: 'MBU Online | Class Offerings' }
          }, {
            path: 'badges',
            component: BadgeList,
            meta: { title: 'MBU Online | Available Badges' }
          }
        ]
      }, {
        path: 'classes',
        component: ClassContainer,
        redirect: 'classes/all',
        children: [
          {
            path: 'all',
            component: ClassList,
            meta: { title: 'MBU Online | All Classes' }
          }, {
            path: ':eventId/:id',
            component: ClassDetail,
            meta: { title: 'MBU Online | Class Detail' },
            props(route) {
              return {
                offeringId: Number(route.params.id),
                eventId: Number(route.params.eventId)
              }
            }
          }
        ]
      }
    ]
  }, {
    path: '/coordinator',
    component: CoordinatorPage,
    beforeEnter: requireRole('coordinator'),
    redirect: 'coordinator/home',
    children: [
      {
        path: 'home',
        component: CoordinatorHome,
        meta: { title: 'MBU Online | Coordinator Home' }
      }, {
        path: 'scouts',
        component: CoordinatorScouts,
        meta: { title: 'MBU Online | Your Scouts' }
      }, {
        path: 'registrations',
        component: CoordinatorRegistration,
        meta: { title: 'MBU Online | Registrations' }
      }, {
        path: 'attendance',
        component: CoordinatorAttendance,
        redirect: 'attendance/list',
        children: [
          {
            path: 'detail',
            component: AttendanceDetails,
            meta: { title: 'MBU Online | Attendance Details' }
          }, {
            path: 'list',
            component: RegistrationTable,
            meta: { title: 'MBU Online | Attendance' }
          }
        ]
      }
    ]
  }, {
    path: '/teacher',
    component: TeacherPage,
    beforeEnter: requireRole('teacher'),
    redirect: '/teacher/home',
    children: [
      {
        path: 'home',
        component: TeacherHome,
        meta: { title: 'MBU Online | Instructor Home' }
      }, {
        path: 'assignments',
        component: AttendanceView,
        meta: { title: 'MBU Online | Statistics' },
        redirect: 'assignments/list',
        children: [
          {
            path: 'detail',
            component: AttendanceList,
          }, {
            path: 'list',
            component: RegistrationTable
          }
        ]
      }, {
        path: 'classes',
        component: ClassContainer,
        redirect: 'classes/all',
        children: [
          {
            path: 'all',
            component: ClassList,
            meta: { title: 'MBU Online | All Classes' }
          }, {
            path: ':eventId/:id',
            component: ClassDetail,
            meta: { title: 'MBU Online | Class Detail' },
            props(route) {
              return {
                offeringId: Number(route.params.id),
                eventId: Number(route.params.eventId)
              }
            }
          }
        ]
      }, {
        path: 'assignments',
        component: AttendanceList,
        meta: { title: 'MBU Online | Assignments' }
      }
    ]
  }, {
    path: '/events',
    component: EventList,
    meta: { title: 'MBU Online | Events' }
  }, {
    path: '/badges',
    component: BadgeList,
    meta: { title: 'MBU Online | Badges' }
  }, {
    path: '/signup',
    component: Signup,
    meta: { title: 'MBU Online | Sign Up' }
  }, {
    path: '/login',
    component: Login,
    meta: { title: 'MBU Online | Log In' }
  }, {
    path: '/reset',
    component: Reset,
    meta: { title: 'MBU Online | Reset Your Password' },
    children: [
      {
        path: '',
        component: EmailForm
      }, {
        path: ':resetToken',
        component: ResetForm
      }
    ]
  }, {
    path: '/profile/:id?',
    component: Profile,
    meta: { title: 'MBU Online | Your Profile' }
  }, {
    path: '*',
    component: NotFound
  }
];

function requireApproval(to, from, next) {
  if (store.getters.isApproved === undefined) {
    store.dispatch('getProfile')
      .then(() => {
        if (!store.getters.isApproved) {
          next(false);
        } else {
          next();
        }
      })
      .catch(() => {
        next(false);
      });
  } else {
    if (!store.getters.isApproved) {
      next(false);
    } else {
      next();
    }
  }
}

function requireRole(role) {
  return function (to, from, next) {
    if (store.getters.role === undefined) {
      store.dispatch('getProfile')
        .then(() => {
          if ((store.getters.role === role || store.getters.isAdmin) && store.getters.isApproved) {
            next();
          } else {
            console.warn('Role is not allowed access to this resource');
            next(false);
          }
        })
        .catch(() => {
          next(false);
        });
    } else {
      if ((store.getters.role === role || store.getters.isAdmin) && store.getters.isApproved) {
        next();
      } else {
        console.warn('Role is not allowed access to this resource');
        next(false);
      }
    }
  }
}
<commit_msg>Redirect to root on role failure<commit_after>import store from 'store';

import About from 'components/About.vue';
import Main from 'components/Main.vue';
import NotFound from 'components/NotFound.vue';

import BadgeList from 'components/badges/List.vue';
import EventList from 'components/events/List.vue';

import Profile from 'components/users/profile/Profile.vue';

import EmailForm from 'components/authentication/EmailForm.vue';
import Reset from 'components/authentication/Reset.vue';
import ResetForm from 'components/authentication/ResetForm.vue';
import Login from 'components/authentication/Login.vue';
import Signup from 'components/authentication/Signup.vue';

import ClassList from 'components/shared/classes/List.vue';
import ClassDetail from 'components/shared/classes/ClassDetail.vue';
import ClassContainer from 'components/shared/classes/ClassContainer.vue';
import AttendanceList from 'components/shared/attendance/List.vue';

import Administration from 'components/administration/Administration.vue';
import AdministrationHome from 'components/administration/AdministrationHome.vue'
import AdminOfferings from 'components/administration/offerings/List.vue';
import AdminUsers from 'components/administration/users/List.vue';
import AdminApproval from 'components/administration/users/AwaitingApproval.vue';
import AdminPurchasables from 'components/administration/purchasables/List.vue';
import AdminScouts from 'components/administration/scouts/List.vue';
import AdminEvents from 'components/administration/events/EventsContainer.vue';
import AttendanceView from 'components/administration/attendance/AttendanceView.vue';
import ScoutContainer from 'components/administration/scouts/ScoutContainer.vue';
import ListAdmins from 'components/administration/users/admins/AdminUsersContainer.vue';
import CoordinatorDetail from 'components/administration/users/CoordinatorDetail.vue';
import UserContainer from 'components/administration/users/UserContainer.vue';

import ScoutDetails from 'components/scouts/ScoutDetail.vue';
import AttendanceDetails from 'components/stats/DetailView.vue';

import CoordinatorPage from 'components/coordinators/CoordinatorPage.vue';
import CoordinatorHome from 'components/coordinators/CoordinatorHome.vue';
import CoordinatorScouts from 'components/coordinators/scouts/List.vue';
import CoordinatorRegistration from 'components/coordinators/registrations/List.vue';
import CoordinatorAttendance from 'components/coordinators/attendance/List.vue';

import TeacherPage from 'components/teachers/TeacherPage.vue';
import TeacherHome from 'components/teachers/TeacherHome.vue';
import TeacherStats from 'components/teachers/stats/TeacherStats.vue';

import RegistrationTable from 'components/stats/RegistrationTable.vue';

export default [
  {
    path: '/',
    name: 'home',
    component: Main,
    meta: { title: 'MBU Online | Home' }
  }, {
    path: '/about',
    component: About,
    meta: { title: 'MBU Online | About' }
  }, {
    path: '/administration',
    component: Administration,
    beforeEnter: requireRole('admin'),
    redirect: 'administration/home',
    children: [
      {
        path: 'home',
        component: AdministrationHome,
        meta: { title: 'MBU Online | Administration' }
      }, {
        path: 'users',
        component: {
          render(component) { return component('router-view') }
        },
        children: [
          {
            path: 'current',
            component: UserContainer,
            redirect: 'current/all',
            children: [
              {
                path: 'all',
                component: AdminUsers,
                meta: { title: 'MBU Online | Current Users' }
              }, {
                path: ':id',
                component: CoordinatorDetail,
                meta: { title: 'MBU Online | User Detail' }
              }
            ]
          }, {
            path: 'approval',
            component: AdminApproval,
            meta: { title: 'MBU Online | Users Needing Approval' }
          }, {
            path: 'admins',
            component: ListAdmins,
            meta: { title: 'MBU Online | Administrative Users' }
          }
        ]
      }, {
        path: 'scouts',
        component: {
          render(component) { return component('router-view') }
        },
        children: [
          {
            path: 'list',
            component: ScoutContainer,
            redirect: 'list/all',
            children: [
              {
                path: 'all',
                component: AdminScouts,
                meta: { title: 'MBU Online | All Scouts' }
              }, {
                path: ':id',
                component: ScoutDetails,
                meta: { title: 'MBU Online | Scout Detail' }
              }
            ]
          }, {
            path: 'assignments',
            component: AttendanceView,
            meta: { title: 'MBU Online | Assignments' },
            redirect: 'assignments/list',
            children: [
              {
                path: 'list',
                component: RegistrationTable,
              }, {
                path: 'detail',
                component: AttendanceList
              }
            ]
          }
        ]
      }, {
        path: 'events',
        component: {
          render(component) { return component('router-view') }
        },
        children: [
          {
            path: 'all',
            component: AdminEvents,
            meta: { title: 'MBU Online | All Events' }
          }, {
            path: 'purchasables',
            component: AdminPurchasables,
            meta: { title: 'MBU Online | Items for Purchase' }
          }, {
            path: 'offerings',
            component: AdminOfferings,
            meta: { title: 'MBU Online | Class Offerings' }
          }, {
            path: 'badges',
            component: BadgeList,
            meta: { title: 'MBU Online | Available Badges' }
          }
        ]
      }, {
        path: 'classes',
        component: ClassContainer,
        redirect: 'classes/all',
        children: [
          {
            path: 'all',
            component: ClassList,
            meta: { title: 'MBU Online | All Classes' }
          }, {
            path: ':eventId/:id',
            component: ClassDetail,
            meta: { title: 'MBU Online | Class Detail' },
            props(route) {
              return {
                offeringId: Number(route.params.id),
                eventId: Number(route.params.eventId)
              }
            }
          }
        ]
      }
    ]
  }, {
    path: '/coordinator',
    component: CoordinatorPage,
    beforeEnter: requireRole('coordinator'),
    redirect: 'coordinator/home',
    children: [
      {
        path: 'home',
        component: CoordinatorHome,
        meta: { title: 'MBU Online | Coordinator Home' }
      }, {
        path: 'scouts',
        component: CoordinatorScouts,
        meta: { title: 'MBU Online | Your Scouts' }
      }, {
        path: 'registrations',
        component: CoordinatorRegistration,
        meta: { title: 'MBU Online | Registrations' }
      }, {
        path: 'attendance',
        component: CoordinatorAttendance,
        redirect: 'attendance/list',
        children: [
          {
            path: 'detail',
            component: AttendanceDetails,
            meta: { title: 'MBU Online | Attendance Details' }
          }, {
            path: 'list',
            component: RegistrationTable,
            meta: { title: 'MBU Online | Attendance' }
          }
        ]
      }
    ]
  }, {
    path: '/teacher',
    component: TeacherPage,
    beforeEnter: requireRole('teacher'),
    redirect: '/teacher/home',
    children: [
      {
        path: 'home',
        component: TeacherHome,
        meta: { title: 'MBU Online | Instructor Home' }
      }, {
        path: 'assignments',
        component: AttendanceView,
        meta: { title: 'MBU Online | Statistics' },
        redirect: 'assignments/list',
        children: [
          {
            path: 'detail',
            component: AttendanceList,
          }, {
            path: 'list',
            component: RegistrationTable
          }
        ]
      }, {
        path: 'classes',
        component: ClassContainer,
        redirect: 'classes/all',
        children: [
          {
            path: 'all',
            component: ClassList,
            meta: { title: 'MBU Online | All Classes' }
          }, {
            path: ':eventId/:id',
            component: ClassDetail,
            meta: { title: 'MBU Online | Class Detail' },
            props(route) {
              return {
                offeringId: Number(route.params.id),
                eventId: Number(route.params.eventId)
              }
            }
          }
        ]
      }, {
        path: 'assignments',
        component: AttendanceList,
        meta: { title: 'MBU Online | Assignments' }
      }
    ]
  }, {
    path: '/events',
    component: EventList,
    meta: { title: 'MBU Online | Events' }
  }, {
    path: '/badges',
    component: BadgeList,
    meta: { title: 'MBU Online | Badges' }
  }, {
    path: '/signup',
    component: Signup,
    meta: { title: 'MBU Online | Sign Up' }
  }, {
    path: '/login',
    component: Login,
    meta: { title: 'MBU Online | Log In' }
  }, {
    path: '/reset',
    component: Reset,
    meta: { title: 'MBU Online | Reset Your Password' },
    children: [
      {
        path: '',
        component: EmailForm
      }, {
        path: ':resetToken',
        component: ResetForm
      }
    ]
  }, {
    path: '/profile/:id?',
    component: Profile,
    meta: { title: 'MBU Online | Your Profile' }
  }, {
    path: '*',
    component: NotFound
  }
];

function requireApproval(to, from, next) {
  if (store.getters.isApproved === undefined) {
    store.dispatch('getProfile')
      .then(() => {
        if (!store.getters.isApproved) {
          next('/');
        } else {
          next();
        }
      })
      .catch(() => {
        next('/');
      });
  } else {
    if (!store.getters.isApproved) {
      next('/');
    } else {
      next();
    }
  }
}

function requireRole(role) {
  return function (to, from, next) {
    if (store.getters.role === undefined) {
      store.dispatch('getProfile')
        .then(() => {
          if ((store.getters.role === role || store.getters.isAdmin) && store.getters.isApproved) {
            next();
          } else {
            console.warn('Role is not allowed access to this resource');
            next('/');
          }
        })
        .catch(() => {
          next('/');
        });
    } else {
      if ((store.getters.role === role || store.getters.isAdmin) && store.getters.isApproved) {
        next();
      } else {
        console.warn('Role is not allowed access to this resource');
        next('/');
      }
    }
  }
}
<|endoftext|>


<commit_before>import Ember from 'ember';

export function mobilityExplorerLink(params, hash) {
  let link = 'https://mobility-explorer.netlify.com/#/'
  if (hash.query == 'operator') {
    link = link + 'operators?bbox=' + hash.operator.get('geometryToBboxString') + '&onestop_id=' + hash.operator.get('onestop_id');
  } else if (hash.query == 'routesByOperator') {
    link = link + 'routes?bbox=' + hash.operator.get('geometryToBboxString') + '&operated_by=' + hash.operator.get('onestop_id');
  } else if (hash.query == 'stopsByOperator') {
    link = link + 'stops?bbox=' + hash.operator.get('geometryToBboxString') + '&served_by=' + hash.operator.get('onestop_id');
  }
  return new Ember.Handlebars.SafeString(`<a href="${link}">${hash.text}</a>`);
}

export default Ember.Helper.helper(mobilityExplorerLink);
<commit_msg>Mobility Explorer links<commit_after>import Ember from 'ember';

export function mobilityExplorerLink(params, hash) {
  let link = 'https://mobility-explorer.interline.io/#/';
  if (hash.query === 'operator') {
    link = link + 'operators?bbox=' + hash.operator.get('geometryToBboxString') + '&onestop_id=' + hash.operator.get('onestop_id');
  } else if (hash.query === 'routesByOperator') {
    link = link + 'routes?bbox=' + hash.operator.get('geometryToBboxString') + '&operated_by=' + hash.operator.get('onestop_id');
  } else if (hash.query === 'stopsByOperator') {
    link = link + 'stops?bbox=' + hash.operator.get('geometryToBboxString') + '&served_by=' + hash.operator.get('onestop_id');
  }
  return new Ember.Handlebars.SafeString(`<a href="${link}">${hash.text}</a>`);
}

export default Ember.Helper.helper(mobilityExplorerLink);
<|endoftext|>


<commit_before>/* UMD.define */ (function (root, factory) {
    if (typeof customLoader === 'function'){ customLoader(factory, 'router'); }
    else if (typeof define === 'function' && define.amd){ define([], factory); }
    else if(typeof exports === 'object'){ module.exports = factory(); }
    else{ root.returnExports = factory();
        window.router = factory(); }
}(this, function () {

    var
        router,
        returnHash,
        uidCount = 0,
        currentState = {},
        callbacks = {id:'callbacks'},
        wildbacks = {id:'wildbacks'},
        beforebacks = {id:'beforebacks'},
        leavebacks = {id:'leavebacks'},
        notFound = {},
        initTimer,
        initialize = function () {
            clearTimeout(initTimer);
            initTimer = setTimeout(function () {
                window.addEventListener('hashchange', function (event) {
                    // IE does not have URLs in the event, so use previous
                    var prev = router.current ? router.current.url : '';
                    router.emit(parse(event.newURL || location.href, prev));
                });
                router.emit(parse(location.href));
                initialize = function () {};
            },100);
        };

    function uid () {
        uidCount++;
        return 'route-' + uidCount;
    }

    // TODO:
    // more than one on('/route')
    // more than one REST param
    // nested routes? like for tabs?
    // wildcards? any? So route can be inspected

    function addCallback (object, route, callback, prop) {
        var id = uid();
        object[route] = object[route] || {};
        object[route][id] = {
            callback: callback,
            prop: prop
        };
        return {
            remove: function () {
                if(object[route]) {
                    delete object[route][id];
                    if (!Object.keys(object[route]).length) {
                        delete object[route];
                    }
                }
            }
        };
    }

    router = {

        on: function (route, callback) {
            initialize();
            var id;
            if(route === 'not-found'){
                id = uid();
                notFound[id] = {
                    callback: callback
                };
                return {
                    remove: function () {
                        delete callbacks[id];
                    }
                };
            }

            // /worksheet/employees/:id
            // /worksheet/employees/Mike123456
            if(route.indexOf(':') > -1){
                return addCallback(wildbacks, route.split('/:')[0], callback, route.split('/:')[1]);
            }

            return addCallback(callbacks, route, callback);
        },

        before: function (route, callback) {
            initialize();
            return addCallback(beforebacks, route, callback);
        },

        leave: function (route, callback) {
            initialize();
            return addCallback(leavebacks, route, callback);
        },

        emit: function (eventDetail, skipBeforeBacks, skipLeaveBacks) {

            var
                hash = eventDetail.hash,
                phash = eventDetail.previous.hash,
                wildCardUrl,
                lastPath = getLastPath(hash);

            if(returnHash === hash){
                returnHash = null;
                return;
            }
            returnHash = null;

            this.hash = hash;

            if(!skipLeaveBacks && phash){
                if(leavebacks[phash]) {
                    Object.keys(leavebacks[phash]).forEach(function (route) {
                        if(leavebacks[phash][route] && leavebacks[phash][route].callback) {
                            leavebacks[phash][route].callback(eventDetail, function (result) {
                                if (hash === currentState.hash) {
                                    if (result) {
                                        // continue
                                        router.emit(eventDetail, false, true);
                                        router.current = eventDetail;
                                    }
                                    else if (eventDetail.previous.hash) {
                                        // reject
                                        returnHash = phash;
                                        location.hash = phash;
                                    }
                                }
                                else {
                                    console.warn('Hash has changed - cannot continue with `leave` action');
                                }
                            });
                        }else{
                            console.warn('router: callback missing for route', phash, route);
                        }
                    });

                    return;
                }
            }

            if(!skipBeforeBacks){
                if(beforebacks[hash]) {
                    Object.keys(beforebacks[hash]).forEach(function (route) {
                        beforebacks[hash][route].callback(eventDetail, function (result) {
                            if(hash === currentState.hash){
                                if(result) {
                                    router.emit(eventDetail, true);
                                    router.current = eventDetail;
                                }else if(eventDetail.previous.hash){
                                    location.hash = eventDetail.previous.hash;
                                }
                            }
                            else{
                                console.warn('Hash has changed - cannot continue with `before` action');
                            }
                        });
                    });

                    return;
                }
            }

            router.current = eventDetail;

            if(callbacks[hash]){
                Object.keys(callbacks[hash]).forEach(function (route) {
                    callbacks[hash][route].callback(eventDetail);
                });
                return;
            }

            wildCardUrl = removeLastPath(hash);
            if(wildbacks[wildCardUrl]){

                Object.keys(wildbacks[wildCardUrl]).forEach(function (route) {
                    eventDetail[wildbacks[wildCardUrl][route].prop] = lastPath;
                    wildbacks[wildCardUrl][route].callback(eventDetail);
                });

                return;
            }

            if(Object.keys(notFound).length) {
                Object.keys(notFound).forEach(function (key) {
                    notFound[key].callback(eventDetail);
                });
            }else{
                console.log('no route found (404)', hash);
            }

        }
    };

    function parse(newUrl, oldUrl){

        currentState = urlToObject(newUrl);
        // FIXME: either remove previous or stub it for IE
        currentState.previous = urlToObject(oldUrl);
        currentState.oldUrl = currentState.previous.url;

        return currentState;
    }

    function paramsToObject (params) {
        if(!params){ return null; }
        params = params.split('&');
        var o = {};
        params.forEach(function (param) {
            o[param.split('=')[0]] = normalize(param.split('=')[1]);
        });
        return o;
    }

    function urlToObject (url) {
        if(!url){
            return {};
        }
        function split(url) {
            if(url.indexOf('?')>-1){
                return url.split('?');
            }else if(url.indexOf('&')>-1){
                return [
                    url.substring(0, url.indexOf('&')),
                    url.substring(url.indexOf('&') + 1)
                ];
            }
            return [url];
        }
        var
            params = paramsToObject(split(url)[1]),
            hash = split(url)[0].split('#')[1] || '/',
            paths = hash ? hash.split('/') : [],
            map = {};

        paths.forEach(function (path) {
            map[path] = true;
        });

        if(hash.indexOf('/') !== 0){
            // should start with slash
            hash = '/';
        }
        return {
            url: url,
            hash: hash,
            paths: paths,
            map: map,
            params: params
        };
    }

    function getLastPath (url) {
        if(!url) { return ''; }
        var paths = url.split('/');
        return paths[paths.length - 1];
    }

    function removeLastPath (url) {
        if(!url) { return ''; }
        var paths = url.split('/');
        paths.pop();
        return paths.join('/');
    }

    function normalize(val){
        if(val === 'false'){
            return false;
        }else if(val === 'true'){
            return true;
        }
        if(!isNaN(parseFloat(val))){
            return parseFloat(val);
        }
        return val;
    }

    return router;
}));<commit_msg>don't block routes if previous = current<commit_after>/* UMD.define */ (function (root, factory) {
    if (typeof customLoader === 'function'){ customLoader(factory, 'router'); }
    else if (typeof define === 'function' && define.amd){ define([], factory); }
    else if(typeof exports === 'object'){ module.exports = factory(); }
    else{ root.returnExports = factory();
        window.router = factory(); }
}(this, function () {

    var
        router,
        returnHash,
        uidCount = 0,
        currentState = {},
        callbacks = {id:'callbacks'},
        wildbacks = {id:'wildbacks'},
        beforebacks = {id:'beforebacks'},
        leavebacks = {id:'leavebacks'},
        notFound = {},
        initTimer,
        initialize = function () {
            clearTimeout(initTimer);
            initTimer = setTimeout(function () {
                window.addEventListener('hashchange', function (event) {
                    // IE does not have URLs in the event, so use previous
                    var prev = router.current ? router.current.url : '';
                    router.emit(parse(event.newURL || location.href, prev));
                });
                router.emit(parse(location.href));
                initialize = function () {};
            },100);
        };

    function uid () {
        uidCount++;
        return 'route-' + uidCount;
    }

    // TODO:
    // more than one on('/route')
    // more than one REST param
    // nested routes? like for tabs?
    // wildcards? any? So route can be inspected

    function addCallback (object, route, callback, prop) {
        var id = uid();
        object[route] = object[route] || {};
        object[route][id] = {
            callback: callback,
            prop: prop
        };
        return {
            remove: function () {
                if(object[route]) {
                    delete object[route][id];
                    if (!Object.keys(object[route]).length) {
                        delete object[route];
                    }
                }
            }
        };
    }

    router = {

        on: function (route, callback) {
            initialize();
            var id;
            if(route === 'not-found'){
                id = uid();
                notFound[id] = {
                    callback: callback
                };
                return {
                    remove: function () {
                        delete callbacks[id];
                    }
                };
            }

            // /worksheet/employees/:id
            // /worksheet/employees/Mike123456
            if(route.indexOf(':') > -1){
                return addCallback(wildbacks, route.split('/:')[0], callback, route.split('/:')[1]);
            }

            return addCallback(callbacks, route, callback);
        },

        before: function (route, callback) {
            initialize();
            return addCallback(beforebacks, route, callback);
        },

        leave: function (route, callback) {
            initialize();
            return addCallback(leavebacks, route, callback);
        },

        emit: function (eventDetail, skipBeforeBacks, skipLeaveBacks) {

            var
                hash = eventDetail.hash,
                phash = eventDetail.previous.hash,
                wildCardUrl,
                lastPath = getLastPath(hash);

            if(returnHash === hash || phash === hash){
                returnHash = null;
                return;
            }
            returnHash = null;

            this.hash = hash;

            if(!skipLeaveBacks && phash){
                if(leavebacks[phash]) {
                    Object.keys(leavebacks[phash]).forEach(function (route) {
                        if(leavebacks[phash][route] && leavebacks[phash][route].callback) {
                            leavebacks[phash][route].callback(eventDetail, function (result) {
                                if (hash === currentState.hash) {
                                    if (result) {
                                        // continue
                                        ///console.log('router.leaveback.continue');
                                        router.emit(eventDetail, false, true);
                                        router.current = eventDetail;
                                    }
                                    else if (eventDetail.previous.hash) {
                                        // reject
                                        //console.log('router.leaveback.reject', eventDetail.previous.hash, phash);
                                        returnHash = phash;
                                        location.hash = phash;
                                    }
                                }
                                else {
                                    console.warn('Hash has changed - cannot continue with `leave` action');
                                }
                            });
                        }else{
                            console.warn('router: callback missing for route', phash, route);
                        }
                    });

                    return;
                }
            }

            if(!skipBeforeBacks){
                if(beforebacks[hash]) {
                    Object.keys(beforebacks[hash]).forEach(function (route) {
                        beforebacks[hash][route].callback(eventDetail, function (result) {
                            if(hash === currentState.hash){
                                if(result) {
                                    // continue
                                    console.log('router.beforeback.continue');
                                    router.emit(eventDetail, true);
                                    router.current = eventDetail;
                                }
                                else if(eventDetail.previous.hash){
                                    // reject
                                    console.log('router.beforeback.reject');
                                    location.hash = eventDetail.previous.hash;
                                }
                            }
                            else{
                                console.warn('Hash has changed - cannot continue with `before` action');
                            }
                        });
                    });

                    return;
                }
            }

            router.current = eventDetail;

            if(callbacks[hash]){
                Object.keys(callbacks[hash]).forEach(function (route) {
                    callbacks[hash][route].callback(eventDetail);
                });
                return;
            }

            wildCardUrl = removeLastPath(hash);
            if(wildbacks[wildCardUrl]){

                Object.keys(wildbacks[wildCardUrl]).forEach(function (route) {
                    eventDetail[wildbacks[wildCardUrl][route].prop] = lastPath;
                    wildbacks[wildCardUrl][route].callback(eventDetail);
                });

                return;
            }

            if(Object.keys(notFound).length) {
                Object.keys(notFound).forEach(function (key) {
                    notFound[key].callback(eventDetail);
                });
            }else{
                console.log('no route found (404)', hash);
            }

        }
    };

    function parse(newUrl, oldUrl){

        currentState = urlToObject(newUrl);
        // FIXME: either remove previous or stub it for IE
        currentState.previous = urlToObject(oldUrl);
        currentState.oldUrl = currentState.previous.url;

        return currentState;
    }

    function paramsToObject (params) {
        if(!params){ return null; }
        params = params.split('&');
        var o = {};
        params.forEach(function (param) {
            o[param.split('=')[0]] = normalize(param.split('=')[1]);
        });
        return o;
    }

    function urlToObject (url) {
        if(!url){
            return {};
        }
        function split(url) {
            if(url.indexOf('?')>-1){
                return url.split('?');
            }else if(url.indexOf('&')>-1){
                return [
                    url.substring(0, url.indexOf('&')),
                    url.substring(url.indexOf('&') + 1)
                ];
            }
            return [url];
        }
        var
            params = paramsToObject(split(url)[1]),
            hash = split(url)[0].split('#')[1] || '/',
            paths = hash ? hash.split('/') : [],
            map = {};

        paths.forEach(function (path) {
            map[path] = true;
        });

        if(hash.indexOf('/') !== 0){
            // should start with slash
            hash = '/';
        }
        return {
            url: url,
            hash: hash,
            paths: paths,
            map: map,
            params: params
        };
    }

    function getLastPath (url) {
        if(!url) { return ''; }
        var paths = url.split('/');
        return paths[paths.length - 1];
    }

    function removeLastPath (url) {
        if(!url) { return ''; }
        var paths = url.split('/');
        paths.pop();
        return paths.join('/');
    }

    function normalize(val){
        if(val === 'false'){
            return false;
        }else if(val === 'true'){
            return true;
        }
        if(!isNaN(parseFloat(val))){
            return parseFloat(val);
        }
        return val;
    }

    return router;
}));<|endoftext|>


<commit_before>var map = new maptalks.Map('map', {
  center:     [-0.113049,51.498568],
  zoom:  6,
  pitch : 40,
  attribution: {
    content: '$(attribution)'
  },
  // add 2 TileLayers with a GroupTileLayer
  baseLayer : new maptalks.GroupTileLayer('base', [
    new maptalks.TileLayer('tile1',{
      urlTemplate: 'http://{s}.tile.stamen.com/watercolor/{z}/{x}/{y}.jpg',
      'subdomains': ['a','b']
    }),
    new maptalks.TileLayer('tile2',{
      urlTemplate: 'http://korona.geog.uni-heidelberg.de/tiles/adminb/x={x}&y={y}&z={z}'
    })
  ])
});
<commit_msg>updates<commit_after>var map = new maptalks.Map('map', {
  center:     [-0.113049,51.498568],
  zoom:  6,
  pitch : 40,
  attribution: {
    content: '$(attribution)'
  },
  // add 2 TileLayers with a GroupTileLayer
  baseLayer : new maptalks.GroupTileLayer('base', [
    new maptalks.WMSTileLayer('wms', {
      'urlTemplate' : 'https://demo.boundlessgeo.com/geoserver/ows',
      'crs' : 'EPSG:3857',
      'layers' : 'ne:ne',
      'styles' : '',
      'version' : '1.3.0',
      'format': 'image/png',
      'transparent' : true,
      'uppercase' : true
    }),
    new maptalks.TileLayer('tile2',{
      urlTemplate: 'http://korona.geog.uni-heidelberg.de/tiles/adminb/x={x}&y={y}&z={z}'
    })
  ])
});
<|endoftext|>