<commit_before>/**
 * Created by theophy on 02/08/2017.
 *
 * this is used to generate our tags from our sails
 */

var _ = require("lodash");
var parsers = require("./parsers");
var formatter = require("./type-formatter");

/**
 * this is used to parse models to tags just the globalId is picked to gather our
 * tags
 * @param models
 * @returns {Array}
 * @private
 */
function _generateModels(models) {
    var tags = [];

    _.forEach(models, function (model) {

        // Do tagging for  all models. Ignoring associative tables
        if (model.globalId) {
            tags.push({name: model.globalId, identity: model.identity});
        }
    });

    return tags;
}

/**
 * this generates our definitions from our models and returns the equivalent swagger specification
 * @param models
 * @returns {{}}
 * @private
 */
function _generateDefinitions(models) {
    var defintions = {};

    _.forEach(models, function (model) {
        // Do tagging for  all models. Ignoring associative tables
        if (model.globalId) {
            defintions[model.identity] = parsers.attributes(model.attributes);
        }
    });

    return defintions;
}

/**
 * this is used to generate our default parameters and extending the ones created in our
 * sails.config[configKey].parameters to the default
 * @param config
 * @param context
 * @private
 */
function _generateParameters(config, context) {
    var params = {};

    //default parameters-> where, limit, skip, sort, populate, select, page
    params.WhereQueryParam = {
        in: 'query',
        name: 'where',
        required: false,
        type: 'string',
        description: 'This follows the standard from http://sailsjs.com/documentation/reference/blueprint-api/find-where'
    };
    params.LimitQueryParam = {
        in: 'query',
        name: 'limit',
        required: false,
        type: 'integer',
        description: 'The maximum number of records to send back (useful for pagination). Defaults to ' + config.blueprints.defaultLimit
    };
    params.SkipQueryParam = {
        in: 'query',
        name: 'skip',
        required: false,
        type: 'integer',
        description: 'The number of records to skip (useful for pagination).'
    };
    params.SortQueryParam = {
        in: 'query',
        name: 'sort',
        required: false,
        type: 'string',
        description: 'The sort order. By default, returned records are sorted by primary key value in ascending order. e.g. ?sort=lastName%20ASC'
    };

    params.PopulateQueryParam = {
        in: 'query',
        name: 'populate',
        required: false,
        type: 'string',
        description: 'check for better understanding -> http://sailsjs.com/documentation/reference/blueprint-api/find-where'
    };

    params.PageQueryParam = {
        in: 'query',
        name: 'page',
        required: false,
        type: 'integer',
        description: 'This helps with pagination and when the limit is known'
    };
    params.SelectQueryParam = {
        in: 'query',
        name: 'select',
        required: false,
        type: 'string',
        description: 'This helps with what to return for the user and its "," delimited'
    };

    params.TokenHeaderParam = {
        in: 'header',
        name: 'token',
        required: false,
        type: 'string',
        description: 'Incase we want to send header inforamtion along our request'
    };

    params.IDPathParam = {
        in: 'path',
        name: 'id',
        required: true,
        type: 'string',
        description: 'This is to identify a particular object out'
    };

    //now we extend our config.swaggerDoc.parameters
    return _.merge(params, config[context.configKey].parameters);
}

/**
 * this uses the controllers from our sails application and the routes defined in our config/routes
 * to get out all the necessary routes with their properties defined in @link parsers.routes
 * @param controllers
 * @param config this sails.config
 * @param tags model dictionary for checking if our identity is among our tag
 * @returns {{}}
 * @private
 */
function _generateRoutes(controllers, config, tags) {

    controllers = _.cloneDeep(controllers);//copy the value out without variable referencing
    //building all our routes from the custom since the custom over writes the default route
    var routes = parsers.routes(config.routes);

    _.forEach(controllers, function (controller, identity) {
        if (!routes[identity])
            routes[identity] = [];

        var blueprints = _.defaults(config.blueprints, {
            rest: true
        });

        if (blueprints.rest === true) { //if rest is true add this to default routes and actions
            ///let's extend our controllers for default blue print actions now iff that controller has a model
            if (_.find(tags, {identity: identity})) {
                controller = _.merge(controller, {
                    findOne: {
                        http_method: 'get',
                        path: identity + '/{id}',
                        summary: 'Get {identity}',
                        description: 'This is use to get a single {identity} with the supplied id'
                    },
                    find: {
                        http_method: 'get',
                        path: identity,
                        summary: 'List {identity}',
                        description: 'This is use to retrieve List of {identity}'
                    },
                    create: {
                        http_method: 'post',
                        path: identity,
                        summary: 'Create {identity}',
                        description: 'This is use to create new {identity}'
                    },
                    update: {
                        http_method: 'put',
                        path: identity + '/{id}',
                        summary: 'Update {identity}',
                        description: 'This is for updating our {identity} based on the id'
                    },
                    destroy: {
                        http_method: 'delete',
                        path: identity + '/{id}',
                        summary: 'Delete {identity}',
                        description: 'This is for deleting specified {identity} with id'
                    }
                });
            }
        }

        //let's go through all the actions in the controller, excluding identity and globalId
        var exclude = ['identity', 'globalId', 'sails'];
        _.forEach(controller, function (value, action) {
            if (exclude.indexOf(action) > -1)
                return;

            //here we check if it's in our custom routes if so don't add, simply move to the next one
            if (_.findIndex(routes[identity], {'action': action}) < 0) {
                routes[identity].push({
                    http_method: value.http_method || 'get', //as my default
                    path: value.path || (identity + '/' + action),
                    action: action,
                    keys: [], //always empty since they are directly from the controller file and not specified unless default blue prints
                    summary: value.summary,
                    description: value.description
                });
            }

        });

    });

    return routes;
}

/**
 * this is used to generate our routes from the generated routes and tags with the custom blue print
 * @param generated_routes
 * @param tags
 * @param customBlueprintMaps
 * @returns {{}}
 * @private
 */
function _generatePaths(generated_routes, tags, customBlueprintMaps) {
    var paths = {};

    _.forEach(generated_routes, function (routes, identity) {
        _.forEach(routes, function (route) {

            var tag = _.find(tags, {identity: identity});

            if (!tag) {
                //   throw new Error("No tag for this identity-" + identity); --> some controller exist without model
                console.warn("No tag for this identity '" + identity + "'");
            }

            var parameter = formatter.blueprint_parameter(route.action, customBlueprintMaps);
            if (!parameter) //which means is not in our parameters, then use the keys to get and add token for us incase of any route using header information
                parameter = _getPathParamsFromKeys(route.keys).concat({$ref: '#/parameters/TokenHeaderParam'});

            var path = {
                summary: route.summary ? route.summary.replace("{identity}", _.capitalize(identity)) : '',
                description: route.description ? route.description.replace("{identity}", _.capitalize(identity)) : '',
                tags: tag ? [tag.name] : [identity],
                produces: ['application/json'],
                consumes: ['application/json'],
                parameters: parameter.concat(_getQueryParamsFromRouteQuery(route.query)).concat(_getBodyParamsFromRouteBody(route.body)),
                responses: {
                    '200': {description: 'The requested resource'},
                    '404': {description: 'Resource not found'},
                    '500': {description: 'Internal server error'}
                }
            };

            //for our route that alters db we need json form body
            if (route.action === "create" || route.action === "update") {
                path.parameters.push({
                    "name": "body",
                    "in": "body",
                    "required": true,
                    "description": "An object defining our schema for " + _.capitalize(identity),
                    "schema": {"$ref": "#/definitions/" + identity}
                });
            }

            //standardize our link here
            var link = _standardiseLink(route.path + "/" + _processRouteKeys(route.keys));
            if (!paths[link]) //if it's undefined create it as empty object for us
                paths[link] = {};

            paths[link][route.http_method] = path;

        });
    });

    return paths;
}

/**
 * help to process route keys to swagger spec format
 * which is {key} instead of sails default /:key
 * @param keys
 * @returns {string}
 * @private
 */
function _processRouteKeys(keys) {

    var map = _.map(keys, function (key) {
        return "{" + key + "}";
    });

    return map.join("/");
}

/**
 * making our link string to look like this
 * user/route instead of /user/route/ which is not allowed by swagger spec
 * @param link
 * @returns {*}
 * @private
 */
function _standardiseLink(link) {

    //check if the first character is / if not add it
    if (!_.startsWith(link, '/'))
        link = "/" + link;

    if (_.endsWith(link, '/'))
        link = link.slice(0, -1); //remove the / by the end

    return link;
}

/**
 * this is used to generate path param from the route keys
 * @param keys
 * @returns {Array}
 * @private
 */
function _getPathParamsFromKeys(keys) {
    var params = [];

    _.forEach(keys, function (key) {
        params.push({
            in: 'path',
            name: key,
            required: true,
            type: 'string',
            description: 'This is a path param for ' + key
        });
    });

    return params;
}

/**
 * this is used to create param or custom queries for our request or route path
 * @param queries
 * @returns {Array}
 * @private
 */
function _getQueryParamsFromRouteQuery(queries) {
    var params = [];

    _.forEach(queries, function (query) {
        params.push({
            in: 'query',
            name: query,
            required: false,
            type: 'string',
            description: 'This is a query param for ' + query
        });
    });

    return params;
}

/**
 * this is used to create body type of parameter for any request that requires post or put of information
 * @param body
 * @returns {Array}
 * @private
 */
function _getBodyParamsFromRouteBody(body) {
    var param = [];

    if (!_.isEmpty(body)) {
        param.push({
            "name": "body",
            "in": "body",
            "required": true,
            "description": "An object defining our schema for this request",
            "schema": parsers.attributes(body)
        });
    }

    return param;
}

module.exports = {
    tags: _generateModels,
    definitions: _generateDefinitions,
    parameters: _generateParameters,
    routes: _generateRoutes,
    paths: _generatePaths
};

<commit_msg>add support of restPrefix and prefix for blueprint<commit_after>/**
 * Created by theophy on 02/08/2017.
 *
 * this is used to generate our tags from our sails
 */

var _ = require("lodash");
var parsers = require("./parsers");
var formatter = require("./type-formatter");

/**
 * this is used to parse models to tags just the globalId is picked to gather our
 * tags
 * @param models
 * @returns {Array}
 * @private
 */
function _generateModels(models) {
    var tags = [];

    _.forEach(models, function (model) {

        // Do tagging for  all models. Ignoring associative tables
        if (model.globalId) {
            tags.push({name: model.globalId, identity: model.identity});
        }
    });

    return tags;
}

/**
 * this generates our definitions from our models and returns the equivalent swagger specification
 * @param models
 * @returns {{}}
 * @private
 */
function _generateDefinitions(models) {
    var defintions = {};

    _.forEach(models, function (model) {
        // Do tagging for  all models. Ignoring associative tables
        if (model.globalId) {
            defintions[model.identity] = parsers.attributes(model.attributes);
        }
    });

    return defintions;
}

/**
 * this is used to generate our default parameters and extending the ones created in our
 * sails.config[configKey].parameters to the default
 * @param config
 * @param context
 * @private
 */
function _generateParameters(config, context) {
    var params = {};

    //default parameters-> where, limit, skip, sort, populate, select, page
    params.WhereQueryParam = {
        in: 'query',
        name: 'where',
        required: false,
        type: 'string',
        description: 'This follows the standard from http://sailsjs.com/documentation/reference/blueprint-api/find-where'
    };
    params.LimitQueryParam = {
        in: 'query',
        name: 'limit',
        required: false,
        type: 'integer',
        description: 'The maximum number of records to send back (useful for pagination). Defaults to ' + config.blueprints.defaultLimit
    };
    params.SkipQueryParam = {
        in: 'query',
        name: 'skip',
        required: false,
        type: 'integer',
        description: 'The number of records to skip (useful for pagination).'
    };
    params.SortQueryParam = {
        in: 'query',
        name: 'sort',
        required: false,
        type: 'string',
        description: 'The sort order. By default, returned records are sorted by primary key value in ascending order. e.g. ?sort=lastName%20ASC'
    };

    params.PopulateQueryParam = {
        in: 'query',
        name: 'populate',
        required: false,
        type: 'string',
        description: 'check for better understanding -> http://sailsjs.com/documentation/reference/blueprint-api/find-where'
    };

    params.PageQueryParam = {
        in: 'query',
        name: 'page',
        required: false,
        type: 'integer',
        description: 'This helps with pagination and when the limit is known'
    };
    params.SelectQueryParam = {
        in: 'query',
        name: 'select',
        required: false,
        type: 'string',
        description: 'This helps with what to return for the user and its "," delimited'
    };

    params.TokenHeaderParam = {
        in: 'header',
        name: 'token',
        required: false,
        type: 'string',
        description: 'Incase we want to send header inforamtion along our request'
    };

    params.IDPathParam = {
        in: 'path',
        name: 'id',
        required: true,
        type: 'string',
        description: 'This is to identify a particular object out'
    };

    //now we extend our config.swaggerDoc.parameters
    return _.merge(params, config[context.configKey].parameters);
}

/**
 * this uses the controllers from our sails application and the routes defined in our config/routes
 * to get out all the necessary routes with their properties defined in @link parsers.routes
 * @param controllers
 * @param config this sails.config
 * @param tags model dictionary for checking if our identity is among our tag
 * @returns {{}}
 * @private
 */
function _generateRoutes(controllers, config, tags) {

    controllers = _.cloneDeep(controllers);//copy the value out without variable referencing
    //building all our routes from the custom since the custom over writes the default route
    var routes = parsers.routes(config.routes);

    _.forEach(controllers, function (controller, identity) {
        if (!routes[identity])
            routes[identity] = [];

        var blueprints = _.defaults(config.blueprints, {
            rest: true
        });

      var prefix = blueprints.prefix + (blueprints.prefix != '' ? '/' : '') + blueprints.restPrefix + (blueprints.restPrefix != '' ? '/' : '')

        if (blueprints.rest === true) { //if rest is true add this to default routes and actions
            ///let's extend our controllers for default blue print actions now iff that controller has a model
            if (_.find(tags, {identity: identity})) {
                controller = _.merge(controller, {
                    findOne: {
                        http_method: 'get',
                        path:  prefix + identity + '/{id}',
                        summary: 'Get {identity}',
                        description: 'This is use to get a single {identity} with the supplied id'
                    },
                    find: {
                        http_method: 'get',
                        path: prefix + identity,
                        summary: 'List {identity}',
                        description: 'This is use to retrieve List of {identity}'
                    },
                    create: {
                        http_method: 'post',
                        path: prefix + identity,
                        summary: 'Create {identity}',
                        description: 'This is use to create new {identity}'
                    },
                    update: {
                        http_method: 'put',
                        path: prefix + identity + '/{id}',
                        summary: 'Update {identity}',
                        description: 'This is for updating our {identity} based on the id'
                    },
                    destroy: {
                        http_method: 'delete',
                        path: prefix + identity + '/{id}',
                        summary: 'Delete {identity}',
                        description: 'This is for deleting specified {identity} with id'
                    }
                });
            }
        }

        //let's go through all the actions in the controller, excluding identity and globalId
        var exclude = ['identity', 'globalId', 'sails'];
        _.forEach(controller, function (value, action) {
            if (exclude.indexOf(action) > -1)
                return;

            //here we check if it's in our custom routes if so don't add, simply move to the next one
            if (_.findIndex(routes[identity], {'action': action}) < 0) {
                routes[identity].push({
                    http_method: value.http_method || 'get', //as my default
                    path: value.path || (identity + '/' + action),
                    action: action,
                    keys: [], //always empty since they are directly from the controller file and not specified unless default blue prints
                    summary: value.summary,
                    description: value.description
                });
            }

        });

    });

    return routes;
}

/**
 * this is used to generate our routes from the generated routes and tags with the custom blue print
 * @param generated_routes
 * @param tags
 * @param customBlueprintMaps
 * @returns {{}}
 * @private
 */
function _generatePaths(generated_routes, tags, customBlueprintMaps) {
    var paths = {};

    _.forEach(generated_routes, function (routes, identity) {
        _.forEach(routes, function (route) {

            var tag = _.find(tags, {identity: identity});

            if (!tag) {
                //   throw new Error("No tag for this identity-" + identity); --> some controller exist without model
                console.warn("No tag for this identity '" + identity + "'");
            }

            var parameter = formatter.blueprint_parameter(route.action, customBlueprintMaps);
            if (!parameter) //which means is not in our parameters, then use the keys to get and add token for us incase of any route using header information
                parameter = _getPathParamsFromKeys(route.keys).concat({$ref: '#/parameters/TokenHeaderParam'});

            var path = {
                summary: route.summary ? route.summary.replace("{identity}", _.capitalize(identity)) : '',
                description: route.description ? route.description.replace("{identity}", _.capitalize(identity)) : '',
                tags: tag ? [tag.name] : [identity],
                produces: ['application/json'],
                consumes: ['application/json'],
                parameters: parameter.concat(_getQueryParamsFromRouteQuery(route.query)).concat(_getBodyParamsFromRouteBody(route.body)),
                responses: {
                    '200': {description: 'The requested resource'},
                    '404': {description: 'Resource not found'},
                    '500': {description: 'Internal server error'}
                }
            };

            //for our route that alters db we need json form body
            if (route.action === "create" || route.action === "update") {
                path.parameters.push({
                    "name": "body",
                    "in": "body",
                    "required": true,
                    "description": "An object defining our schema for " + _.capitalize(identity),
                    "schema": {"$ref": "#/definitions/" + identity}
                });
            }

            //standardize our link here
            var link = _standardiseLink(route.path + "/" + _processRouteKeys(route.keys));
            if (!paths[link]) //if it's undefined create it as empty object for us
                paths[link] = {};

            paths[link][route.http_method] = path;

        });
    });

    return paths;
}

/**
 * help to process route keys to swagger spec format
 * which is {key} instead of sails default /:key
 * @param keys
 * @returns {string}
 * @private
 */
function _processRouteKeys(keys) {

    var map = _.map(keys, function (key) {
        return "{" + key + "}";
    });

    return map.join("/");
}

/**
 * making our link string to look like this
 * user/route instead of /user/route/ which is not allowed by swagger spec
 * @param link
 * @returns {*}
 * @private
 */
function _standardiseLink(link) {

    //check if the first character is / if not add it
    if (!_.startsWith(link, '/'))
        link = "/" + link;

    if (_.endsWith(link, '/'))
        link = link.slice(0, -1); //remove the / by the end

    return link;
}

/**
 * this is used to generate path param from the route keys
 * @param keys
 * @returns {Array}
 * @private
 */
function _getPathParamsFromKeys(keys) {
    var params = [];

    _.forEach(keys, function (key) {
        params.push({
            in: 'path',
            name: key,
            required: true,
            type: 'string',
            description: 'This is a path param for ' + key
        });
    });

    return params;
}

/**
 * this is used to create param or custom queries for our request or route path
 * @param queries
 * @returns {Array}
 * @private
 */
function _getQueryParamsFromRouteQuery(queries) {
    var params = [];

    _.forEach(queries, function (query) {
        params.push({
            in: 'query',
            name: query,
            required: false,
            type: 'string',
            description: 'This is a query param for ' + query
        });
    });

    return params;
}

/**
 * this is used to create body type of parameter for any request that requires post or put of information
 * @param body
 * @returns {Array}
 * @private
 */
function _getBodyParamsFromRouteBody(body) {
    var param = [];

    if (!_.isEmpty(body)) {
        param.push({
            "name": "body",
            "in": "body",
            "required": true,
            "description": "An object defining our schema for this request",
            "schema": parsers.attributes(body)
        });
    }

    return param;
}

module.exports = {
    tags: _generateModels,
    definitions: _generateDefinitions,
    parameters: _generateParameters,
    routes: _generateRoutes,
    paths: _generatePaths
};

<|endoftext|>


<commit_before>/* vuex-i18n defines the Vuexi18nPlugin to enable localization using a vuex
** module to store the translation information. Make sure to also include the
** file vuex-i18n-store.js to include a respective vuex module.
*/

import module from './vuex-i18n-store';
import plurals from './vuex-i18n-plurals';

// initialize the plugin object
let VuexI18nPlugin = {};

// internationalization plugin for vue js using vuex
VuexI18nPlugin.install = function install(Vue, store, config) {

	// TODO: remove this block for next major update (API break)
	if (typeof arguments[2] === 'string' || typeof arguments[3] === 'string') {
		console.warn('i18n: Registering the plugin vuex-i18n with a string for `moduleName` or `identifiers` is deprecated. Use a configuration object instead.', 'https://github.com/dkfbasel/vuex-i18n#setup');
		config = {
			moduleName: arguments[2],
			identifiers: arguments[3]
		};
	}

	// merge default options with user supplied options
	let mergedConfig = Object.assign({
		moduleName: 'i18n',
		identifiers: ['{', '}'],
		preserveState: false,
		onTranslationNotFound: function() {}
	}, config);

	// define module name and identifiers as constants to prevent any changes
	const moduleName = mergedConfig.moduleName;
	const identifiers = mergedConfig.identifiers;

	// initialize the onTranslationNotFound function and make sure it is actually
	// a function
	let onTranslationNotFound = mergedConfig.onTranslationNotFound;
	if (typeof onTranslationNotFound !== 'function') {
		console.error('i18n: i18n config option onTranslationNotFound must be a function');
		onTranslationNotFound = function() {};
	}

	// register the i18n module in the vuex store
	// preserveState can be used via configuration if server side rendering is used
	store.registerModule(moduleName, module, {preserveState: mergedConfig.preserveState});

	// check if the plugin was correctly initialized
	if (store.state.hasOwnProperty(moduleName) === false) {
		console.error('i18n: i18n vuex module is not correctly initialized. Please check the module name:', moduleName);

		// always return the key if module is not initialized correctly
		Vue.prototype.$i18n = function(key) {
			return key;
		};

		Vue.prototype.$getLanguage = function() {
			return null;
		};

		Vue.prototype.$setLanguage = function() {
			console.error('i18n: i18n vuex module is not correctly initialized');
		};

		return;
	};

	// initialize the replacement function
	let render = renderFn(identifiers);

	// get localized string from store. note that we pass the arguments passed
	// to the function directly to the translateInLanguage function
	let translate = function $t() {

		// get the current language from the store
		let locale = store.state[moduleName].locale;

		return translateInLanguage(locale, ...arguments);
	};

	// get localized string from store in a given language if available.
	// there are two possible signatures for the function.
	// we will check the arguments to make up the options passed.
	// 1: locale, key, options, pluralization
	// 2: locale, key, defaultValue, options, pluralization
	let translateInLanguage = function translateInLanguage(locale) {

		// read the function arguments
		let args = arguments;

		// initialize options
		let key = '';
		let defaultValue = '';
		let options = {};
		let pluralization = null;

		let count = args.length;

		// check if a default value was specified and fill options accordingly
		if (count >= 3 && typeof args[2] === 'string') {

			key = args[1];
			defaultValue = args[2];

			if (count > 3) {
				options = args[3];
			}

			if (count > 4) {
				pluralization = args[4];
			}

		} else {

			key = args[1];

			// default value was not specified and is therefore the same as the key
			defaultValue = key;

			if (count > 2) {
				options = args[2];
			}

			if (count > 3) {
				pluralization = args[3];
			}

		}

		// return the default value if the locale is not set (could happen on initialization)
		if (!locale) {
			console.warn('i18n: i18n locale is not set when trying to access translations:', key);
			return defaultValue;
		}

		// get the translations from the store
		let translations = store.state[moduleName].translations;

		// get the last resort fallback from the store
		let fallback = store.state[moduleName].fallback;

		// split locale by - to support partial fallback for regional locales
		// like de-CH, en-UK
		let localeRegional = locale.split('-');

		// flag for translation to exist or not
		let translationExists = true;

		// check if the language exists in the store. return the key if not
		if (translations.hasOwnProperty(locale) === false ) {
			translationExists = false;

		// check if the key exists in the store. return the key if not
		} else if (translations[locale].hasOwnProperty(key) === false) {
			translationExists = false;
		}

		// return the value from the store
		if (translationExists === true) {
			return render(locale, translations[locale][key], options, pluralization);
		}

		// check if a regional locale translation would be available for the key
		// i.e. de for de-CH
		if (localeRegional.length > 1 &&
			translations.hasOwnProperty(localeRegional[0]) === true &&
			translations[localeRegional[0]].hasOwnProperty(key) === true) {
			return render(localeRegional[0], translations[localeRegional[0]][key], options, pluralization);
		}

		// invoke a method if a translation is not found
		let asyncTranslation = onTranslationNotFound(locale, key, defaultValue);

		// resolve async translations by updating the store
		if (asyncTranslation) {
			Promise.resolve(asyncTranslation).then((value) => {
				let additionalTranslations = {};
				additionalTranslations[key] = value;
				addLocale(locale, additionalTranslations);
			});
		}

		// check if a vaild fallback exists in the store.
		// return the default value if not
		if (translations.hasOwnProperty(fallback) === false ) {
			return render(locale, defaultValue, options, pluralization);
		}

		// check if the key exists in the fallback locale in the store.
		// return the default value if not
		if (translations[fallback].hasOwnProperty(key) === false) {
			return render(fallback, defaultValue, options, pluralization);
		}

		return render(locale, translations[fallback][key], options, pluralization);

	};

	// check if the given key exists in the current locale
	let checkKeyExists = function checkKeyExists(key, scope = 'fallback') {

		// get the current language from the store
		let locale = store.state[moduleName].locale;
		let fallback = store.state[moduleName].fallback;
		let translations = store.state[moduleName].translations;

		// check the current translation
		if (translations.hasOwnProperty(locale) && translations[locale].hasOwnProperty(key)) {
			return true;
		}

		if (scope == 'strict') {
			return false;
		}

		// check any localized translations
		let localeRegional = locale.split('-');

		if (localeRegional.length > 1 &&
			translations.hasOwnProperty(localeRegional[0]) &&
			translations[localeRegional[0]].hasOwnProperty(key)) {
			return true;
		}

		if (scope == 'locale') {
			return false;
		}

		// check if a fallback locale exists
		if (translations.hasOwnProperty(fallback) && translations[fallback].hasOwnProperty(key)) {
			return true;
		}

		// key does not exist in the store
		return false;
	};

	// set fallback locale
	let setFallbackLocale = function setFallbackLocale(locale) {
		store.dispatch({
			type: `${moduleName}/setFallbackLocale`,
			locale: locale
		});
	};

	// set the current locale
	let setLocale = function setLocale(locale) {
		store.dispatch({
			type: `${moduleName}/setLocale`,
			locale: locale
		});
	};

	// get the current locale
	let getLocale = function getLocale() {
		return store.state[moduleName].locale;
	};

	// get all available locales
	let getLocales = function getLocales() {
		return Object.keys(store.state[moduleName].translations);
	};

	// add predefined translations to the store (keeping existing information)
	let addLocale = function addLocale(locale, translations) {
		return store.dispatch({
			type: `${moduleName}/addLocale`,
			locale: locale,
			translations: translations
		});
	};

	// replace all locale information in the store
	let replaceLocale = function replaceLocale(locale, translations) {
		return store.dispatch({
			type: `${moduleName}/replaceLocale`,
			locale: locale,
			translations: translations
		});
	};

	// remove the givne locale from the store
	let removeLocale = function removeLocale(locale) {
		if (store.state[moduleName].translations.hasOwnProperty(locale)) {
			store.dispatch({
				type: `${moduleName}/removeLocale`,
				locale: locale
			});
		}
	};

	// we are phasing out the exists function
	let phaseOutExistsFn = function phaseOutExistsFn(locale) {
		console.warn('i18n: $i18n.exists is depreceated. Please use $i18n.localeExists instead. It provides exatly the same functionality.');
		return checkLocaleExists(locale);
	};

	// check if the given locale is already loaded
	let checkLocaleExists = function checkLocaleExists(locale) {
		return store.state[moduleName].translations.hasOwnProperty(locale);
	};

	// register vue prototype methods
	Vue.prototype.$i18n = {
		locale: getLocale,
		locales: getLocales,
		set: setLocale,
		add: addLocale,
		replace: replaceLocale,
		remove: removeLocale,
		fallback: setFallbackLocale,
		localeExists: checkLocaleExists,
		keyExists: checkKeyExists,

		translate: translate,
		translateIn: translateInLanguage,

		exists: phaseOutExistsFn
	};

	// register global methods
	Vue.i18n = {
		locale: getLocale,
		locales: getLocales,
		set: setLocale,
		add: addLocale,
		replace: replaceLocale,
		remove: removeLocale,
		fallback: setFallbackLocale,
		translate: translate,
		translateIn: translateInLanguage,
		localeExists: checkLocaleExists,
		keyExists: checkKeyExists,

		exists: phaseOutExistsFn
	};

	// register the translation function on the vue instance directly
	Vue.prototype.$t = translate;

	// register the specific language translation function on the vue instance directly
	Vue.prototype.$tlang = translateInLanguage;

	// register a filter function for translations
	Vue.filter('translate', translate);

};

// renderFn will initialize a function to render the variable substitutions in
// the translation string. identifiers specify the tags will be used to find
// variable substitutions, i.e. {test} or {{test}}, note that we are using a
// closure to avoid recompilation of the regular expression to match tags on
// every render cycle.
let renderFn = function(identifiers) {

	if (identifiers == null || identifiers.length != 2) {
		console.warn('i18n: You must specify the start and end character identifying variable substitutions');
	}

	// construct a regular expression ot find variable substitutions, i.e. {test}
	let matcher = new RegExp('' + identifiers[0] + '\\w+' + identifiers[1], 'g');

	// define the replacement function
	let replace = function replace(translation, replacements, warn = true) {

		// check if the object has a replace property
		if (!translation.replace) {
			return translation;
		}

		return translation.replace(matcher, function(placeholder) {

			// remove the identifiers (can be set on the module level)
			let key = placeholder.replace(identifiers[0], '').replace(identifiers[1], '');

			if (replacements[key] !== undefined) {
				return replacements[key];
			}

			// warn user that the placeholder has not been found
			if (warn === true) {
				console.group ? console.group('i18n: Not all placeholders found') : console.warn('i18n: Not all placeholders found');
				console.warn('Text:', translation);
				console.warn('Placeholder:', placeholder);
				if(console.groupEnd) {
					console.groupEnd();
				}
			}

			// return the original placeholder
			return placeholder;
		});
	};

	// the render function will replace variable substitutions and prepare the
	// translations for rendering
	let render = function render(locale, translation, replacements = {}, pluralization = null) {
		// get the type of the property
		let objType = typeof translation;
		let pluralizationType = typeof pluralization;

		let resolvePlaceholders = function() {

			if (isArray(translation)) {

				// replace the placeholder elements in all sub-items
				return translation.map((item) => {
					return replace(item, replacements, false);
				});

			} else if (objType === 'string') {
				return replace(translation, replacements, true);
			}

		};

			// return translation item directly
		if (pluralization === null) {
			return resolvePlaceholders();
		}

		// check if pluralization value is countable
		if (pluralizationType !== 'number') {
			console.warn('i18n: pluralization is not a number');
			return resolvePlaceholders();
		}

		// --- handle pluralizations ---

		// replace all placeholders
		let resolvedTranslation = resolvePlaceholders();

		// initialize pluralizations
		let pluralizations = null;

		// if translations are already an array and have more than one entry,
		// we will not perform a split operation on :::
		if (isArray(resolvedTranslation) && resolvedTranslation.length > 0) {
			pluralizations = resolvedTranslation;

		} else {
			// split translation strings by ::: to find create the pluralization array
			pluralizations = resolvedTranslation.split(':::');
		}

		// determine the pluralization version to use by locale
		let index = plurals.getTranslationIndex(locale, pluralization);

		// check if the specified index is present in the pluralization
		if(typeof pluralizations[index] === 'undefined') {
			console.warn('i18n: pluralization not provided in locale', translation, locale, index);

			// return the first element of the pluralization by default
			return pluralizations[0].trim();
		}

		// return the requested item from the pluralizations
		return pluralizations[index].trim();

	};

	// return the render function to the caller
	return render;

};

// check if the given object is an array
function isArray(obj) {
	return !!obj && Array === obj.constructor;
}

export default VuexI18nPlugin;
<commit_msg>add translateFilterName config<commit_after>/* vuex-i18n defines the Vuexi18nPlugin to enable localization using a vuex
** module to store the translation information. Make sure to also include the
** file vuex-i18n-store.js to include a respective vuex module.
*/

import module from './vuex-i18n-store';
import plurals from './vuex-i18n-plurals';

// initialize the plugin object
let VuexI18nPlugin = {};

// internationalization plugin for vue js using vuex
VuexI18nPlugin.install = function install(Vue, store, config) {

	// TODO: remove this block for next major update (API break)
	if (typeof arguments[2] === 'string' || typeof arguments[3] === 'string') {
		console.warn('i18n: Registering the plugin vuex-i18n with a string for `moduleName` or `identifiers` is deprecated. Use a configuration object instead.', 'https://github.com/dkfbasel/vuex-i18n#setup');
		config = {
			moduleName: arguments[2],
			identifiers: arguments[3]
		};
	}

	// merge default options with user supplied options
	let mergedConfig = Object.assign({
		moduleName: 'i18n',
		identifiers: ['{', '}'],
		preserveState: false,
		translateFilterName: 'translate',
		onTranslationNotFound: function() {}
	}, config);

	// define module name and identifiers as constants to prevent any changes
	const moduleName = mergedConfig.moduleName;
	const identifiers = mergedConfig.identifiers;
	const translateFilterName = mergedConfig.translateFilterName;

	// initialize the onTranslationNotFound function and make sure it is actually
	// a function
	let onTranslationNotFound = mergedConfig.onTranslationNotFound;
	if (typeof onTranslationNotFound !== 'function') {
		console.error('i18n: i18n config option onTranslationNotFound must be a function');
		onTranslationNotFound = function() {};
	}

	// register the i18n module in the vuex store
	// preserveState can be used via configuration if server side rendering is used
	store.registerModule(moduleName, module, {preserveState: mergedConfig.preserveState});

	// check if the plugin was correctly initialized
	if (store.state.hasOwnProperty(moduleName) === false) {
		console.error('i18n: i18n vuex module is not correctly initialized. Please check the module name:', moduleName);

		// always return the key if module is not initialized correctly
		Vue.prototype.$i18n = function(key) {
			return key;
		};

		Vue.prototype.$getLanguage = function() {
			return null;
		};

		Vue.prototype.$setLanguage = function() {
			console.error('i18n: i18n vuex module is not correctly initialized');
		};

		return;
	};

	// initialize the replacement function
	let render = renderFn(identifiers);

	// get localized string from store. note that we pass the arguments passed
	// to the function directly to the translateInLanguage function
	let translate = function $t() {

		// get the current language from the store
		let locale = store.state[moduleName].locale;

		return translateInLanguage(locale, ...arguments);
	};

	// get localized string from store in a given language if available.
	// there are two possible signatures for the function.
	// we will check the arguments to make up the options passed.
	// 1: locale, key, options, pluralization
	// 2: locale, key, defaultValue, options, pluralization
	let translateInLanguage = function translateInLanguage(locale) {

		// read the function arguments
		let args = arguments;

		// initialize options
		let key = '';
		let defaultValue = '';
		let options = {};
		let pluralization = null;

		let count = args.length;

		// check if a default value was specified and fill options accordingly
		if (count >= 3 && typeof args[2] === 'string') {

			key = args[1];
			defaultValue = args[2];

			if (count > 3) {
				options = args[3];
			}

			if (count > 4) {
				pluralization = args[4];
			}

		} else {

			key = args[1];

			// default value was not specified and is therefore the same as the key
			defaultValue = key;

			if (count > 2) {
				options = args[2];
			}

			if (count > 3) {
				pluralization = args[3];
			}

		}

		// return the default value if the locale is not set (could happen on initialization)
		if (!locale) {
			console.warn('i18n: i18n locale is not set when trying to access translations:', key);
			return defaultValue;
		}

		// get the translations from the store
		let translations = store.state[moduleName].translations;

		// get the last resort fallback from the store
		let fallback = store.state[moduleName].fallback;

		// split locale by - to support partial fallback for regional locales
		// like de-CH, en-UK
		let localeRegional = locale.split('-');

		// flag for translation to exist or not
		let translationExists = true;

		// check if the language exists in the store. return the key if not
		if (translations.hasOwnProperty(locale) === false ) {
			translationExists = false;

		// check if the key exists in the store. return the key if not
		} else if (translations[locale].hasOwnProperty(key) === false) {
			translationExists = false;
		}

		// return the value from the store
		if (translationExists === true) {
			return render(locale, translations[locale][key], options, pluralization);
		}

		// check if a regional locale translation would be available for the key
		// i.e. de for de-CH
		if (localeRegional.length > 1 &&
			translations.hasOwnProperty(localeRegional[0]) === true &&
			translations[localeRegional[0]].hasOwnProperty(key) === true) {
			return render(localeRegional[0], translations[localeRegional[0]][key], options, pluralization);
		}

		// invoke a method if a translation is not found
		let asyncTranslation = onTranslationNotFound(locale, key, defaultValue);

		// resolve async translations by updating the store
		if (asyncTranslation) {
			Promise.resolve(asyncTranslation).then((value) => {
				let additionalTranslations = {};
				additionalTranslations[key] = value;
				addLocale(locale, additionalTranslations);
			});
		}

		// check if a vaild fallback exists in the store.
		// return the default value if not
		if (translations.hasOwnProperty(fallback) === false ) {
			return render(locale, defaultValue, options, pluralization);
		}

		// check if the key exists in the fallback locale in the store.
		// return the default value if not
		if (translations[fallback].hasOwnProperty(key) === false) {
			return render(fallback, defaultValue, options, pluralization);
		}

		return render(locale, translations[fallback][key], options, pluralization);

	};

	// check if the given key exists in the current locale
	let checkKeyExists = function checkKeyExists(key, scope = 'fallback') {

		// get the current language from the store
		let locale = store.state[moduleName].locale;
		let fallback = store.state[moduleName].fallback;
		let translations = store.state[moduleName].translations;

		// check the current translation
		if (translations.hasOwnProperty(locale) && translations[locale].hasOwnProperty(key)) {
			return true;
		}

		if (scope == 'strict') {
			return false;
		}

		// check any localized translations
		let localeRegional = locale.split('-');

		if (localeRegional.length > 1 &&
			translations.hasOwnProperty(localeRegional[0]) &&
			translations[localeRegional[0]].hasOwnProperty(key)) {
			return true;
		}

		if (scope == 'locale') {
			return false;
		}

		// check if a fallback locale exists
		if (translations.hasOwnProperty(fallback) && translations[fallback].hasOwnProperty(key)) {
			return true;
		}

		// key does not exist in the store
		return false;
	};

	// set fallback locale
	let setFallbackLocale = function setFallbackLocale(locale) {
		store.dispatch({
			type: `${moduleName}/setFallbackLocale`,
			locale: locale
		});
	};

	// set the current locale
	let setLocale = function setLocale(locale) {
		store.dispatch({
			type: `${moduleName}/setLocale`,
			locale: locale
		});
	};

	// get the current locale
	let getLocale = function getLocale() {
		return store.state[moduleName].locale;
	};

	// get all available locales
	let getLocales = function getLocales() {
		return Object.keys(store.state[moduleName].translations);
	};

	// add predefined translations to the store (keeping existing information)
	let addLocale = function addLocale(locale, translations) {
		return store.dispatch({
			type: `${moduleName}/addLocale`,
			locale: locale,
			translations: translations
		});
	};

	// replace all locale information in the store
	let replaceLocale = function replaceLocale(locale, translations) {
		return store.dispatch({
			type: `${moduleName}/replaceLocale`,
			locale: locale,
			translations: translations
		});
	};

	// remove the givne locale from the store
	let removeLocale = function removeLocale(locale) {
		if (store.state[moduleName].translations.hasOwnProperty(locale)) {
			store.dispatch({
				type: `${moduleName}/removeLocale`,
				locale: locale
			});
		}
	};

	// we are phasing out the exists function
	let phaseOutExistsFn = function phaseOutExistsFn(locale) {
		console.warn('i18n: $i18n.exists is depreceated. Please use $i18n.localeExists instead. It provides exatly the same functionality.');
		return checkLocaleExists(locale);
	};

	// check if the given locale is already loaded
	let checkLocaleExists = function checkLocaleExists(locale) {
		return store.state[moduleName].translations.hasOwnProperty(locale);
	};

	// register vue prototype methods
	Vue.prototype.$i18n = {
		locale: getLocale,
		locales: getLocales,
		set: setLocale,
		add: addLocale,
		replace: replaceLocale,
		remove: removeLocale,
		fallback: setFallbackLocale,
		localeExists: checkLocaleExists,
		keyExists: checkKeyExists,

		translate: translate,
		translateIn: translateInLanguage,

		exists: phaseOutExistsFn
	};

	// register global methods
	Vue.i18n = {
		locale: getLocale,
		locales: getLocales,
		set: setLocale,
		add: addLocale,
		replace: replaceLocale,
		remove: removeLocale,
		fallback: setFallbackLocale,
		translate: translate,
		translateIn: translateInLanguage,
		localeExists: checkLocaleExists,
		keyExists: checkKeyExists,

		exists: phaseOutExistsFn
	};

	// register the translation function on the vue instance directly
	Vue.prototype.$t = translate;

	// register the specific language translation function on the vue instance directly
	Vue.prototype.$tlang = translateInLanguage;

	// register a filter function for translations
	Vue.filter(translateFilterName, translate);

};

// renderFn will initialize a function to render the variable substitutions in
// the translation string. identifiers specify the tags will be used to find
// variable substitutions, i.e. {test} or {{test}}, note that we are using a
// closure to avoid recompilation of the regular expression to match tags on
// every render cycle.
let renderFn = function(identifiers) {

	if (identifiers == null || identifiers.length != 2) {
		console.warn('i18n: You must specify the start and end character identifying variable substitutions');
	}

	// construct a regular expression ot find variable substitutions, i.e. {test}
	let matcher = new RegExp('' + identifiers[0] + '\\w+' + identifiers[1], 'g');

	// define the replacement function
	let replace = function replace(translation, replacements, warn = true) {

		// check if the object has a replace property
		if (!translation.replace) {
			return translation;
		}

		return translation.replace(matcher, function(placeholder) {

			// remove the identifiers (can be set on the module level)
			let key = placeholder.replace(identifiers[0], '').replace(identifiers[1], '');

			if (replacements[key] !== undefined) {
				return replacements[key];
			}

			// warn user that the placeholder has not been found
			if (warn === true) {
				console.group ? console.group('i18n: Not all placeholders found') : console.warn('i18n: Not all placeholders found');
				console.warn('Text:', translation);
				console.warn('Placeholder:', placeholder);
				if(console.groupEnd) {
					console.groupEnd();
				}
			}

			// return the original placeholder
			return placeholder;
		});
	};

	// the render function will replace variable substitutions and prepare the
	// translations for rendering
	let render = function render(locale, translation, replacements = {}, pluralization = null) {
		// get the type of the property
		let objType = typeof translation;
		let pluralizationType = typeof pluralization;

		let resolvePlaceholders = function() {

			if (isArray(translation)) {

				// replace the placeholder elements in all sub-items
				return translation.map((item) => {
					return replace(item, replacements, false);
				});

			} else if (objType === 'string') {
				return replace(translation, replacements, true);
			}

		};

			// return translation item directly
		if (pluralization === null) {
			return resolvePlaceholders();
		}

		// check if pluralization value is countable
		if (pluralizationType !== 'number') {
			console.warn('i18n: pluralization is not a number');
			return resolvePlaceholders();
		}

		// --- handle pluralizations ---

		// replace all placeholders
		let resolvedTranslation = resolvePlaceholders();

		// initialize pluralizations
		let pluralizations = null;

		// if translations are already an array and have more than one entry,
		// we will not perform a split operation on :::
		if (isArray(resolvedTranslation) && resolvedTranslation.length > 0) {
			pluralizations = resolvedTranslation;

		} else {
			// split translation strings by ::: to find create the pluralization array
			pluralizations = resolvedTranslation.split(':::');
		}

		// determine the pluralization version to use by locale
		let index = plurals.getTranslationIndex(locale, pluralization);

		// check if the specified index is present in the pluralization
		if(typeof pluralizations[index] === 'undefined') {
			console.warn('i18n: pluralization not provided in locale', translation, locale, index);

			// return the first element of the pluralization by default
			return pluralizations[0].trim();
		}

		// return the requested item from the pluralizations
		return pluralizations[index].trim();

	};

	// return the render function to the caller
	return render;

};

// check if the given object is an array
function isArray(obj) {
	return !!obj && Array === obj.constructor;
}

export default VuexI18nPlugin;
<|endoftext|>


<commit_before>/**
 * Created by rsie on 3/30/2014.
 */

var amqp = require('amqp')
    ,amqpNode = require('amqplib')
    ,ampq   = require('amqp')
    ,when = require('when');

function MsgServerModule(msgServerType) {

// Implementation reference:

    this._impl = null;

// Setup procedure:

    this._SetImplementation(this._EstablishImplementer(msgServerType));

    return this;
}

MsgServerModule.prototype = {

    _SetImplementation: function(implementer)
    {
        this._impl = null;
        if(implementer)
            this._impl = implementer;
    },

    // EstablishImplementer - function that creates
    // the Concrete Implementer and binds it to MsgModule.
    // This is the very method to place your
    // browser/feature/object detection code.
    _EstablishImplementer: function(container)
    {
        if(container === 'amqp')
            return new Amqp();

        else if(container === 'amqpnode')
            return new AmqpNode();

        return null;
    },

  // Functions "exported" by the MsgServerModule abstraction:
  //                                 __________________
  //________________________________/   Client API     \___________________________________
    connect:  function(host)
    {
        if(this._impl) {
            this._impl.connect(host)
            return true
        } else
            return false
    },
    sendMessage: function(msg) {
        if(this._impl) {
            this._impl.sendMessage(msg)
            return true
        } else
            return false
    },

    receiveMessage: function() {
        if(this._impl) {
            this._impl.receiveMessage()
            return true
        } else
            return false
    },
    createExchanges:  function(exchangeNames) {

    },
    createQueues: function(queueNames) {
    },
    removeExchanges: function(exchangeNames) {
        console.log("remove these exchanges: " + exchangeNames)
    },
    removeQueues: function(queueNames) {
        console.log("remove thesse queues: " + queueNames)
    }
}

// This is the set of concrete implementers:
//                             ___________________________
//____________________________/     Implementations       \__________________________

//this is the first implementer
function Amqp() {
    this._amqp = null
}

Amqp.prototype = {
    createQueue: function() {
                //----------------create amqp queue(s)
//        queueNames.forEach(queueName,function () {
//            this._connection.queue(queueName,function(queue) {
//                console.log('Queue ' + queue.name + ' is open')
//                qStatus = 'The ' + queue.name + ' is ready for use!'
//                queue.bind(this._exchange,queueName.routingKey)
//                queue.subscribe(queueName.routingKey,function(msg,headers,deliveryInfo) {
//                    msg.message.timestamp = new Date().toJSON()
//                    console.log({'log':'the.routing.register','msg.message':msg.message})
//                    //insertReg(app.register,msg.message, msg.message.node.nodeId)
//                })
//            })
//        })
    },
    createExchange: function() {
        console.log("amqp: createExchange")
    }
}

//this is the second implementer
function AmqpNode() {
    this._amqpNode = null
}

AmqpNode.prototype = {
    connect: function(host) {
        this._amqpNode = amqpNode.connect(host)
            .then(function(connection) {
                console.log("AmqpNode connected")
                return connection
            })
    },
    createExchange: function() {
        console.log("Amqp.node: createExchange")
    },
    sendMessage: function(msg) {
        this._amqpNode.then(function(conn) {
            return when(conn.createChannel().then(function(ch) {
                var q = 'hello';
                //var msg = 'Hello World!';

                var ok = ch.assertQueue(q, {durable: false});

                return ok.then(function(_qok) {
                    ch.sendToQueue(q, new Buffer(JSON.stringify(msg)),{'Content-Type': 'application/json'});
                    console.log(" [x] Sent '%s'", JSON.stringify(msg));
                    return ch.close();
                });
            })).ensure(function() { /*conn.close();*/ });
        }).then(null, console.warn);
    },
    receiveMessage: function() {
        this._amqpNode.then(function(conn) {
          process.once('SIGINT', function() { conn.close(); });
          return conn.createChannel().then(function(ch) {

            var ok = ch.assertQueue('hello', {durable: false});

            ok = ok.then(function(_qok) {
              return ch.consume('hello', function(msg) {
                console.log(" [x] Received '%s'", msg.content)
              }, {noAck: true});
            });

            return ok.then(function(_consumeOk) {
              console.log(' [*] Waiting for messages. To exit press CTRL+C');
            });
          });
        }).then(null, console.warn);
    }
}

// This is the set of private objects:
//                             ___________________________
//____________________________/     Private Objects       \__________________________

var getSomething = function() {

}

module.exports = MsgServerModule
<commit_msg>just some cosmetic changes for documentation<commit_after>/**
 * Created by rsie on 3/30/2014.
 */

var amqp = require('amqp')
    ,amqpNode = require('amqplib')
    ,ampq   = require('amqp')
    ,when = require('when');

function MsgServerModule(msgServerType) {

// Implementation reference:

    this._impl = null;

// Setup procedure:

    this._SetImplementation(this._EstablishImplementer(msgServerType));

    return this;
}

MsgServerModule.prototype = {

    _SetImplementation: function(implementer)
    {
        this._impl = null;
        if(implementer)
            this._impl = implementer;
    },

    // EstablishImplementer - function that creates
    // the Concrete Implementer and binds it to MsgModule.
    // This is the very method to place your
    // browser/feature/object detection code.
    _EstablishImplementer: function(container)
    {
        if(container === 'amqp')
            return new Amqp();

        else if(container === 'amqpnode')
            return new AmqpNode();

        return null;
    },

  // Functions "exported" by the MsgServerModule abstraction:
  //                                 __________________
  //________________________________/   Client API     \___________________________________
    connect:  function(host)
    {
        if(this._impl) {
            this._impl.connect(host)
            return true
        } else
            return false
    },
    sendMessage: function(msg) {
        if(this._impl) {
            this._impl.sendMessage(msg)
            return true
        } else
            return false
    },

    receiveMessage: function() {
        if(this._impl) {
            this._impl.receiveMessage()
            return true
        } else
            return false
    },
    createExchanges:  function(exchangeNames) {

    },
    createQueues: function(queueNames) {
    },
    removeExchanges: function(exchangeNames) {
        console.log("remove these exchanges: " + exchangeNames)
    },
    removeQueues: function(queueNames) {
        console.log("remove thesse queues: " + queueNames)
    }
}

//                             ___________________________
//____________________________/     Implementations       \__________________________

//                                  ___________________________
//_________________________________/          Amqp             \__________________________

function Amqp() {
    this._amqp = null
}

Amqp.prototype = {
    createQueue: function() {
                //----------------create amqp queue(s)
//        queueNames.forEach(queueName,function () {
//            this._connection.queue(queueName,function(queue) {
//                console.log('Queue ' + queue.name + ' is open')
//                qStatus = 'The ' + queue.name + ' is ready for use!'
//                queue.bind(this._exchange,queueName.routingKey)
//                queue.subscribe(queueName.routingKey,function(msg,headers,deliveryInfo) {
//                    msg.message.timestamp = new Date().toJSON()
//                    console.log({'log':'the.routing.register','msg.message':msg.message})
//                    //insertReg(app.register,msg.message, msg.message.node.nodeId)
//                })
//            })
//        })
    },
    createExchange: function() {
        console.log("amqp: createExchange")
    }
}

//                                  ___________________________
//_________________________________/         AmqpNode          \__________________________

function AmqpNode() {
    this._amqpNode = null
}

AmqpNode.prototype = {
    connect: function(host) {
        this._amqpNode = amqpNode.connect(host)
            .then(function(connection) {
                console.log("AmqpNode connected")
                return connection
            })
    },
    createExchange: function() {
        console.log("Amqp.node: createExchange")
    },
    sendMessage: function(msg) {
        this._amqpNode.then(function(conn) {
            return when(conn.createChannel().then(function(ch) {
                var q = 'hello';
                //var msg = 'Hello World!';

                var ok = ch.assertQueue(q, {durable: false});

                return ok.then(function(_qok) {
                    ch.sendToQueue(q, new Buffer(JSON.stringify(msg)),{'Content-Type': 'application/json'});
                    console.log(" [x] Sent '%s'", JSON.stringify(msg));
                    return ch.close();
                });
            })).ensure(function() { /*conn.close();*/ });
        }).then(null, console.warn);
    },
    receiveMessage: function() {
        this._amqpNode.then(function(conn) {
          process.once('SIGINT', function() { conn.close(); });
          return conn.createChannel().then(function(ch) {

            var ok = ch.assertQueue('hello', {durable: false});

            ok = ok.then(function(_qok) {
              return ch.consume('hello', function(msg) {
                console.log(" [x] Received '%s'", msg.content)
              }, {noAck: true});
            });

            return ok.then(function(_consumeOk) {
              console.log(' [*] Waiting for messages. To exit press CTRL+C');
            });
          });
        }).then(null, console.warn);
    }
}

//                             ___________________________
//____________________________/     Private Objects       \__________________________

var getSomething = function() {

}

module.exports = MsgServerModule
<|endoftext|>


<commit_before>/* Script for pop-up dhtml more tabs implementation
 * uses jQuery library
 */

/* dhtml_more_tabs
 * displays the More Sites div
 * note the technique of recasting the function after initalization
 */

var dhtml_more_tabs = function() {
	// first time through set up the DOM
	jQuery('#selectNav').appendTo('#linkNav').addClass('dhtml_more_tabs'); // move the selectNav in the DOM
	jQuery('#selectNav').css('top',jQuery('#linkNav').height() - 3);       // set its top position
	jQuery('#selectNav').width(jQuery('#linkNav').width()*0.75);           // set its width to fix an IE6 bug
	jQuery('#selectNav').css('z-index',9900);                                 // explicitely set the z-index
	jQuery('.more-tab').css('z-index',9800);                                  //  " for the More Tabs div element

	// then recast the function to the post initialized state which will run from then on
	dhtml_more_tabs = function() {
		if (jQuery('#selectNav').css('display') == 'none' ) {
			jQuery('div#selectNav').show();
			// highlight the more tab
			jQuery('.more-tab').addClass('more-active');
			// dim the current tab
			jQuery('.selectedTab').addClass('tab-dim');
			// mask the rest of the page
			createDHTMLMask(dhtml_more_tabs) ;
			// bind this function to the More Tabs tab to close More Tabs on click
			jQuery('.selectedTab').bind('click',function(){dhtml_more_tabs();return false;});
		} else {
			// unhighlight the more tab
			jQuery('.more-tab').removeClass('more-active');
			// hide the dropdown
			jQuery('div#selectNav').hide(); // hide the box
			//undim the currently selected tab
			jQuery('.selectedTab').removeClass('tab-dim');
			removeDHTMLMask()
			jQuery('.selectedTab').unbind('click');
		}
	}
	// finally run the inner function, first time through
	dhtml_more_tabs();
}

function createDHTMLMask(callback) {
	jQuery('body').append('

');
	jQuery('#portalMask').css('height',browserSafeDocHeight()).css('width','100%').css('z-index',1000).bind("click",function(event){
		callback();
		return false;
	});
	jQuery('#portalMask').bgiframe();
}

function removeDHTMLMask() {
	jQuery('#portalMask').remove();
}

/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate$
 * $Rev$
 *
 * Version 2.1.1
 */
(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&/6.0/.test(navigator.userAgent)){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};})(jQuery);

//For SAK-13987
//For SAK-16162
//Just use the EB current.json as the session id rather than trying to do a search/replace
var sessionId = "current";
var sessionTimeOut;
var timeoutDialogEnabled = false;
var timeoutDialogWarningTime;
var timeoutLoggedoutUrl;
var timeoutPortalPath;
jQuery(document).ready(function(){
	// note a session exists whether the user is logged in or no
	if (portal.loggedIn && portal.timeoutDialog ) {
		setTimeout('setup_timeout_config();', 60000);
	}
});

var setup_timeout_config = function() {
	timeoutDialogEnabled = portal.timeoutDialog.enabled;
	timeoutDialogWarningTime = portal.timeoutDialog.seconds;
	timeoutLoggedoutUrl = portal.loggedOutUrl;
	timeoutPortalPath = portal.portalPath;
	if (timeoutDialogEnabled == true) {
		poll_session_data();
		fetch_timeout_dialog();
	}
}

var poll_session_data = function() {
    //Need to append Date.getTime as sakai still uses jquery pre 1.2.1 which doesn't support the cache: false parameter.
	jQuery.ajax({
		url: "/direct/session/" + sessionId + ".json?auto=true&_=" + (new Date()).getTime(),    //auto=true makes it not refresh the session lastaccessedtime
		dataType: "json",
		success: function(data){
		//get the maxInactiveInterval in the same ms
		data.maxInactiveInterval = data.maxInactiveInterval * 1000;
		if(data.active && data.userId != null && data.lastAccessedTime + data.maxInactiveInterval
				> data.currentTime) {
			//User is logged in, so now determine how much time is left
			var remaining = data.lastAccessedTime + data.maxInactiveInterval - data.currentTime;
			//If time remaining is less than timeoutDialogWarningTime minutes, show/update dialog box
			if (remaining < timeoutDialogWarningTime * 1000){
				//we are within 5 min now - show popup
				min = Math.round(remaining / (1000 * 60));
				show_timeout_alert(min);
				clearTimeout(sessionTimeOut);
				sessionTimeOut = setTimeout("poll_session_data()", 1000 * 60);
			} else {
				//more than timeoutDialogWarningTime min away
				clearTimeout(sessionTimeOut);
				sessionTimeOut = setTimeout("poll_session_data()", (remaining - timeoutDialogWarningTime*1000));
			}
		} else if (data.userId == null) {
			// if data.userId is null, the session is done; redirect the user to logoutUrl
			location.href=timeoutLoggedoutUrl;

		} else {
			//the timeout length has occurred, but there is a slight delay, do this until there isn't a user.
			sessionTimeOut = setTimeout("poll_session_data()", 1000 * 10);
		}
	},
	error: function(XMLHttpRequest, status, error){
		// We used to to 404 handling here but now we should always get good session data.
	}
	});
}

function keep_session_alive(){
	dismiss_session_alert();
	jQuery.get(timeoutPortalPath);
}

var dismiss_session_alert = function(){
	removeDHTMLMask();
	jQuery("#timeout_alert_body").remove();
}

var timeoutDialogFragment;
function fetch_timeout_dialog() {
	jQuery.ajax({
		url: "/portal/timeout?auto=true",
		cache: true,
		dataType: "text",
		success: function(data) {
		timeoutDialogFragment = data;
	},
	error: function(XMLHttpRequest, status, error){
		timeoutDialogEnabled = false;
	}
	});
}

function show_timeout_alert(min) {
	if (!timeoutDialogEnabled) {
		return;
	}

	if (!jQuery("#portalMask").get(0)){
		createDHTMLMask(dismiss_session_alert);
		jQuery("#portalMask").css("z-index", 10000);
	}
	if (jQuery("#timeout_alert_body").get(0)) {
		//its there, just update the min
		jQuery("#timeout_alert_body span").html(min);
	} else {
		var dialog = timeoutDialogFragment.replace("{0}", min);
		jQuery("body").append(dialog);
	}
}

// The official way for a tool to request minimized navigation
function portalMaximizeTool() {
        if ( ! ( portal.toggle.sitenav || portal.toggle.tools ) ) return;
        if ( ! portal.toggle.allowauto ) return;
        sakaiMinimizeNavigation();
}

function sakaiMinimizeNavigation() {
        if ( ! ( portal.toggle.sitenav || portal.toggle.tools ) ) return;
	if (portal.toggle.sitenav) {
		$('#portalContainer').addClass('sakaiMinimizeSiteNavigation')
	}
	if (portal.toggle.tools){
		$('#container').addClass('sakaiMinimizePageNavigation');
	}
	$('#toggleToolMax').hide();
	$('#toggleNormal').css({'display':'block'});
}

function sakaiRestoreNavigation() {
        if ( ! ( portal.toggle.sitenav || portal.toggle.tools ) ) return;
	if (portal.toggle.sitenav) {
		$('#portalContainer').removeClass('sakaiMinimizeSiteNavigation')
	}
	if (portal.toggle.tools){
		$('#container').removeClass('sakaiMinimizePageNavigation');
	}
	$('#toggleToolMax').show();
	$('#toggleNormal').css({'display':'none'});
}

function updatePresence() {
	jQuery.ajax( {
		url: sakaiPresenceFragment,
		cache: false,
		success: function(frag){
			var whereHead = frag.indexOf('');
			if ( whereHead > 0 ) {
			 	location.reload();
			} else {
				$("#presenceIframe").html(frag);
			}
		},
		// If we get an error, wait 60 seconds before retry
		error: function(request, strError){
			sakaiLastPresenceTimeOut = setTimeout('updatePresence()', 60000);
		}
	});
}
<commit_msg>SAK-17267 Matt Mize patch to place timeout alert on screen<commit_after>/* Script for pop-up dhtml more tabs implementation
 * uses jQuery library
 */

/* dhtml_more_tabs
 * displays the More Sites div
 * note the technique of recasting the function after initalization
 */

var dhtml_more_tabs = function() {
	// first time through set up the DOM
	jQuery('#selectNav').appendTo('#linkNav').addClass('dhtml_more_tabs'); // move the selectNav in the DOM
	jQuery('#selectNav').css('top',jQuery('#linkNav').height() - 3);       // set its top position
	jQuery('#selectNav').width(jQuery('#linkNav').width()*0.75);           // set its width to fix an IE6 bug
	jQuery('#selectNav').css('z-index',9900);                                 // explicitely set the z-index
	jQuery('.more-tab').css('z-index',9800);                                  //  " for the More Tabs div element

	// then recast the function to the post initialized state which will run from then on
	dhtml_more_tabs = function() {
		if (jQuery('#selectNav').css('display') == 'none' ) {
			jQuery('div#selectNav').show();
			// highlight the more tab
			jQuery('.more-tab').addClass('more-active');
			// dim the current tab
			jQuery('.selectedTab').addClass('tab-dim');
			// mask the rest of the page
			createDHTMLMask(dhtml_more_tabs) ;
			// bind this function to the More Tabs tab to close More Tabs on click
			jQuery('.selectedTab').bind('click',function(){dhtml_more_tabs();return false;});
		} else {
			// unhighlight the more tab
			jQuery('.more-tab').removeClass('more-active');
			// hide the dropdown
			jQuery('div#selectNav').hide(); // hide the box
			//undim the currently selected tab
			jQuery('.selectedTab').removeClass('tab-dim');
			removeDHTMLMask()
			jQuery('.selectedTab').unbind('click');
		}
	}
	// finally run the inner function, first time through
	dhtml_more_tabs();
}

function createDHTMLMask(callback) {
	jQuery('body').append('

');
	jQuery('#portalMask').css('height',browserSafeDocHeight()).css('width','100%').css('z-index',1000).bind("click",function(event){
		callback();
		return false;
	});
	jQuery('#portalMask').bgiframe();
}

function removeDHTMLMask() {
	jQuery('#portalMask').remove();
}

/* Copyright (c) 2006 Brandon Aaron (http://brandonaaron.net)
 * Dual licensed under the MIT (http://www.opensource.org/licenses/mit-license.php)
 * and GPL (http://www.opensource.org/licenses/gpl-license.php) licenses.
 *
 * $LastChangedDate$
 * $Rev$
 *
 * Version 2.1.1
 */
(function($){$.fn.bgIframe=$.fn.bgiframe=function(s){if($.browser.msie&&/6.0/.test(navigator.userAgent)){s=$.extend({top:'auto',left:'auto',width:'auto',height:'auto',opacity:true,src:'javascript:false;'},s||{});var prop=function(n){return n&&n.constructor==Number?n+'px':n;},html='<iframe class="bgiframe"frameborder="0"tabindex="-1"src="'+s.src+'"'+'style="display:block;position:absolute;z-index:-1;'+(s.opacity!==false?'filter:Alpha(Opacity=\'0\');':'')+'top:'+(s.top=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderTopWidth)||0)*-1)+\'px\')':prop(s.top))+';'+'left:'+(s.left=='auto'?'expression(((parseInt(this.parentNode.currentStyle.borderLeftWidth)||0)*-1)+\'px\')':prop(s.left))+';'+'width:'+(s.width=='auto'?'expression(this.parentNode.offsetWidth+\'px\')':prop(s.width))+';'+'height:'+(s.height=='auto'?'expression(this.parentNode.offsetHeight+\'px\')':prop(s.height))+';'+'"/>';return this.each(function(){if($('> iframe.bgiframe',this).length==0)this.insertBefore(document.createElement(html),this.firstChild);});}return this;};})(jQuery);

//For SAK-13987
//For SAK-16162
//Just use the EB current.json as the session id rather than trying to do a search/replace
var sessionId = "current";
var sessionTimeOut;
var timeoutDialogEnabled = false;
var timeoutDialogWarningTime;
var timeoutLoggedoutUrl;
var timeoutPortalPath;
jQuery(document).ready(function(){
	// note a session exists whether the user is logged in or no
	if (portal.loggedIn && portal.timeoutDialog ) {
		setTimeout('setup_timeout_config();', 60000);
	}
});

var setup_timeout_config = function() {
	timeoutDialogEnabled = portal.timeoutDialog.enabled;
	timeoutDialogWarningTime = portal.timeoutDialog.seconds;
	timeoutLoggedoutUrl = portal.loggedOutUrl;
	timeoutPortalPath = portal.portalPath;
	if (timeoutDialogEnabled == true) {
		poll_session_data();
		fetch_timeout_dialog();
	}
}

var poll_session_data = function() {
    //Need to append Date.getTime as sakai still uses jquery pre 1.2.1 which doesn't support the cache: false parameter.
	jQuery.ajax({
		url: "/direct/session/" + sessionId + ".json?auto=true&_=" + (new Date()).getTime(),    //auto=true makes it not refresh the session lastaccessedtime
		dataType: "json",
		success: function(data){
		//get the maxInactiveInterval in the same ms
		data.maxInactiveInterval = data.maxInactiveInterval * 1000;
		if(data.active && data.userId != null && data.lastAccessedTime + data.maxInactiveInterval
				> data.currentTime) {
			//User is logged in, so now determine how much time is left
			var remaining = data.lastAccessedTime + data.maxInactiveInterval - data.currentTime;
			//If time remaining is less than timeoutDialogWarningTime minutes, show/update dialog box
			if (remaining < timeoutDialogWarningTime * 1000){
				//we are within 5 min now - show popup
				min = Math.round(remaining / (1000 * 60));
				show_timeout_alert(min);
				clearTimeout(sessionTimeOut);
				sessionTimeOut = setTimeout("poll_session_data()", 1000 * 60);
			} else {
				//more than timeoutDialogWarningTime min away
				clearTimeout(sessionTimeOut);
				sessionTimeOut = setTimeout("poll_session_data()", (remaining - timeoutDialogWarningTime*1000));
			}
		} else if (data.userId == null) {
			// if data.userId is null, the session is done; redirect the user to logoutUrl
			location.href=timeoutLoggedoutUrl;

		} else {
			//the timeout length has occurred, but there is a slight delay, do this until there isn't a user.
			sessionTimeOut = setTimeout("poll_session_data()", 1000 * 10);
		}
	},
	error: function(XMLHttpRequest, status, error){
		// We used to to 404 handling here but now we should always get good session data.
	}
	});
}

function keep_session_alive(){
	dismiss_session_alert();
	jQuery.get(timeoutPortalPath);
}

var dismiss_session_alert = function(){
	removeDHTMLMask();
	jQuery("#timeout_alert_body").remove();
}

var timeoutDialogFragment;
function fetch_timeout_dialog() {
	jQuery.ajax({
		url: "/portal/timeout?auto=true",
		cache: true,
		dataType: "text",
		success: function(data) {
		timeoutDialogFragment = data;
	},
	error: function(XMLHttpRequest, status, error){
		timeoutDialogEnabled = false;
	}
	});
}

function show_timeout_alert(min) {
	if (!timeoutDialogEnabled) {
		return;
	}

	if (!jQuery("#portalMask").get(0)){
		createDHTMLMask(dismiss_session_alert);
		jQuery("#portalMask").css("z-index", 10000);
	}
	if (jQuery("#timeout_alert_body").get(0)) {
		//its there, just update the min
		jQuery("#timeout_alert_body span").html(min);
		jQuery("#timeout_alert_body span").css('top', (f_scrollTop() + 100) + "px");
	} else {
		var dialog = timeoutDialogFragment.replace("{0}", min);
		jQuery("body").append(dialog);
		jQuery('#timeout_alert_body').css('top', (f_scrollTop() + 100) + "px");
	}
}

// The official way for a tool to request minimized navigation
function portalMaximizeTool() {
        if ( ! ( portal.toggle.sitenav || portal.toggle.tools ) ) return;
        if ( ! portal.toggle.allowauto ) return;
        sakaiMinimizeNavigation();
}

function sakaiMinimizeNavigation() {
        if ( ! ( portal.toggle.sitenav || portal.toggle.tools ) ) return;
	if (portal.toggle.sitenav) {
		$('#portalContainer').addClass('sakaiMinimizeSiteNavigation')
	}
	if (portal.toggle.tools){
		$('#container').addClass('sakaiMinimizePageNavigation');
	}
	$('#toggleToolMax').hide();
	$('#toggleNormal').css({'display':'block'});
}

function sakaiRestoreNavigation() {
        if ( ! ( portal.toggle.sitenav || portal.toggle.tools ) ) return;
	if (portal.toggle.sitenav) {
		$('#portalContainer').removeClass('sakaiMinimizeSiteNavigation')
	}
	if (portal.toggle.tools){
		$('#container').removeClass('sakaiMinimizePageNavigation');
	}
	$('#toggleToolMax').show();
	$('#toggleNormal').css({'display':'none'});
}

function updatePresence() {
	jQuery.ajax( {
		url: sakaiPresenceFragment,
		cache: false,
		success: function(frag){
			var whereHead = frag.indexOf('');
			if ( whereHead > 0 ) {
			 	location.reload();
			} else {
				$("#presenceIframe").html(frag);
			}
		},
		// If we get an error, wait 60 seconds before retry
		error: function(request, strError){
			sakaiLastPresenceTimeOut = setTimeout('updatePresence()', 60000);
		}
	});
}

function f_scrollTop() {
	return f_filterResults (
		window.pageYOffset ? window.pageYOffset : 0,
		document.documentElement ? document.documentElement.scrollTop : 0,
		document.body ? document.body.scrollTop : 0
	);
}

function f_filterResults(n_win, n_docel, n_body) {
	var n_result = n_win ? n_win : 0;
	if (n_docel && (!n_result || (n_result > n_docel)))
		n_result = n_docel;
	return n_body && (!n_result || (n_result > n_body)) ? n_body : n_result;
}
<|endoftext|>


<commit_before>/*
 * Copyright 2012 Adobe Systems Incorporated. All Rights Reserved.
 */

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
/*global $: false, define: false, describe: false, it: false, expect: false, beforeEach: false, afterEach: false, waitsFor: false, runs: false */

define(function (require, exports, module) {
    'use strict';

    // Load dependent modules from brackets.test
    var CommandManager,
        Commands,
        DocumentManager,
        FileViewController,
        SpecRunnerUtils     = require("./SpecRunnerUtils.js");

    describe("WorkingSetView", function () {

        var testPath = SpecRunnerUtils.getTestPath("/spec/WorkingSetView-test-files");
        var testWindow;

        beforeEach(function () {
            SpecRunnerUtils.createTestWindowAndRun(this, function (w) {
                testWindow = w;

                // Load module instances from brackets.test
                CommandManager      = testWindow.brackets.test.CommandManager;
                Commands            = testWindow.brackets.test.Commands;
                DocumentManager     = testWindow.brackets.test.DocumentManager;
                FileViewController  = testWindow.brackets.test.FileViewController;

                // Open a directory
                SpecRunnerUtils.loadProjectInTestWindow(testPath);
            });

            var didOpen = false, gotError = false;

            var openAndMakeDirty = function (path) {
                // open file
                runs(function () {
                    FileViewController.openAndSelectDocument(path, FileViewController.PROJECT_MANAGER)
                        .done(function () { didOpen = true; })
                        .fail(function () { gotError = true; });
                });
                waitsFor(function () { return didOpen && !gotError; }, "FILE_OPEN on file timeout", 1000);

                // change editor content to make doc dirty
                runs(function () {
                    var editor = DocumentManager.getCurrentDocument()._editor;
                    editor.setValue("dirty document");
                    expect(DocumentManager.getCurrentDocument().isDirty).toBe(true);
                });

            };

            openAndMakeDirty(testPath + "/file_one.js");
            openAndMakeDirty(testPath + "/file_two.js");
        });

        afterEach(function () {
            SpecRunnerUtils.closeTestWindow();
        });

        it("should add a list item when a file is dirtied", function () {
            // check if files are added to work set and dirty icons are present
            runs(function () {
                var listItems = testWindow.$("#open-files-container > ul").children();
                expect(listItems.length).toBe(2);
                expect(listItems.find("a").get(0).text === "file_one.js").toBeTruthy();
                expect(listItems.find(".file-status-icon").length).toBe(2);
            });

        });

        it("should remove a list item when a file is closed", function () {
            DocumentManager.getCurrentDocument()._markClean(); // so we can close without a save dialog

            // close the document
            var didClose = false, gotError = false;
            runs(function () {
                CommandManager.execute(Commands.FILE_CLOSE)
                    .done(function () { didClose = true; })
                    .fail(function () { gotError = true; });
            });
            waitsFor(function () { return didClose && !gotError; }, "FILE_OPEN on file timeout", 1000);

            // check there are no list items
            runs(function () {
                var listItems = testWindow.$("#open-files-container > ul").children();
                expect(listItems.length).toBe(1);
            });

        });

        it("should make a file that is clicked the current one in the editor", function () {
            var $ = testWindow.$;
            var secondItem =  $($("#open-files-container > ul").children()[1]);
            secondItem.trigger('click');

            var listItems = $("#open-files-container > ul").children();
            expect($(listItems[0]).hasClass("selected")).not.toBeTruthy();
            expect($(listItems[1]).hasClass("selected")).toBeTruthy();

        });

        it("should rebuild the ui from the model correctly", function () {
            // force the test window to initialize to unit test preferences
            // for just this test
            runs(function () {
                localStorage.setItem("doLoadPreferences", true);
            });

            // close test window while working set has 2 files
            SpecRunnerUtils.closeTestWindow();

            // reopen without loading a project
            SpecRunnerUtils.createTestWindowAndRun(this, function (w) {
                testWindow = w;
            });

            // files should be in the working set
            runs(function () {
                var listItems = testWindow.$("#open-files-container > ul").children();
                expect(listItems.find("a").get(0).text === "file_one.js").toBeTruthy();
                expect(listItems.find("a").get(1).text === "file_two.js").toBeTruthy();

                // files should be clean
                expect(listItems.find(".file-status-icon dirty").length).toBe(0);

                // file_two.js should be active
                expect($(listItems[1]).hasClass("selected")).toBeTruthy();

                localStorage.removeItem("doLoadPreferences", true);
            });
        });

        it("should close a file when the user clicks the close button", function () {
            var $ = testWindow.$;

            // make 2nd doc clean
            var docList = DocumentManager.getWorkingSet();
			docList[1]._markClean();

            // make the first one active
            DocumentManager.showInEditor(docList[0]);

            // hover over and click on close icon of 2nd list item
            var secondItem =  $($("#open-files-container > ul").children()[1]);
            secondItem.trigger('mouseover');
            var closeIcon = secondItem.find(".file-status-icon");
            expect(closeIcon.length).toBe(1);

            // simulate click
            var didClose = false;
            $(DocumentManager).on("workingSetRemove", function (event, removedDoc) {
                didClose = true;
            });

            closeIcon.trigger('click');
            waitsFor(function () { return didClose; }, "click on working set close icon timeout", 1000);

            var listItems = $("#open-files-container > ul").children();
            expect(listItems.length).toBe(1);
            expect(listItems.find("a").get(0).text === "file_one.js").toBeTruthy();

        });

        it("should remove dirty icon when file becomes clean", function () {
            // check that dirty icon is removed when docs are cleaned
            var docList = DocumentManager.getWorkingSet();
            docList[0]._markClean();
            var listItems = testWindow.$("#open-files-container > ul").children();
            expect(listItems.find(".file-status-icon dirty").length).toBe(0);
        });

    });
});<commit_msg>Fix intermittent failure in WorkingSetView-test.<commit_after>/*
 * Copyright 2012 Adobe Systems Incorporated. All Rights Reserved.
 */

/*jslint vars: true, plusplus: true, devel: true, browser: true, nomen: true, indent: 4, maxerr: 50 */
/*global $: false, define: false, describe: false, it: false, expect: false, beforeEach: false, afterEach: false, waitsFor: false, runs: false */

define(function (require, exports, module) {
    'use strict';

    // Load dependent modules from brackets.test
    var CommandManager,
        Commands,
        DocumentManager,
        FileViewController,
        SpecRunnerUtils     = require("./SpecRunnerUtils.js");

    describe("WorkingSetView", function () {

        var testPath = SpecRunnerUtils.getTestPath("/spec/WorkingSetView-test-files");
        var testWindow;

        beforeEach(function () {
            SpecRunnerUtils.createTestWindowAndRun(this, function (w) {
                testWindow = w;

                // Load module instances from brackets.test
                CommandManager      = testWindow.brackets.test.CommandManager;
                Commands            = testWindow.brackets.test.Commands;
                DocumentManager     = testWindow.brackets.test.DocumentManager;
                FileViewController  = testWindow.brackets.test.FileViewController;

                // Open a directory
                SpecRunnerUtils.loadProjectInTestWindow(testPath);
            });

            var didOpen = false, gotError = false;

            var openAndMakeDirty = function (path) {
                // open file
                runs(function () {
                    FileViewController.openAndSelectDocument(path, FileViewController.PROJECT_MANAGER)
                        .done(function () { didOpen = true; })
                        .fail(function () { gotError = true; });
                });
                waitsFor(function () { return didOpen && !gotError; }, "FILE_OPEN on file timeout", 1000);

                // change editor content to make doc dirty
                runs(function () {
                    var editor = DocumentManager.getCurrentDocument()._editor;
                    editor.setValue("dirty document");
                    expect(DocumentManager.getCurrentDocument().isDirty).toBe(true);
                });

            };

            openAndMakeDirty(testPath + "/file_one.js");
            openAndMakeDirty(testPath + "/file_two.js");
        });

        afterEach(function () {
            SpecRunnerUtils.closeTestWindow();
        });

        it("should add a list item when a file is dirtied", function () {
            // check if files are added to work set and dirty icons are present
            runs(function () {
                var listItems = testWindow.$("#open-files-container > ul").children();
                expect(listItems.length).toBe(2);
                expect(listItems.find("a").get(0).text === "file_one.js").toBeTruthy();
                expect(listItems.find(".file-status-icon").length).toBe(2);
            });

        });

        it("should remove a list item when a file is closed", function () {
            DocumentManager.getCurrentDocument()._markClean(); // so we can close without a save dialog

            // close the document
            var didClose = false, gotError = false;
            runs(function () {
                CommandManager.execute(Commands.FILE_CLOSE)
                    .done(function () { didClose = true; })
                    .fail(function () { gotError = true; });
            });
            waitsFor(function () { return didClose && !gotError; }, "FILE_OPEN on file timeout", 1000);

            // check there are no list items
            runs(function () {
                var listItems = testWindow.$("#open-files-container > ul").children();
                expect(listItems.length).toBe(1);
            });

        });

        it("should make a file that is clicked the current one in the editor", function () {
            var $ = testWindow.$;
            var secondItem =  $($("#open-files-container > ul").children()[1]);
            secondItem.trigger('click');

            var listItems = $("#open-files-container > ul").children();
            expect($(listItems[0]).hasClass("selected")).not.toBeTruthy();
            expect($(listItems[1]).hasClass("selected")).toBeTruthy();

        });

        it("should rebuild the ui from the model correctly", function () {
            // force the test window to initialize to unit test preferences
            // for just this test
            runs(function () {
                localStorage.setItem("doLoadPreferences", true);
            });

            // remove temporary unit test preferences with a single-spec after()
            this.after(function () {
                localStorage.removeItem("doLoadPreferences");
            });

            // close test window while working set has 2 files (see beforeEach())
            SpecRunnerUtils.closeTestWindow();

            // reopen brackets test window to initialize unit test working set
            SpecRunnerUtils.createTestWindowAndRun(this, function (w) {
                testWindow = w;
            });

            var listItems;

            // wait for working set to populate
            waitsFor(
                function () {
                    // check working set UI list content
                    listItems = testWindow.$("#open-files-container > ul").children();
                    return listItems.length > 0;
                },
                1000
            );

            // files should be in the working set
            runs(function () {
                expect(listItems.find("a").get(0).text === "file_one.js").toBeTruthy();
                expect(listItems.find("a").get(1).text === "file_two.js").toBeTruthy();

                // files should be clean
                expect(listItems.find(".file-status-icon dirty").length).toBe(0);

                // file_two.js should be active
                expect($(listItems[1]).hasClass("selected")).toBeTruthy();
            });
        });

        it("should close a file when the user clicks the close button", function () {
            var $ = testWindow.$;

            // make 2nd doc clean
            var docList = DocumentManager.getWorkingSet();
			docList[1]._markClean();

            // make the first one active
            DocumentManager.showInEditor(docList[0]);

            // hover over and click on close icon of 2nd list item
            var secondItem =  $($("#open-files-container > ul").children()[1]);
            secondItem.trigger('mouseover');
            var closeIcon = secondItem.find(".file-status-icon");
            expect(closeIcon.length).toBe(1);

            // simulate click
            var didClose = false;
            $(DocumentManager).on("workingSetRemove", function (event, removedDoc) {
                didClose = true;
            });

            closeIcon.trigger('click');
            waitsFor(function () { return didClose; }, "click on working set close icon timeout", 1000);

            var listItems = $("#open-files-container > ul").children();
            expect(listItems.length).toBe(1);
            expect(listItems.find("a").get(0).text === "file_one.js").toBeTruthy();

        });

        it("should remove dirty icon when file becomes clean", function () {
            // check that dirty icon is removed when docs are cleaned
            var docList = DocumentManager.getWorkingSet();
            docList[0]._markClean();
            var listItems = testWindow.$("#open-files-container > ul").children();
            expect(listItems.find(".file-status-icon dirty").length).toBe(0);
        });

    });
});<|endoftext|>


<commit_before><commit_msg>Update changelog<commit_after><|endoftext|>