<commit_before>var DBNAME = 'flora', DBFILE = '/depot/flora6.sql';
var link = undefined;

exports.getAll = function() {
	return;
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var resultSet = link.execute('SELECT * FROM flora ORDER BY id');
	while (resultSet.isValidRow()) {
		var res = {
			deutsch : resultSet.fieldByName('deutsch'),
			familie : resultSet.fieldByName('familie'),
			sorte : resultSet.fieldByName('sorte'),
			art : resultSet.fieldByName('art'),
			subart : resultSet.fieldByName('subart'),
			id : resultSet.fieldByName('id'),
			bereich : resultSet.fieldByName('bereich'),
			unterbereich : resultSet.fieldByName('unterbereich'),
			standort : resultSet.fieldByName('standort'),
		};
		var select = link.execute('SELECT total FROM flora2 WHERE id=?', res.id);
		if (!select.isValidRow()) {
			console.log('INSERT');
			link.execute('INSERT INTO flora2 VALUES (total=0,id=?,deutsch=?,familie=?,sorte=?,art=?,subart=?,bereich=?,unterbereich=?,standort=?)', res.id, res.deutsch, res.familie, res.sorte, res.art, res.subart, res.bereich, res.unterbereich, res.standort);
		} else {
			console.log('UPDATE');
			link.execute('UPDATE flora2 set total=? WHERE id=?', res.id, select.fieldByName('total') + 1);
		}
		//var resultSet = link.execute('SELECT * FROM flora WHERE standort <> "" ORDER BY id LIMIT 0,200');
		resultSet.next();
	}
	resultSet.close();
	link.close();
}

exports.search = function(_needle, _callback) {
	if (_needle.length < 4)
		return;
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var resultSet = link.execute('SELECT DISTINCT deutsch,art,gattung,id FROM flora WHERE deutsch like "%' + _needle + '%" GROUP BY deutsch LIMIT 0,100');
	var results = [];
	while (resultSet.isValidRow()) {
		results.push({
			deutsch : resultSet.fieldByName('deutsch'),
			gattung : resultSet.fieldByName('gattung'),
			art : resultSet.fieldByName('art'),
			id : resultSet.fieldByName('id'),
		});
		//require('module/model').getDetail(resultSet.fieldByName('id'), function() {
		//});
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
}

exports.getDetail = function(_data, _callback) {
	try {
		if (!link)
			link = Ti.Database.install(DBFILE, DBNAME);
		var q = 'SELECT * FROM flora WHERE gattung="' + _data.gattung + '" AND art="' + _data.art + '"'
		console.log(q);
		if (_data.subart)
			q += ' AND subart="' + _data.subart + '"';
		var resultSet = link.execute(q);
		var rowcount = 0;
		var res = {
			plantinfo : {},
			standorte : {}
		};
		while (resultSet.isValidRow()) {
			if (rowcount === 0) {
				res.plantinfo = {
					art : resultSet.fieldByName('art'),
					subart : resultSet.fieldByName('subart'),
					familie : resultSet.fieldByName('familie'),
					deutsch : resultSet.fieldByName('deutsch'),
					gattung : resultSet.fieldByName('gattung'),
					standort : resultSet.fieldByName('standort')
				}
			}
			if ( typeof res.standorte[resultSet.fieldByName('unterbereich')] == 'undefined')
				res.standorte[resultSet.fieldByName('unterbereich')] = {
					total : 1,
					bereich : resultSet.fieldByName('bereich')
				}
			else
				res.standorte[resultSet.fieldByName('bereich')].total += 1;
			resultSet.next();
			rowcount++;
		}
		if (_callback)
			_callback(res);
		resultSet.close();
	} catch(E) {
		console.log(E)
	}
}

exports.getDetailFromNet = function() {
	var results = [];
	var url = 'http://bghamburg.de/datenbank-detail?detail=' + _id;
	var query = 'SELECT * FROM html WHERE url="' + url + '" AND xpath="//table"';
	Ti.Yahoo.yql(query, function(_y) {
		if (!_y.data) {
			return;
		}
		var tr = _y.data.table.tbody.tr;
		var res = {};
		for (var i = 0; i < tr.length; i++) {
			var key = tr[i].td[0].p.toLowerCase();
			var val = tr[i].td[1].p;
			res[key] = val;
		}

		var q = 'UPDATE flora SET standort="' + res.standort + '"  WHERE id=' + _id;
		try {
			link.execute('BEGIN TRANSACTION;');
			link.execute(q);
			link.execute('COMMIT;');
		} catch(E) {
			console.log(E);
		}

		if (_callback)
			_callback(res);
	});
}
exports.getCalendar = function(_callback) {
	var url = 'http://bghamburg.de/veranstaltungen?format=feed&type=rss&limit=100';
	var xhr = Ti.Network.createHTTPClient({
		onload : function() {
			var XMLTools = require("vendor/XMLTools");
			var parser = new XMLTools(this.responseXML);
			var res = parser.toObject().channel.item;
			_callback(res);
		}
	});
	xhr.open('GET', url);
	xhr.send();
}

exports.getFamilien = function(_callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);

	var resultSet = link.execute('SELECT DISTINCT familie FROM flora WHERE familie NOT LIKE "?%" ORDER BY familie');
	var results = [];
	while (resultSet.isValidRow()) {
		results.push(resultSet.fieldByName('familie'));
		resultSet.next();
	}
	resultSet.close();
	_callback(results);

}
exports.getGattungenByFamilie = function(_familie, _callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var q = 'SELECT DISTINCT gattung FROM flora WHERE familie="' + _familie + '" ORDER BY gattung';
	var resultSet = link.execute(q);
	var results = [];
	while (resultSet.isValidRow()) {
		results.push(resultSet.fieldByName('gattung'));
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
}

exports.getArtenByGattung = function(_gattung, _callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var q = 'SELECT gattung,art,subart,deutsch FROM flora WHERE gattung="' + _gattung + '" GROUP BY gattung,art,subart ORDER BY art';
	console.log(q);
	var resultSet = link.execute(q);
	var results = [];
	while (resultSet.isValidRow()) {
		results.push({
			art : resultSet.fieldByName('art'),
			subart : resultSet.fieldByName('subart'),
			gattung : _gattung,
			deutsch : resultSet.fieldByName('deutsch')
		});
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
	return results;
}

exports.getArtenByBereich = function(_bereich, _callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var q = 'SELECT DISTINCT id,art,gattung,deutsch FROM flora WHERE bereich="' + _bereich + '" GROUP BY art,subart ORDER BY art';
	var resultSet = link.execute(q);
	console.log(resultSet);
	var results = [];
	while (resultSet.isValidRow()) {
		results.push({
			art : resultSet.fieldByName('art'),
			gattung : resultSet.fieldByName('gattung'),
			id : resultSet.fieldByName('id'),
			deutsch : resultSet.fieldByName('deutsch')
		});
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
}

exports.getBereiche = function() {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var resultSet = link.execute('SELECT DISTINCT bereich FROM flora WHERE bereich <> "" AND bereich <> "undefined" ORDER BY bereich');
	var results = [];
	while (resultSet.isValidRow()) {
		results.push(resultSet.fieldByName('bereich'));
		resultSet.next();
	}
	resultSet.close();
	return (results);
}
<commit_msg>Bugfix with bereich<commit_after>var DBNAME = 'flora', DBFILE = '/depot/flora6.sql';
var link = undefined;

exports.getAll = function() {
	return;
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var resultSet = link.execute('SELECT * FROM flora ORDER BY id');
	while (resultSet.isValidRow()) {
		var res = {
			deutsch : resultSet.fieldByName('deutsch'),
			familie : resultSet.fieldByName('familie'),
			sorte : resultSet.fieldByName('sorte'),
			art : resultSet.fieldByName('art'),
			subart : resultSet.fieldByName('subart'),
			id : resultSet.fieldByName('id'),
			bereich : resultSet.fieldByName('bereich'),
			unterbereich : resultSet.fieldByName('unterbereich'),
			standort : resultSet.fieldByName('standort'),
		};
		var select = link.execute('SELECT total FROM flora2 WHERE id=?', res.id);
		if (!select.isValidRow()) {
			console.log('INSERT');
			link.execute('INSERT INTO flora2 VALUES (total=0,id=?,deutsch=?,familie=?,sorte=?,art=?,subart=?,bereich=?,unterbereich=?,standort=?)', res.id, res.deutsch, res.familie, res.sorte, res.art, res.subart, res.bereich, res.unterbereich, res.standort);
		} else {
			console.log('UPDATE');
			link.execute('UPDATE flora2 set total=? WHERE id=?', res.id, select.fieldByName('total') + 1);
		}
		//var resultSet = link.execute('SELECT * FROM flora WHERE standort <> "" ORDER BY id LIMIT 0,200');
		resultSet.next();
	}
	resultSet.close();
	link.close();
}

exports.search = function(_needle, _callback) {
	if (_needle.length < 4)
		return;
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var resultSet = link.execute('SELECT DISTINCT deutsch,art,gattung,id FROM flora WHERE deutsch like "%' + _needle + '%" GROUP BY deutsch LIMIT 0,100');
	var results = [];
	while (resultSet.isValidRow()) {
		results.push({
			deutsch : resultSet.fieldByName('deutsch'),
			gattung : resultSet.fieldByName('gattung'),
			art : resultSet.fieldByName('art'),
			id : resultSet.fieldByName('id'),
		});
		//require('module/model').getDetail(resultSet.fieldByName('id'), function() {
		//});
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
}

exports.getDetail = function(_data, _callback) {
	try {
		if (!link)
			link = Ti.Database.install(DBFILE, DBNAME);
		var q = 'SELECT * FROM flora WHERE unterbereich <> "" AND gattung="' + _data.gattung + '" AND art="' + _data.art + '"'
		console.log(q);
		if (_data.subart)
			q += ' AND subart="' + _data.subart + '"';
		var resultSet = link.execute(q);
		var rowcount = 0;
		var res = {
			plantinfo : {},
			standorte : {}
		};
		while (resultSet.isValidRow()) {
			if (rowcount === 0) {
				res.plantinfo = {
					art : resultSet.fieldByName('art'),
					subart : resultSet.fieldByName('subart'),
					familie : resultSet.fieldByName('familie'),
					deutsch : resultSet.fieldByName('deutsch'),
					gattung : resultSet.fieldByName('gattung'),
					standort : resultSet.fieldByName('standort')
				}
			}
			if (!res.standorte[resultSet.fieldByName('unterbereich')])
				res.standorte[resultSet.fieldByName('unterbereich')] = {
					total : 1,
					bereich : resultSet.fieldByName('bereich')
				}
			else
				res.standorte[resultSet.fieldByName('unterbereich')].total += 1;
			resultSet.next();
			rowcount++;
		}
		if (_callback)
			_callback(res);
		resultSet.close();
	} catch(E) {
		console.log(E)
	}
}

exports.getDetailFromNet = function() {
	var results = [];
	var url = 'http://bghamburg.de/datenbank-detail?detail=' + _id;
	var query = 'SELECT * FROM html WHERE url="' + url + '" AND xpath="//table"';
	Ti.Yahoo.yql(query, function(_y) {
		if (!_y.data) {
			return;
		}
		var tr = _y.data.table.tbody.tr;
		var res = {};
		for (var i = 0; i < tr.length; i++) {
			var key = tr[i].td[0].p.toLowerCase();
			var val = tr[i].td[1].p;
			res[key] = val;
		}

		var q = 'UPDATE flora SET standort="' + res.standort + '"  WHERE id=' + _id;
		try {
			link.execute('BEGIN TRANSACTION;');
			link.execute(q);
			link.execute('COMMIT;');
		} catch(E) {
			console.log(E);
		}

		if (_callback)
			_callback(res);
	});
}
exports.getCalendar = function(_callback) {
	var url = 'http://bghamburg.de/veranstaltungen?format=feed&type=rss&limit=100';
	var xhr = Ti.Network.createHTTPClient({
		onload : function() {
			var XMLTools = require("vendor/XMLTools");
			var parser = new XMLTools(this.responseXML);
			var res = parser.toObject().channel.item;
			_callback(res);
		}
	});
	xhr.open('GET', url);
	xhr.send();
}

exports.getFamilien = function(_callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);

	var resultSet = link.execute('SELECT DISTINCT familie FROM flora WHERE familie NOT LIKE "?%" ORDER BY familie');
	var results = [];
	while (resultSet.isValidRow()) {
		results.push(resultSet.fieldByName('familie'));
		resultSet.next();
	}
	resultSet.close();
	_callback(results);

}
exports.getGattungenByFamilie = function(_familie, _callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var q = 'SELECT DISTINCT gattung FROM flora WHERE familie="' + _familie + '" ORDER BY gattung';
	var resultSet = link.execute(q);
	var results = [];
	while (resultSet.isValidRow()) {
		results.push(resultSet.fieldByName('gattung'));
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
}

exports.getArtenByGattung = function(_gattung, _callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var q = 'SELECT gattung,art,subart,deutsch FROM flora WHERE gattung="' + _gattung + '" GROUP BY gattung,art,subart ORDER BY art';
	console.log(q);
	var resultSet = link.execute(q);
	var results = [];
	while (resultSet.isValidRow()) {
		results.push({
			art : resultSet.fieldByName('art'),
			subart : resultSet.fieldByName('subart'),
			gattung : _gattung,
			deutsch : resultSet.fieldByName('deutsch')
		});
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
	return results;
}

exports.getArtenByBereich = function(_bereich, _callback) {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var q = 'SELECT DISTINCT id,art,gattung,deutsch FROM flora WHERE bereich="' + _bereich + '" GROUP BY art,subart ORDER BY art';
	var resultSet = link.execute(q);
	console.log(resultSet);
	var results = [];
	while (resultSet.isValidRow()) {
		results.push({
			art : resultSet.fieldByName('art'),
			gattung : resultSet.fieldByName('gattung'),
			id : resultSet.fieldByName('id'),
			deutsch : resultSet.fieldByName('deutsch')
		});
		resultSet.next();
	}
	resultSet.close();
	_callback(results);
}

exports.getBereiche = function() {
	if (!link)
		link = Ti.Database.install(DBFILE, DBNAME);
	var resultSet = link.execute('SELECT DISTINCT bereich FROM flora WHERE bereich <> "" AND bereich <> "undefined" ORDER BY bereich');
	var results = [];
	while (resultSet.isValidRow()) {
		results.push(resultSet.fieldByName('bereich'));
		resultSet.next();
	}
	resultSet.close();
	return (results);
}
<|endoftext|>


<commit_before>$(function() {
    $("a[id^='add-cart']").click(function(event){
        var id = this.id.substring(9);
        var display = $("#cart-amount").html();

        //send request to server
        var amount = 1;
        if ($("#cart-quantity") && $("#cart-quantity").val() > 1) {
            amount = $("#cart-quantity").val();
        }

        var url = Routing.generate('zh-CN__RG__' + 'best365_store_cart_add_purchasable', {id: id, quantity: amount}, true);
        console.log(url);
        // var url = 'http://localhost/michael/new_best365/web/app_dev.php/best365/cart/add/'+id+'/'+amount;
        $.ajax({
            url: url,
            type: 'GET',
            success: function(result){
                if (result == 'success') {
                    // update cart amount display
                    $("#cart-amount").html(parseInt(display) + amount);
                    console.log(parseInt(display) + amount);
                } else {
                    console.log(result);
                    alert('failed to add product to cart.');
                }
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log(jqXHR);
                console.log(textStatus);
                console.log(errorThrown);
                alert('failed to add product to cart.');
            }
        });
    });
});<commit_msg>fixing request url<commit_after>$(function() {
    $("a[id^='add-cart']").click(function(event){
        var domain = 'www.best365.co.nz';
        var id = this.id.substring(9);
        var display = $("#cart-amount").html();

        //send request to server
        var amount = 1;
        if ($("#cart-quantity") && $("#cart-quantity").val() > 1) {
            amount = $("#cart-quantity").val();
        }

        var url = domain + Routing.generate('zh-CN__RG__' + 'best365_store_cart_add_purchasable', {id: id, quantity: amount});
        console.log(url);
        // var url = 'http://localhost/michael/new_best365/web/app_dev.php/best365/cart/add/'+id+'/'+amount;
        $.ajax({
            url: url,
            type: 'GET',
            success: function(result){
                if (result == 'success') {
                    // update cart amount display
                    $("#cart-amount").html(parseInt(display) + amount);
                    console.log(parseInt(display) + amount);
                } else {
                    console.log(result);
                    alert('failed to add product to cart.');
                }
            },
            error: function(jqXHR, textStatus, errorThrown) {
                console.log(jqXHR);
                console.log(textStatus);
                console.log(errorThrown);
                alert('failed to add product to cart.');
            }
        });
    });
});<|endoftext|>


<commit_before>var Helpers = require('../../helpers');
var Plugin = require('../../plugin');
var MediaStreamPlugin = require('../media-stream-plugin');

function RtpbroadcastPlugin() {
  RtpbroadcastPlugin.super_.apply(this, arguments);
}

RtpbroadcastPlugin.NAME = 'janus.plugin.cm.rtpbroadcast';
Helpers.inherits(RtpbroadcastPlugin, MediaStreamPlugin);
Plugin.register(RtpbroadcastPlugin.NAME, RtpbroadcastPlugin);

/**
 * {@link https://github.com/cargomedia/janus-gateway-rtpbroadcast#create}
 * @typedef {Object} StreamParams
 */

/**
 * @param {string} id
 * @param {Object} [options]
 * @param {string} [options.name]
 * @param {string} [options.description]
 * @param {boolean} [options.recorded]
 * @param {string} [options.whitelist]
 * @param {StreamParams} [options.streams]

 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.create = function(id, options) {
  return this._create(id, options);
};

/**
 * @param {string} id
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.destroy = function(id) {
  return this._destroy(id);
};

/**
 * @param {string} [id]
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.list = function(id) {
  return this._list(id);
};

/**
 * @param {string} id
 * @param {Object} [answerOptions] {@link createAnswer}
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.watch = function(id, answerOptions) {
  return this._watch(id, null, answerOptions);
};

/**
 * @param {string} mountpointId
 * @param {Array} streams
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.watchUDP = function(mountpointId, streams) {
  return this.sendWithTransaction({body: {request: 'watch-udp', id: mountpointId, streams: streams}});
};

/**
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.start = function() {
  return this._start();
};

/**
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.stop = function() {
  return this._stop();
};

/**
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.pause = function() {
  return this._pause();
};

/**
 * @param {string} id
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.switch = function(id) {
  return this._switch(id);
};

/**
 * @param {number} index
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.switchSource = function(index) {
  return this.sendWithTransaction({body: {request: 'switch-source', index: index}});
};

/**
 * @param {boolean} enabled
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.superuser = function(enabled) {
  return this.sendWithTransaction({body: {request: 'superuser', enabled: enabled}});
};

module.exports = RtpbroadcastPlugin;
<commit_msg>Streamline Rtpbroadcast.watchUDP params<commit_after>var Helpers = require('../../helpers');
var Plugin = require('../../plugin');
var MediaStreamPlugin = require('../media-stream-plugin');

function RtpbroadcastPlugin() {
  RtpbroadcastPlugin.super_.apply(this, arguments);
}

RtpbroadcastPlugin.NAME = 'janus.plugin.cm.rtpbroadcast';
Helpers.inherits(RtpbroadcastPlugin, MediaStreamPlugin);
Plugin.register(RtpbroadcastPlugin.NAME, RtpbroadcastPlugin);

/**
 * {@link https://github.com/cargomedia/janus-gateway-rtpbroadcast#create}
 * @typedef {Object} StreamParams
 */

/**
 * @param {string} id
 * @param {Object} [options]
 * @param {string} [options.name]
 * @param {string} [options.description]
 * @param {boolean} [options.recorded]
 * @param {string} [options.whitelist]
 * @param {StreamParams} [options.streams]

 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.create = function(id, options) {
  return this._create(id, options);
};

/**
 * @param {string} id
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.destroy = function(id) {
  return this._destroy(id);
};

/**
 * @param {string} [id]
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.list = function(id) {
  return this._list(id);
};

/**
 * @param {string} id
 * @param {Object} [answerOptions] {@link createAnswer}
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.watch = function(id, answerOptions) {
  return this._watch(id, null, answerOptions);
};

/**
 * @param {string} id
 * @param {Array} streams
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.watchUDP = function(id, streams) {
  return this.sendWithTransaction({body: {request: 'watch-udp', id: id, streams: streams}});
};

/**
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.start = function() {
  return this._start();
};

/**
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.stop = function() {
  return this._stop();
};

/**
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.pause = function() {
  return this._pause();
};

/**
 * @param {string} id
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.switch = function(id) {
  return this._switch(id);
};

/**
 * @param {number} index
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.switchSource = function(index) {
  return this.sendWithTransaction({body: {request: 'switch-source', index: index}});
};

/**
 * @param {boolean} enabled
 * @return {Promise}
 */
RtpbroadcastPlugin.prototype.superuser = function(enabled) {
  return this.sendWithTransaction({body: {request: 'superuser', enabled: enabled}});
};

module.exports = RtpbroadcastPlugin;
<|endoftext|>


<commit_before>/**
 * @name mainApp
 * @requieres
 * @type {angular.Module}
 * @description Main module of the application
 */
var mainApp = angular.module('mainApp',[
    'ngRoute',
    'mainAppCtrls',
    'mgcrea.ngStrap',
    'ui.router',
    'angular-jwt',
    'restSvcs',
    'angular-storage',
    'pascalprecht.translate',
    'textAngular',
    'prntSvcs'
]);
/**
 * @name mainAppCtrls
 * @type {angular.Module}
 * @description Module containg all controller of the application
 */
var mainAppCtrls = angular.module('mainAppCtrls',["pascalprecht.translate"]);

mainApp.config(['$urlRouterProvider','$stateProvider',
    function($urlRouterProvider,$stateProvider)
    {
        var prefix = "resources/views/";

        $stateProvider
            .state('workshops',{
                url: '/workshops',
                controller: 'WorkshopListCtrl',
                templateUrl: prefix.concat('workshopList.html')
            })
            .state('workshopsdetails',{
                url: '/workshops/details/:id',
                controller: 'WorkshopDetailsCtrl',
                templateUrl: prefix.concat('workshopDetails.html')
            })

            .state('login',{
                url: '/login',
                controller: 'LoginCtrl',
                templateUrl: prefix.concat('login.html')
            })
            .state('enrollment_confirm',{
                url: '/enrollment_confirm/:id/:token',
                templateUrl: prefix.concat('enrollmentConfirm.html'),
                controller: 'EnrollmentConfirm'
            })
            .state('unsubscribe',{
                url: '/unsubscribe/:id/:workshopid/:token',
                templateUrl: prefix.concat('unsubscribemessage.html'),
                controller: 'UnsubscribeController'
            })
            .state('password_reset',{
                url: '/password_reset/:token',
                templateUrl: prefix.concat('passwordReset.html'),
                controller: 'PasswordRestCtrl'
            })
            .state('dashboard',{
                url: '/dashboard',
                controller: 'DashboardCtrl',
                templateUrl: prefix.concat('adminDashboard.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('workshop_template',{
                url:'/workshop_template',
                controller:'WorkshopTemplateCtrl',
                templateUrl: prefix.concat('adminWorkshopTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('workshop_template_new', {
                url: '/workshop/template/new',
                controller: 'NewWorkshopTemplateCtrl',
                templateUrl: prefix.concat('adminNewWorkshopTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('workshop_template.edit', {
                url: '/edit/:id',
                controller: 'EditWorkshopTemplateCtrl',
                templateUrl: prefix.concat('workshopTemplateNew.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('email_template', {
                url: '/email_template',
                controller: 'EmailTemplateCtrl',
                templateUrl: prefix.concat('adminEmailTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('email_template_new', {
                url: '/email/template/new',
                controller: 'NewEmailTemplateCtrl',
                templateUrl: prefix.concat('adminNewEmailTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('email_template_edit', {
                url: '/email/template/edit',
                controller: 'EditEmailTemplateCtrl',
                templateUrl: prefix.concat('adminEditEmailTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('blacklist',{
                url: '/blacklist',
                controller: 'BlacklistCtrl',
                templateUrl: prefix.concat('adminBlacklist.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('administrator_management', {
                    url: '/administrator_management',
                    controller: 'AdministratorManagementCtrl',
                    templateUrl: prefix.concat('administratorManagement.html'),
                data: {
                    requiresLogin: true
                }
                })

            .state('administrator_workshop_details', {
                url: '/workshop/management/:id',
                controller: 'adminWorkshopDetailsCtrl',
                templateUrl: prefix.concat('adminWorkshopDetails.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('admin_workshop_management',{
                url: '/workshop/management',
                controller: 'adminWorkshopManagementCtrl',
                templateUrl: prefix.concat('adminWorkshopManagement.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('settings', {
                url: '/settings',
                controller: 'SettingsCtrl',
                templateUrl: prefix.concat('adminSettings.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('admininvite',{
                url: '/admin/create/:token',
                controller: 'AdminCreateCtrl',
                templateUrl: prefix.concat('adminInvite.html')

            })
            .state('legalnotice',{
                url: '/legalnotice',
                controller: 'LegalNoticeCtrl',
                templateUrl: prefix.concat('legalNotice.html')
            })
            .state('contact',{
                url: '/contact',
                controller: 'ContactCtrl',
                templateUrl: prefix.concat('contact.html')
            });

        $urlRouterProvider.otherwise('/workshops');

    }
]);

mainApp.config(['jwtInterceptorProvider','$httpProvider','$urlRouterProvider',function(jwtInterceptorProvider,$httpProvider,$urlRouterProvider){
    jwtInterceptorProvider.tokenGetter = function(store) {
        return store.get('jwt');
    }

    $httpProvider.interceptors.push('jwtInterceptor');
}])
    .run(['$rootScope','$state','store','jwtHelper','UIHelper',function($rootScope, $state, store, jwtHelper,UIHelper) {
        UIHelper.ToggleLogout();
        $rootScope.$on('$stateChangeStart', function(e, to) {
            if (to.data && to.data.requiresLogin) {
                if (!store.get('jwt') || jwtHelper.isTokenExpired(store.get('jwt'))) {
                    e.preventDefault();
                    $state.go('login');
                }
            }

        });
    }]);

mainApp.config(['$translateProvider', function($translateProvider) {
    $translateProvider.useStaticFilesLoader({
        prefix: 'resources/local/lang-',
        suffix: '.json'
    });
    $translateProvider.preferredLanguage('en');
}]);
/**
 * @ngdoc service
 * @descrption Helper service to show or hide User UI elements
 * @name  mainApp.UIHelper
 */
mainApp.factory('UIHelper',['$rootScope','store','jwtHelper',function($rootScope,store,jwtHelper){
    return {
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#HideUserUI
         * @description hide the user UI
         * @methodOf mainApp.UIHelper
         */
        HideUserUI: function(){
            $rootScope.hide_user_ui = true;
        },
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#ShowUserUI
         * @description show the user UI
         * @methodOf mainApp.UIHelper
         */
        ShowUserUI: function(){
            $rootScope.hide_user_ui = false;
        },
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#ToggleUserUI
         * @description toggle the user UI
         * @methodOf mainApp.UIHelper
         */
        ToggleUserUI: function(){
            $rootScope.hide_user_ui = ! $rootScope.hide_user_ui;
        },
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#ToggleLogout
         * @description Toggles, if the Logout or the Login Button is shown
         * @methodOf mainApp.UIHelper
         */
        ToggleLogout: function(){
            var jwt  = store.get('jwt');
            if(!jwt){
                $rootScope.logged_in = false;
                return;
            }
            $rootScope.logged_in = !jwtHelper.isTokenExpired(jwt);
        },
        /**
         * @ndoc function
         * @name mainApp.UIHelper#logout
         * @description Deletes the saved JWT token from last login
         * @methodOf mainApp.UIHelper
         */
        logout: function(){
            if(store.get('jwt'))
                store.delete('jwt');
        }
    }
}]);
/**
 * @ngdoc directive
 * @name mainApp.compare-to
 */
mainApp.directive('compareTo',[function(){
    return {
        require: "ngModel",
        scope: {
            otherModelValue: "=compareTo"
        },
        link: function(scope, element, attributes, ngModel) {

            ngModel.$validators.compareTo = function(modelValue) {
                return modelValue == scope.otherModelValue;
            };

            scope.$watch("otherModelValue", function() {
                ngModel.$validate();
            });
        }
    };
    }
]);
mainApp.config(function($provide){
    $provide.decorator('taOptions', ['taRegisterTool', '$delegate', function(taRegisterTool, taOptions){
        // $delegate is the taOptions we are decorating
        // register the tool with textAngular
        taRegisterTool('usermail', {
            iconclass: "fa fa-user black",
            action: function(){
                this.$editor()
            }
        });
        // add the button to the default toolbar definition
        taOptions.toolbar[1].push('colourRed');
        return taOptions;
    }]);
});
<commit_msg>Updated app.js<commit_after>/**
 * @name mainApp
 * @requieres
 * @type {angular.Module}
 * @description Main module of the application
 */
var mainApp = angular.module('mainApp',[
    'ngRoute',
    'mainAppCtrls',
    'mgcrea.ngStrap',
    'ui.router',
    'angular-jwt',
    'restSvcs',
    'angular-storage',
    'pascalprecht.translate',
    'textAngular',
    'prntSvcs'
]);
/**
 * @name mainAppCtrls
 * @type {angular.Module}
 * @description Module containg all controller of the application
 */
var mainAppCtrls = angular.module('mainAppCtrls',["pascalprecht.translate"]);

mainApp.config(['$urlRouterProvider','$stateProvider',
    function($urlRouterProvider,$stateProvider)
    {
        var prefix = "resources/views/";

        $stateProvider
            .state('workshops',{
                url: '/workshops',
                controller: 'WorkshopListCtrl',
                templateUrl: prefix.concat('workshopList.html')
            })
            .state('workshopsdetails',{
                url: '/workshops/details/:id',
                controller: 'WorkshopDetailsCtrl',
                templateUrl: prefix.concat('workshopDetails.html')
            })

            .state('login',{
                url: '/login',
                controller: 'LoginCtrl',
                templateUrl: prefix.concat('login.html')
            })
            .state('enrollment_confirm',{
                url: '/enrollment_confirm/:id/:token',
                templateUrl: prefix.concat('enrollmentConfirm.html'),
                controller: 'enrollmentConfirmCtrl'
            })
            .state('unsubscribe',{
                url: '/unsubscribe/:id/:workshopid/:token',
                templateUrl: prefix.concat('unsubscribemessage.html'),
                controller: 'UnsubscribeController'
            })
            .state('password_reset',{
                url: '/password_reset/:token',
                templateUrl: prefix.concat('passwordReset.html'),
                controller: 'PasswordRestCtrl'
            })
            .state('dashboard',{
                url: '/dashboard',
                controller: 'DashboardCtrl',
                templateUrl: prefix.concat('adminDashboard.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('workshop_template',{
                url:'/workshop_template',
                controller:'WorkshopTemplateCtrl',
                templateUrl: prefix.concat('adminWorkshopTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('workshop_template_new', {
                url: '/workshop/template/new',
                controller: 'NewWorkshopTemplateCtrl',
                templateUrl: prefix.concat('adminNewWorkshopTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('workshop_template.edit', {
                url: '/edit/:id',
                controller: 'EditWorkshopTemplateCtrl',
                templateUrl: prefix.concat('workshopTemplateNew.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('email_template', {
                url: '/email_template',
                controller: 'EmailTemplateCtrl',
                templateUrl: prefix.concat('adminEmailTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('email_template_new', {
                url: '/email/template/new',
                controller: 'NewEmailTemplateCtrl',
                templateUrl: prefix.concat('adminNewEmailTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('email_template_edit', {
                url: '/email/template/edit',
                controller: 'EditEmailTemplateCtrl',
                templateUrl: prefix.concat('adminEditEmailTemplate.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('blacklist',{
                url: '/blacklist',
                controller: 'BlacklistCtrl',
                templateUrl: prefix.concat('adminBlacklist.html'),
                data: {
                    requiresLogin: true
                }
            })
            .state('administrator_management', {
                    url: '/administrator_management',
                    controller: 'AdministratorManagementCtrl',
                    templateUrl: prefix.concat('administratorManagement.html'),
                data: {
                    requiresLogin: true
                }
                })

            .state('administrator_workshop_details', {
                url: '/workshop/management/:id',
                controller: 'adminWorkshopDetailsCtrl',
                templateUrl: prefix.concat('adminWorkshopDetails.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('admin_workshop_management',{
                url: '/workshop/management',
                controller: 'adminWorkshopManagementCtrl',
                templateUrl: prefix.concat('adminWorkshopManagement.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('settings', {
                url: '/settings',
                controller: 'SettingsCtrl',
                templateUrl: prefix.concat('adminSettings.html'),
                data: {
                    requiresLogin: true
                }
            })

            .state('admininvite',{
                url: '/admin/create/:token',
                controller: 'AdminCreateCtrl',
                templateUrl: prefix.concat('adminInvite.html')

            })
            .state('legalnotice',{
                url: '/legalnotice',
                controller: 'LegalNoticeCtrl',
                templateUrl: prefix.concat('legalNotice.html')
            })
            .state('contact',{
                url: '/contact',
                controller: 'ContactCtrl',
                templateUrl: prefix.concat('contact.html')
            });

        $urlRouterProvider.otherwise('/workshops');

    }
]);

mainApp.config(['jwtInterceptorProvider','$httpProvider','$urlRouterProvider',function(jwtInterceptorProvider,$httpProvider,$urlRouterProvider){
    jwtInterceptorProvider.tokenGetter = function(store) {
        return store.get('jwt');
    }

    $httpProvider.interceptors.push('jwtInterceptor');
}])
    .run(['$rootScope','$state','store','jwtHelper','UIHelper',function($rootScope, $state, store, jwtHelper,UIHelper) {
        UIHelper.ToggleLogout();
        $rootScope.$on('$stateChangeStart', function(e, to) {
            if (to.data && to.data.requiresLogin) {
                if (!store.get('jwt') || jwtHelper.isTokenExpired(store.get('jwt'))) {
                    e.preventDefault();
                    $state.go('login');
                }
            }

        });
    }]);

mainApp.config(['$translateProvider', function($translateProvider) {
    $translateProvider.useStaticFilesLoader({
        prefix: 'resources/local/lang-',
        suffix: '.json'
    });
    $translateProvider.preferredLanguage('en');
}]);
/**
 * @ngdoc service
 * @descrption Helper service to show or hide User UI elements
 * @name  mainApp.UIHelper
 */
mainApp.factory('UIHelper',['$rootScope','store','jwtHelper',function($rootScope,store,jwtHelper){
    return {
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#HideUserUI
         * @description hide the user UI
         * @methodOf mainApp.UIHelper
         */
        HideUserUI: function(){
            $rootScope.hide_user_ui = true;
        },
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#ShowUserUI
         * @description show the user UI
         * @methodOf mainApp.UIHelper
         */
        ShowUserUI: function(){
            $rootScope.hide_user_ui = false;
        },
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#ToggleUserUI
         * @description toggle the user UI
         * @methodOf mainApp.UIHelper
         */
        ToggleUserUI: function(){
            $rootScope.hide_user_ui = ! $rootScope.hide_user_ui;
        },
        /**
         * @ngdoc function
         * @name mainApp.UIHelper#ToggleLogout
         * @description Toggles, if the Logout or the Login Button is shown
         * @methodOf mainApp.UIHelper
         */
        ToggleLogout: function(){
            var jwt  = store.get('jwt');
            if(!jwt){
                $rootScope.logged_in = false;
                return;
            }
            $rootScope.logged_in = !jwtHelper.isTokenExpired(jwt);
        },
        /**
         * @ndoc function
         * @name mainApp.UIHelper#logout
         * @description Deletes the saved JWT token from last login
         * @methodOf mainApp.UIHelper
         */
        logout: function(){
            if(store.get('jwt'))
                store.delete('jwt');
        }
    }
}]);
/**
 * @ngdoc directive
 * @name mainApp.compare-to
 */
mainApp.directive('compareTo',[function(){
    return {
        require: "ngModel",
        scope: {
            otherModelValue: "=compareTo"
        },
        link: function(scope, element, attributes, ngModel) {

            ngModel.$validators.compareTo = function(modelValue) {
                return modelValue == scope.otherModelValue;
            };

            scope.$watch("otherModelValue", function() {
                ngModel.$validate();
            });
        }
    };
    }
]);
mainApp.config(function($provide){
    $provide.decorator('taOptions', ['taRegisterTool', '$delegate', function(taRegisterTool, taOptions){
        // $delegate is the taOptions we are decorating
        // register the tool with textAngular
        taRegisterTool('usermail', {
            iconclass: "fa fa-user black",
            action: function(){
                this.$editor()
            }
        });
        // add the button to the default toolbar definition
        taOptions.toolbar[1].push('colourRed');
        return taOptions;
    }]);
});
<|endoftext|>


<commit_before>// Load our dependencies
var assert = require('assert');
var async = require('async');
var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var gutil = require('gulp-util');
var Minimatch = require('minimatch').Minimatch;
var templater = require('spritesheet-templates');
var Spritesmith = require('spritesmith');
var through2 = require('through2');
var url = require('url2');

function ExtFormat() {
  this.formatObj = {};
}
ExtFormat.prototype = {
  add: function (name, val) {
    this.formatObj[name] = val;
  },
  get: function (filepath) {
    // Grab the extension from the filepath
    var ext = path.extname(filepath);
    var lowerExt = ext.toLowerCase();

    // Look up the file extenion from our format object
    var formatObj = this.formatObj;
    var format = formatObj[lowerExt];
    return format;
  }
};

// Create img and css formats
var imgFormats = new ExtFormat();
var cssFormats = new ExtFormat();

// Add our img formats
imgFormats.add('.png', 'png');
imgFormats.add('.jpg', 'jpeg');
imgFormats.add('.jpeg', 'jpeg');

// Add our css formats
cssFormats.add('.styl', 'stylus');
cssFormats.add('.stylus', 'stylus');
cssFormats.add('.sass', 'sass');
cssFormats.add('.scss', 'scss');
cssFormats.add('.less', 'less');
cssFormats.add('.json', 'json');
cssFormats.add('.css', 'css');

// Copy/paste helper from gulp
// https://github.com/wearefractal/glob-stream/blob/v5.0.0/index.js#L131-L138
function unrelative(cwd, glob) {
  var mod = '';
  if (glob[0] === '!') {
    mod = glob[0];
    glob = glob.slice(1);
  }
  return mod + path.resolve(cwd, glob);
}

// Define helper for coordinate naming
function getCoordinateName(filepath) {
  // Extract the image name (exlcuding extension)
  var fullname = path.basename(filepath);
  var nameParts = fullname.split('.');

  // If there is are more than 2 parts, pop the last one
  if (nameParts.length >= 2) {
    nameParts.pop();
  }

  // Return our modified filename
  return nameParts.join('.');
}

// Create a gulp-spritesmith function
function gulpSpritesmith(params) {
  var imgName = params.imgName;
  var cssName = params.cssName;
  assert(imgName, 'An `imgName` parameter was not provided to `gulp.spritesmith` (required)');
  assert(cssName, 'A `cssName` parameter was not provided to `gulp.spritesmith` (required)');

  // If there are settings for retina, verify our all of them are present
  var retinaSrcFilter = params.retinaSrcFilter;
  var retinaImgName = params.retinaImgName;
  if (retinaSrcFilter || retinaImgName) {
    assert(retinaSrcFilter && retinaImgName, 'Retina settings detected. We must have both `retinaSrcFilter` and ' +
      '`retinaImgName` provided for retina to work');
  }

  // Define our output streams
  var imgStream = through2.obj();
  var cssStream = through2.obj();

  // Create a stream to take in images
  var images = [];
  var onData = function (file, encoding, cb) {
    images.push(file);
    cb();
  };

  // When we have completed our input
  var onEnd = function (cb) {
    // If there are no images present, exit early
    // DEV: This is against the behavior of `spritesmith` but pro-gulp
    // DEV: See https://github.com/twolfson/gulp.spritesmith/issues/17
    if (images.length === 0) {
      imgStream.push(null);
      cssStream.push(null);
      return cb();
    }

    // Determine the format of the image
    var imgOpts = params.imgOpts || {};
    var imgFormat = imgOpts.format || imgFormats.get(imgName) || 'png';

    // Set up the defautls for imgOpts
    imgOpts = _.defaults({}, imgOpts, {format: imgFormat});

    // If we have retina settings, filter out the retina images
    var retinaImages;
    if (retinaSrcFilter) {
      // Filter out our retina files
      // https://github.com/wearefractal/glob-stream/blob/v5.0.0/index.js#L84-L87
      retinaImages = [];
      var retinaSrcPatterns = Array.isArray(retinaSrcFilter) ? retinaSrcFilter : [retinaSrcFilter];
      images = images.filter(function filterSrcFile(file) {
        // If we have a retina file, filter it out
        var matched = retinaSrcPatterns.some(function matchMinimatches(retinaSrcPattern) {
          var minimatch = new Minimatch(unrelative(file.cwd, retinaSrcPattern));
          return minimatch.match(file.path);
        });
        if (matched) {
          retinaImages.push(file);
          return false;
        // Otherwise, keep it in the src files
        } else {
          return true;
        }
      });

      // If we have a different amount of normal and retina images, complain and leave
      if (images.length !== retinaImages.length) {
        var err = new Error('Retina settings detected but ' + retinaImages.length + ' retina images were found. ' +
          'We have ' + images.length + ' normal images and expect these numbers to line up. ' +
          'Please double check `retinaSrcFilter`.');
        err.images = images;
        err.retinaImages = retinaImages;
        this.emit('error', err);
        imgStream.push(null);
        cssStream.push(null);
        return cb();
      }
    }

    // Prepare spritesmith parameters
    var spritesmithParams = {
      engine: params.engine,
      algorithm: params.algorithm,
      padding: params.padding || 0,
      algorithmOpts: params.algorithmOpts || {},
      engineOpts: params.engineOpts || {},
      exportOpts: imgOpts
    };
    var that = this;

    // Construct our spritesmiths
    var spritesmith = new Spritesmith(spritesmithParams);
    var retinaSpritesmithParams;
    var retinaSpritesmith;
    if (retinaImages) {
      retinaSpritesmithParams = _.defaults({
        padding: spritesmithParams.padding * 2
      }, spritesmithParams);
      retinaSpritesmith = new Spritesmith(retinaSpritesmithParams);
    }

    // In parallel
    async.parallel([
      // Load in our normal images
      function generateNormalImages(callback) {
        spritesmith.createImages(images, callback);
      },
      // If we have retina images, load them in as well
      function generateRetinaSpritesheet(callback) {
        if (retinaImages) {
          retinaSpritesmith.createImages(retinaImages, callback);
        } else {
          process.nextTick(callback);
        }
      }
    ], function handleImages(err, resultArr) {
      // If an error occurred, emit it
      if (err) {
        return cb(err);
      }

      // Otherwise, validate our images line up
      var normalSprites = resultArr[0];
      var retinaSprites = resultArr[1];

      // If we have retina images, verify the widths line up
      if (retinaSprites) {
        // Perform our assertions
        var errorEncountered = false;
        normalSprites.forEach(function validateImageSizes(normalSprite, i) {
          var retinaSprite = retinaSprites[i];
          if (retinaSprite.width !== normalSprite.width * 2 || retinaSprite.height !== normalSprite.height * 2) {
            errorEncountered = true;
            var err = new Error('Normal sprite has inconsistent size with retina sprite. ' +
              '"' + images[i].path + '" is ' + normalSprite.width + 'x' + normalSprite.height + ' while ' +
              '"' + retinaImages[i].path + '" is ' + retinaSprite.width + 'x' + retinaSprite.height + '.');
            err.normalSprite = normalSprite;
            err.retinaSprite = retinaSprite;
            that.emit('error', err);
          }
        });

        // If there was an error, then bail out
        if (errorEncountered) {
          imgStream.push(null);
          cssStream.push(null);
          return cb();
        }
      }

      // Process our images now
      var result = spritesmith.processImages(normalSprites, spritesmithParams);
      var retinaResult;
      if (retinaSprites) {
        retinaResult = retinaSpritesmith.processImages(retinaSprites, retinaSpritesmithParams);
      }

      // START OF DUPLICATE CODE FROM grunt-spritesmith
      // Generate a listing of CSS variables
      var coordinates = result.coordinates;
      var properties = result.properties;
      var spritePath = params.imgPath || url.relative(cssName, imgName);
      var spritesheetData = {
        width: properties.width,
        height: properties.height,
        image: spritePath
      };
      var cssVarMap = params.cssVarMap || function noop() {};
      var cleanCoords = [];

      // Clean up the file name of the file
      Object.getOwnPropertyNames(coordinates).sort().forEach(function (file) {
        // Extract out our name
        var name = getCoordinateName(file);
        var coords = coordinates[file];

        // Specify the image for the sprite
        coords.name = name;
        coords.source_image = file;
        // DEV: `image`, `total_width`, `total_height` are deprecated as they are overwritten in `spritesheet-templates`
        coords.image = spritePath;
        coords.total_width = properties.width;
        coords.total_height = properties.height;

        // Map the coordinates through cssVarMap
        coords = cssVarMap(coords) || coords;

        // Save the cleaned name and coordinates
        cleanCoords.push(coords);
      });

      // If we have retina sprites
      var retinaCleanCoords;
      var retinaGroups;
      var retinaSpritesheetInfo;
      if (retinaResult) {
        // Generate a listing of CSS variables
        var retinaCoordinates = retinaResult.coordinates;
        var retinaProperties = retinaResult.properties;
        var retinaSpritePath = params.retinaImgPath || url.relative(cssName, retinaImgName);
        retinaSpritesheetInfo = {
          width: retinaProperties.width,
          height: retinaProperties.height,
          image: retinaSpritePath
        };
        // DEV: We reuse cssVarMap
        retinaCleanCoords = [];

        // Clean up the file name of the file
        Object.getOwnPropertyNames(retinaCoordinates).sort().forEach(function prepareRetinaTemplateData(file) {
          var name = getCoordinateName(file);
          var coords = retinaCoordinates[file];
          coords.name = name;
          coords.source_image = file;
          coords.image = retinaSpritePath;
          coords.total_width = retinaProperties.width;
          coords.total_height = retinaProperties.height;
          coords = cssVarMap(coords) || coords;
          retinaCleanCoords.push(coords);
        });

        // Verify we have no conflicting file names (e.g. `1x/home.png` and `2x/home.png`)
        //   https://github.com/twolfson/gulp.spritesmith/issues/124
        var cleanCoordNames = _.pluck(cleanCoords, 'name');
        var retinaCleanCoordNames = _.pluck(retinaCleanCoords, 'name');
        var intersectingNames = _.intersection(cleanCoordNames, retinaCleanCoordNames);
        if (intersectingNames.length) {
          throw new Error('Normal and retina sprites have same names: ' + JSON.stringify(intersectingNames) + '. ' +
            'Please rename them to different names (e.g. `-1x`, `-2x`) or use `cssVarMap` to prevent collisions. ' +
            'See https://github.com/twolfson/gulp.spritesmith/issues/124 for more info');
        }

        // Generate groups for our coordinates
        retinaGroups = cleanCoords.map(function getRetinaGroups(normalSprite, i) {
          // Generate our group
          // DEV: Name is inherited from `cssVarMap` on normal sprite
          return {
            name: normalSprite.name,
            index: i
          };
        });
      }

      // If we have handlebars helpers, register them
      var handlebarsHelpers = params.cssHandlebarsHelpers;
      if (handlebarsHelpers) {
        Object.keys(handlebarsHelpers).forEach(function registerHelper(helperKey) {
          templater.registerHandlebarsHelper(helperKey, handlebarsHelpers[helperKey]);
        });
      }

      // If there is a custom template, use it
      var cssFormat = 'spritesmith-custom';
      var cssTemplate = params.cssTemplate;
      if (cssTemplate) {
        if (typeof cssTemplate === 'function') {
          templater.addTemplate(cssFormat, cssTemplate);
        } else {
          templater.addHandlebarsTemplate(cssFormat, fs.readFileSync(cssTemplate, 'utf8'));
        }
      // Otherwise, override the cssFormat and fallback to 'json'
      } else {
        cssFormat = params.cssFormat;
        if (!cssFormat) {
          cssFormat = cssFormats.get(cssName) || 'json';

          // If we are dealing with retina items, move to retina flavor (e.g. `scss` -> `scss_retina`)
          if (retinaGroups) {
            cssFormat += '_retina';
          }
        }
      }

      // Render the variables via `spritesheet-templates`
      var cssStr = templater({
        sprites: cleanCoords,
        spritesheet: spritesheetData,
        spritesheet_info: {
          name: params.cssSpritesheetName
        },
        retina_groups: retinaGroups,
        retina_sprites: retinaCleanCoords,
        retina_spritesheet: retinaSpritesheetInfo,
        retina_spritesheet_info: {
          name: params.cssRetinaSpritesheetName
        },
        retina_groups_info: {
          name: params.cssRetinaGroupsName
        }
      }, {
        format: cssFormat,
        formatOpts: params.cssOpts || {}
      });
      // END OF DUPLICATE CODE FROM grunt-spritesmith

      // Pipe out images as streams and forward their errors
      // TODO: Consider making joint stream default
      //   but allow for split stream which has more distinct errors
      //   e.g. spritesmith.split() = {css, img}
      result.image.on('error', function forwardImgError(err) {
        that.emit('error', err);
      });
      var imgFile = new gutil.File({
        path: imgName,
        contents: result.image
      });
      that.push(imgFile);
      imgStream.push(imgFile);
      if (retinaResult) {
        var retinaImgFile = new gutil.File({
          path: retinaImgName,
          contents: retinaResult.image
        });
        retinaResult.image.on('error', function forwardImgError(err) {
          that.emit('error', err);
        });
        that.push(retinaImgFile);
        imgStream.push(retinaImgFile);
      }

      // Close our image stream
      imgStream.push(null);

      // Output the CSS
      var cssFile = new gutil.File({
        path: cssName,
        contents: new Buffer(cssStr)
      });
      that.push(cssFile);
      cssStream.push(cssFile);
      cssStream.push(null);
      cb();
    });
  };

  // Return output stream with two sub-streams:
  // - master stream includes all files
  // - 'css' stream for css only
  // - 'img' stream for images only
  var retStream = through2.obj(onData, onEnd);
  retStream.css = cssStream;
  retStream.img = imgStream;
  return retStream;
}

module.exports = gulpSpritesmith;
<commit_msg>Fixed up remaining lint errors<commit_after>// Load our dependencies
var assert = require('assert');
var async = require('async');
var fs = require('fs');
var path = require('path');
var _ = require('underscore');
var gutil = require('gulp-util');
var Minimatch = require('minimatch').Minimatch;
var templater = require('spritesheet-templates');
var Spritesmith = require('spritesmith');
var through2 = require('through2');
var url = require('url2');

function ExtFormat() {
  this.formatObj = {};
}
ExtFormat.prototype = {
  add: function (name, val) {
    this.formatObj[name] = val;
  },
  get: function (filepath) {
    // Grab the extension from the filepath
    var ext = path.extname(filepath);
    var lowerExt = ext.toLowerCase();

    // Look up the file extenion from our format object
    var formatObj = this.formatObj;
    var format = formatObj[lowerExt];
    return format;
  }
};

// Create img and css formats
var imgFormats = new ExtFormat();
var cssFormats = new ExtFormat();

// Add our img formats
imgFormats.add('.png', 'png');
imgFormats.add('.jpg', 'jpeg');
imgFormats.add('.jpeg', 'jpeg');

// Add our css formats
cssFormats.add('.styl', 'stylus');
cssFormats.add('.stylus', 'stylus');
cssFormats.add('.sass', 'sass');
cssFormats.add('.scss', 'scss');
cssFormats.add('.less', 'less');
cssFormats.add('.json', 'json');
cssFormats.add('.css', 'css');

// Copy/paste helper from gulp
// https://github.com/wearefractal/glob-stream/blob/v5.0.0/index.js#L131-L138
function unrelative(cwd, glob) {
  var mod = '';
  if (glob[0] === '!') {
    mod = glob[0];
    glob = glob.slice(1);
  }
  return mod + path.resolve(cwd, glob);
}

// Define helper for coordinate naming
function getCoordinateName(filepath) {
  // Extract the image name (exlcuding extension)
  var fullname = path.basename(filepath);
  var nameParts = fullname.split('.');

  // If there is are more than 2 parts, pop the last one
  if (nameParts.length >= 2) {
    nameParts.pop();
  }

  // Return our modified filename
  return nameParts.join('.');
}

// Create a gulp-spritesmith function
function gulpSpritesmith(params) {
  var imgName = params.imgName;
  var cssName = params.cssName;
  assert(imgName, 'An `imgName` parameter was not provided to `gulp.spritesmith` (required)');
  assert(cssName, 'A `cssName` parameter was not provided to `gulp.spritesmith` (required)');

  // If there are settings for retina, verify our all of them are present
  var retinaSrcFilter = params.retinaSrcFilter;
  var retinaImgName = params.retinaImgName;
  if (retinaSrcFilter || retinaImgName) {
    assert(retinaSrcFilter && retinaImgName, 'Retina settings detected. We must have both `retinaSrcFilter` and ' +
      '`retinaImgName` provided for retina to work');
  }

  // Define our output streams
  var imgStream = through2.obj();
  var cssStream = through2.obj();

  // Create a stream to take in images
  var images = [];
  var onData = function (file, encoding, cb) {
    images.push(file);
    cb();
  };

  // When we have completed our input
  var onEnd = function (cb) {
    // If there are no images present, exit early
    // DEV: This is against the behavior of `spritesmith` but pro-gulp
    // DEV: See https://github.com/twolfson/gulp.spritesmith/issues/17
    if (images.length === 0) {
      imgStream.push(null);
      cssStream.push(null);
      return cb();
    }

    // Determine the format of the image
    var imgOpts = params.imgOpts || {};
    var imgFormat = imgOpts.format || imgFormats.get(imgName) || 'png';

    // Set up the defautls for imgOpts
    imgOpts = _.defaults({}, imgOpts, {format: imgFormat});

    // If we have retina settings, filter out the retina images
    var retinaImages;
    if (retinaSrcFilter) {
      // Filter out our retina files
      // https://github.com/wearefractal/glob-stream/blob/v5.0.0/index.js#L84-L87
      retinaImages = [];
      var retinaSrcPatterns = Array.isArray(retinaSrcFilter) ? retinaSrcFilter : [retinaSrcFilter];
      images = images.filter(function filterSrcFile(file) {
        // If we have a retina file, filter it out
        var matched = retinaSrcPatterns.some(function matchMinimatches(retinaSrcPattern) {
          var minimatch = new Minimatch(unrelative(file.cwd, retinaSrcPattern));
          return minimatch.match(file.path);
        });
        if (matched) {
          retinaImages.push(file);
          return false;
        // Otherwise, keep it in the src files
        } else {
          return true;
        }
      });

      // If we have a different amount of normal and retina images, complain and leave
      if (images.length !== retinaImages.length) {
        var err = new Error('Retina settings detected but ' + retinaImages.length + ' retina images were found. ' +
          'We have ' + images.length + ' normal images and expect these numbers to line up. ' +
          'Please double check `retinaSrcFilter`.');
        err.images = images;
        err.retinaImages = retinaImages;
        this.emit('error', err);
        imgStream.push(null);
        cssStream.push(null);
        return cb();
      }
    }

    // Prepare spritesmith parameters
    var spritesmithParams = {
      engine: params.engine,
      algorithm: params.algorithm,
      padding: params.padding || 0,
      algorithmOpts: params.algorithmOpts || {},
      engineOpts: params.engineOpts || {},
      exportOpts: imgOpts
    };
    var that = this;

    // Construct our spritesmiths
    var spritesmith = new Spritesmith(spritesmithParams);
    var retinaSpritesmithParams; // eslint-disable-line
    var retinaSpritesmith; // eslint-disable-line
    if (retinaImages) {
      retinaSpritesmithParams = _.defaults({
        padding: spritesmithParams.padding * 2
      }, spritesmithParams);
      retinaSpritesmith = new Spritesmith(retinaSpritesmithParams);
    }

    // In parallel
    async.parallel([
      // Load in our normal images
      function generateNormalImages(callback) {
        spritesmith.createImages(images, callback);
      },
      // If we have retina images, load them in as well
      function generateRetinaSpritesheet(callback) {
        if (retinaImages) {
          return retinaSpritesmith.createImages(retinaImages, callback);
        } else {
          return process.nextTick(callback);
        }
      }
    ], function handleImages(err, resultArr) {
      // If an error occurred, emit it
      if (err) {
        return cb(err);
      }

      // Otherwise, validate our images line up
      var normalSprites = resultArr[0];
      var retinaSprites = resultArr[1];

      // If we have retina images, verify the widths line up
      if (retinaSprites) {
        // Perform our assertions
        var errorEncountered = false;
        normalSprites.forEach(function validateImageSizes(normalSprite, i) {
          var retinaSprite = retinaSprites[i];
          if (retinaSprite.width !== normalSprite.width * 2 || retinaSprite.height !== normalSprite.height * 2) {
            errorEncountered = true;
            var err = new Error('Normal sprite has inconsistent size with retina sprite. ' +
              '"' + images[i].path + '" is ' + normalSprite.width + 'x' + normalSprite.height + ' while ' +
              '"' + retinaImages[i].path + '" is ' + retinaSprite.width + 'x' + retinaSprite.height + '.');
            err.normalSprite = normalSprite;
            err.retinaSprite = retinaSprite;
            that.emit('error', err);
          }
        });

        // If there was an error, then bail out
        if (errorEncountered) {
          imgStream.push(null);
          cssStream.push(null);
          return cb();
        }
      }

      // Process our images now
      var result = spritesmith.processImages(normalSprites, spritesmithParams);
      var retinaResult;
      if (retinaSprites) {
        retinaResult = retinaSpritesmith.processImages(retinaSprites, retinaSpritesmithParams);
      }

      // START OF DUPLICATE CODE FROM grunt-spritesmith
      // Generate a listing of CSS variables
      var coordinates = result.coordinates;
      var properties = result.properties;
      var spritePath = params.imgPath || url.relative(cssName, imgName);
      var spritesheetData = {
        width: properties.width,
        height: properties.height,
        image: spritePath
      };
      var cssVarMap = params.cssVarMap || function noop() {};
      var cleanCoords = [];

      // Clean up the file name of the file
      Object.getOwnPropertyNames(coordinates).sort().forEach(function (file) {
        // Extract out our name
        var name = getCoordinateName(file);
        var coords = coordinates[file];

        // Specify the image for the sprite
        coords.name = name;
        coords.source_image = file;
        // DEV: `image`, `total_width`, `total_height` are deprecated as they are overwritten in `spritesheet-templates`
        coords.image = spritePath;
        coords.total_width = properties.width;
        coords.total_height = properties.height;

        // Map the coordinates through cssVarMap
        coords = cssVarMap(coords) || coords;

        // Save the cleaned name and coordinates
        cleanCoords.push(coords);
      });

      // If we have retina sprites
      var retinaCleanCoords; // eslint-disable-line
      var retinaGroups; // eslint-disable-line
      var retinaSpritesheetInfo; // eslint-disable-line
      if (retinaResult) {
        // Generate a listing of CSS variables
        var retinaCoordinates = retinaResult.coordinates;
        var retinaProperties = retinaResult.properties;
        var retinaSpritePath = params.retinaImgPath || url.relative(cssName, retinaImgName);
        retinaSpritesheetInfo = {
          width: retinaProperties.width,
          height: retinaProperties.height,
          image: retinaSpritePath
        };
        // DEV: We reuse cssVarMap
        retinaCleanCoords = [];

        // Clean up the file name of the file
        Object.getOwnPropertyNames(retinaCoordinates).sort().forEach(function prepareRetinaTemplateData(file) {
          var name = getCoordinateName(file);
          var coords = retinaCoordinates[file];
          coords.name = name;
          coords.source_image = file;
          coords.image = retinaSpritePath;
          coords.total_width = retinaProperties.width;
          coords.total_height = retinaProperties.height;
          coords = cssVarMap(coords) || coords;
          retinaCleanCoords.push(coords);
        });

        // Verify we have no conflicting file names (e.g. `1x/home.png` and `2x/home.png`)
        //   https://github.com/twolfson/gulp.spritesmith/issues/124
        var cleanCoordNames = _.pluck(cleanCoords, 'name');
        var retinaCleanCoordNames = _.pluck(retinaCleanCoords, 'name');
        var intersectingNames = _.intersection(cleanCoordNames, retinaCleanCoordNames);
        if (intersectingNames.length) {
          throw new Error('Normal and retina sprites have same names: ' + JSON.stringify(intersectingNames) + '. ' +
            'Please rename them to different names (e.g. `-1x`, `-2x`) or use `cssVarMap` to prevent collisions. ' +
            'See https://github.com/twolfson/gulp.spritesmith/issues/124 for more info');
        }

        // Generate groups for our coordinates
        retinaGroups = cleanCoords.map(function getRetinaGroups(normalSprite, i) {
          // Generate our group
          // DEV: Name is inherited from `cssVarMap` on normal sprite
          return {
            name: normalSprite.name,
            index: i
          };
        });
      }

      // If we have handlebars helpers, register them
      var handlebarsHelpers = params.cssHandlebarsHelpers;
      if (handlebarsHelpers) {
        Object.keys(handlebarsHelpers).forEach(function registerHelper(helperKey) {
          templater.registerHandlebarsHelper(helperKey, handlebarsHelpers[helperKey]);
        });
      }

      // If there is a custom template, use it
      var cssFormat = 'spritesmith-custom';
      var cssTemplate = params.cssTemplate;
      if (cssTemplate) {
        if (typeof cssTemplate === 'function') {
          templater.addTemplate(cssFormat, cssTemplate);
        } else {
          templater.addHandlebarsTemplate(cssFormat, fs.readFileSync(cssTemplate, 'utf8'));
        }
      // Otherwise, override the cssFormat and fallback to 'json'
      } else {
        cssFormat = params.cssFormat;
        if (!cssFormat) {
          cssFormat = cssFormats.get(cssName) || 'json';

          // If we are dealing with retina items, move to retina flavor (e.g. `scss` -> `scss_retina`)
          if (retinaGroups) {
            cssFormat += '_retina';
          }
        }
      }

      // Render the variables via `spritesheet-templates`
      var cssStr = templater({
        sprites: cleanCoords,
        spritesheet: spritesheetData,
        spritesheet_info: {
          name: params.cssSpritesheetName
        },
        retina_groups: retinaGroups,
        retina_sprites: retinaCleanCoords,
        retina_spritesheet: retinaSpritesheetInfo,
        retina_spritesheet_info: {
          name: params.cssRetinaSpritesheetName
        },
        retina_groups_info: {
          name: params.cssRetinaGroupsName
        }
      }, {
        format: cssFormat,
        formatOpts: params.cssOpts || {}
      });
      // END OF DUPLICATE CODE FROM grunt-spritesmith

      // Pipe out images as streams and forward their errors
      // TODO: Consider making joint stream default
      //   but allow for split stream which has more distinct errors
      //   e.g. spritesmith.split() = {css, img}
      result.image.on('error', function forwardImgError(err) {
        that.emit('error', err);
      });
      var imgFile = new gutil.File({
        path: imgName,
        contents: result.image
      });
      that.push(imgFile);
      imgStream.push(imgFile);
      if (retinaResult) {
        var retinaImgFile = new gutil.File({
          path: retinaImgName,
          contents: retinaResult.image
        });
        retinaResult.image.on('error', function forwardImgError(err) {
          that.emit('error', err);
        });
        that.push(retinaImgFile);
        imgStream.push(retinaImgFile);
      }

      // Close our image stream
      imgStream.push(null);

      // Output the CSS
      var cssFile = new gutil.File({
        path: cssName,
        contents: new Buffer(cssStr)
      });
      that.push(cssFile);
      cssStream.push(cssFile);
      cssStream.push(null);
      cb();
    });
  };

  // Return output stream with two sub-streams:
  // - master stream includes all files
  // - 'css' stream for css only
  // - 'img' stream for images only
  var retStream = through2.obj(onData, onEnd);
  retStream.css = cssStream;
  retStream.img = imgStream;
  return retStream;
}

module.exports = gulpSpritesmith;
<|endoftext|>


<commit_before>/** global: Garnish */
/**
 * Disclosure Widget
 */
Garnish.DisclosureMenu = Garnish.Base.extend(
  {
    settings: null,

    $trigger: null,
    $container: null,
    $alignmentElement: null,
    $wrapper: null,

    _windowWidth: null,
    _windowHeight: null,
    _windowScrollLeft: null,
    _windowScrollTop: null,

    _wrapperElementOffset: null,
    _alignmentElementOffset: null,
    _triggerWidth: null,
    _triggerHeight: null,

    _menuWidth: null,
    _menuHeight: null,

    /**
     * Constructor
     */
    init: function (trigger, settings) {
      this.setSettings(settings, Garnish.DisclosureMenu.defaults);

      this.$trigger = $(trigger);
      var triggerId = this.$trigger.attr('aria-controls');
      this.$container = $("#" + triggerId);

      if (!this.$container) return; /* Exit if no disclosure container is found */

      // Get and store expanded state from trigger
      var expanded = this.$trigger.attr('aria-expanded');

      // If no expanded state exists on trigger, add for a11y
      if (!expanded) {
        this.$trigger.attr('aria-expanded', 'false');
      }

      // Capture additional alignment element
      var alignmentSelector = this.$container.data('align-to');
      if (alignmentSelector) {
        this.$alignmentElement = $(alignmentSelector);
      } else {
        this.$alignmentElement = this.$trigger;
      }

      var wrapper = this.$container.closest('[data-wrapper]');
      if (wrapper) {
        this.$wrapper = wrapper;
      }

      this.addDisclosureMenuEventListeners();
    },

    addDisclosureMenuEventListeners: function() {
      this.addListener(this.$trigger, 'click', function() {
        this.handleTriggerClick();
      });

      this.addListener(this.$container, 'keyup', function(event) {
        this.handleKeypress(event);
      });

      this.addListener(this.$container, 'focusout', function(event) {
        var newTarget = event.relatedTarget;
        var newTargetIsInsideDisclosure = this.$container.has(newTarget).length > 0;

        // If click target matches trigger element or disclosure child, do nothing
      if (newTarget === this.$trigger.get(0) || newTargetIsInsideDisclosure) {
          return;
        }

        this.hide();
      });
    },

    handleKeypress: function(event) {
      if (event.key === 'Escape') {
        this.hide();
        this.$trigger.focus();
      }
    },

    isExpanded: function () {
      var isExpanded = this.$trigger.attr('aria-expanded');

      return isExpanded === 'true';
    },

    handleTriggerClick: function() {
      if (!this.isExpanded()) {
        this.show();
      } else {
        this.hide();
      }
    },

    show: function () {
      if (this.isExpanded()) {
        return;
      }

      this.setContainerPosition();
      this.addListener(
        Garnish.$scrollContainer,
        'scroll',
        'setContainerPosition'
      );

      this.$container.velocity('stop');
      this.$container.css({
        opacity: 1,
        display: 'block',
      });

      // Set ARIA attribute for expanded
      this.$trigger.attr('aria-expanded', 'true');

      // Focus first focusable element
      var firstFocusableEl = this.$container.find(':focusable')[0];
      if (firstFocusableEl) {
        firstFocusableEl.focus();
      } else {
        this.$container.attr('tabindex', '-1');
        this.$container.focus();
      }
    },

    hide: function () {
      if (!this.isExpanded()) {
        return;
      }

      this.$container.velocity(
        'fadeOut',
        { duration: Garnish.FX_DURATION }
      );

      this.$trigger.attr('aria-expanded', 'false');
    },

    setContainerPosition: function () {
      this._windowWidth = Garnish.$win.width();
      this._windowHeight = Garnish.$win.height();
      this._windowScrollLeft = Garnish.$win.scrollLeft();
      this._windowScrollTop = Garnish.$win.scrollTop();

      this._alignmentElementOffset = this.$alignmentElement[0].getBoundingClientRect();

      this._wrapperElementOffset = this.$wrapper[0].getBoundingClientRect();

      this._triggerWidth = this.$trigger.outerWidth();

      this.$container.css('minWidth', 0);
      this.$container.css(
        'minWidth',
        this._triggerWidth -
          (this.$container.outerWidth() - this.$container.width())
      );

      this._menuWidth = this.$container.outerWidth();
      this._menuHeight = this.$container.outerHeight();

      // Is there room for the menu below the trigger?
      var topClearance = this._alignmentElementOffset.top,
        bottomClearance = this._windowHeight - this._alignmentElementOffset.bottom;

      // Find top/bottom offset relative to wrapper element
      var topAdjustment = this._alignmentElementOffset.top - this._wrapperElementOffset.top;
      var bottomAdjustment = this._alignmentElementOffset.bottom - this._wrapperElementOffset.bottom;

      var bottomClearanceExists =
        bottomClearance >= this._menuHeight ||
        (topClearance < this._menuHeight && bottomClearance >= topClearance);

      if (bottomClearanceExists) {
        this.$container.css({
          top: 'calc(100% + ' + bottomAdjustment + 'px)',
          bottom: 'unset',
          maxHeight: bottomClearance - this.settings.windowSpacing,
        });
      } else {
        this.$container.css({
          bottom: 'calc(100% - ' + topAdjustment + 'px)',
          top: 'unset',
          maxHeight: topClearance - this.settings.windowSpacing,
        });
      }

      // Figure out how we're aliging it
      var align = this.$container.data('align');

      if (align !== 'left' && align !== 'center' && align !== 'right') {
        align = 'left';
      }

      if (align === 'center') {
        this._alignCenter();
      } else {
        // Figure out which options are actually possible
        var rightClearance =
            this._windowWidth +
            this._windowScrollLeft -
            (this._alignmentElementOffset.left + this._menuWidth),
          leftClearance = this._alignmentElementOffset.right - this._menuWidth;

        if ((align === 'right' && leftClearance >= 0) || rightClearance < 0) {
          this._alignRight();
        } else {
          this._alignLeft();
        }
      }

      delete this._windowWidth;
      delete this._windowHeight;
      delete this._windowScrollLeft;
      delete this._windowScrollTop;
      delete this._wrapperElementOffset;
      delete this._alignmentElementOffset;
      delete this._triggerWidth;
      delete this._triggerHeight;
      delete this._menuWidth;
      delete this._menuHeight;
    },

    _alignLeft: function () {
      var leftAdjustment = this._alignmentElementOffset.left - this._wrapperElementOffset.left;

      this.$container.css({
        right: 'unset',
        left: leftAdjustment + 'px',
      });
    },

    _alignRight: function () {
      var rightAdjustment = this._alignmentElementOffset.right - this._wrapperElementOffset.right;

      this.$container.css({
        left: 'unset',
        right: - rightAdjustment + 'px',
      });
    },

    _alignCenter: function () {
      var left = Math.round(this._triggerWidth / 2 - this._menuWidth / 2);
      var leftAdjustment = this._alignmentElementOffset.left - this._wrapperElementOffset.left;

      this.$container.css('left', left - leftAdjustment);
    },
  },
  {
    defaults: {
      windowSpacing: 5,
    },
  }
);
<commit_msg>Add additional key interactions for going to next/previous focusable element in menu based on directional keys<commit_after>/** global: Garnish */
/**
 * Disclosure Widget
 */
Garnish.DisclosureMenu = Garnish.Base.extend(
  {
    settings: null,

    $trigger: null,
    $container: null,
    $alignmentElement: null,
    $wrapper: null,

    _windowWidth: null,
    _windowHeight: null,
    _windowScrollLeft: null,
    _windowScrollTop: null,

    _wrapperElementOffset: null,
    _alignmentElementOffset: null,
    _triggerWidth: null,
    _triggerHeight: null,

    _menuWidth: null,
    _menuHeight: null,

    /**
     * Constructor
     */
    init: function (trigger, settings) {
      this.setSettings(settings, Garnish.DisclosureMenu.defaults);

      this.$trigger = $(trigger);
      var triggerId = this.$trigger.attr('aria-controls');
      this.$container = $("#" + triggerId);

      if (!this.$container) return; /* Exit if no disclosure container is found */

      // Get and store expanded state from trigger
      var expanded = this.$trigger.attr('aria-expanded');

      // If no expanded state exists on trigger, add for a11y
      if (!expanded) {
        this.$trigger.attr('aria-expanded', 'false');
      }

      // Capture additional alignment element
      var alignmentSelector = this.$container.data('align-to');
      if (alignmentSelector) {
        this.$alignmentElement = $(alignmentSelector);
      } else {
        this.$alignmentElement = this.$trigger;
      }

      var wrapper = this.$container.closest('[data-wrapper]');
      if (wrapper) {
        this.$wrapper = wrapper;
      }

      this.addDisclosureMenuEventListeners();
    },

    addDisclosureMenuEventListeners: function() {
      this.addListener(this.$trigger, 'click', function() {
        this.handleTriggerClick();
      });

      this.addListener(this.$container, 'keyup', function(event) {
        this.handleKeypress(event);
      });

      this.addListener(this.$container, 'focusout', function(event) {
        var newTarget = event.relatedTarget;
        var newTargetIsInsideDisclosure = this.$container.has(newTarget).length > 0;

        // If click target matches trigger element or disclosure child, do nothing
      if (newTarget === this.$trigger.get(0) || newTargetIsInsideDisclosure) {
          return;
        }

        this.hide();
      });
    },

    focusElement: function(direction) {
      var currentFocus = $(':focus');

      var focusable = this.$container.find(':focusable');

      var currentIndex = focusable.index(currentFocus);
      var newIndex;

      if (direction === 'prev') {
        newIndex = currentIndex - 1;
      } else {
        newIndex = currentIndex + 1;
      }

      if (newIndex >= 0 && newIndex < focusable.length) {
        var elementToFocus = focusable[newIndex];
        elementToFocus.focus();
      }
    },

    handleKeypress: function(event) {
      var keyCode = event.keyCode;

      switch (keyCode) {
        case Garnish.ESC_KEY:
          this.hide();
          this.$trigger.focus();
          break;
        case Garnish.RIGHT_KEY:
        case Garnish.DOWN_KEY:
          this.focusElement('next');
          break;
        case Garnish.LEFT_KEY:
        case Garnish.UP_KEY:
          this.focusElement('prev');
          break;
        default:
          break;
      }
    },

    isExpanded: function () {
      var isExpanded = this.$trigger.attr('aria-expanded');

      return isExpanded === 'true';
    },

    handleTriggerClick: function() {
      if (!this.isExpanded()) {
        this.show();
      } else {
        this.hide();
      }
    },

    show: function () {
      if (this.isExpanded()) {
        return;
      }

      this.setContainerPosition();
      this.addListener(
        Garnish.$scrollContainer,
        'scroll',
        'setContainerPosition'
      );

      this.$container.velocity('stop');
      this.$container.css({
        opacity: 1,
        display: 'block',
      });

      // Set ARIA attribute for expanded
      this.$trigger.attr('aria-expanded', 'true');

      // Focus first focusable element
      var firstFocusableEl = this.$container.find(':focusable')[0];
      if (firstFocusableEl) {
        firstFocusableEl.focus();
      } else {
        this.$container.attr('tabindex', '-1');
        this.$container.focus();
      }
    },

    hide: function () {
      if (!this.isExpanded()) {
        return;
      }

      this.$container.velocity(
        'fadeOut',
        { duration: Garnish.FX_DURATION }
      );

      this.$trigger.attr('aria-expanded', 'false');
    },

    setContainerPosition: function () {
      this._windowWidth = Garnish.$win.width();
      this._windowHeight = Garnish.$win.height();
      this._windowScrollLeft = Garnish.$win.scrollLeft();
      this._windowScrollTop = Garnish.$win.scrollTop();

      this._alignmentElementOffset = this.$alignmentElement[0].getBoundingClientRect();

      this._wrapperElementOffset = this.$wrapper[0].getBoundingClientRect();

      this._triggerWidth = this.$trigger.outerWidth();

      this.$container.css('minWidth', 0);
      this.$container.css(
        'minWidth',
        this._triggerWidth -
          (this.$container.outerWidth() - this.$container.width())
      );

      this._menuWidth = this.$container.outerWidth();
      this._menuHeight = this.$container.outerHeight();

      // Is there room for the menu below the trigger?
      var topClearance = this._alignmentElementOffset.top,
        bottomClearance = this._windowHeight - this._alignmentElementOffset.bottom;

      // Find top/bottom offset relative to wrapper element
      var topAdjustment = this._alignmentElementOffset.top - this._wrapperElementOffset.top;
      var bottomAdjustment = this._alignmentElementOffset.bottom - this._wrapperElementOffset.bottom;

      var bottomClearanceExists =
        bottomClearance >= this._menuHeight ||
        (topClearance < this._menuHeight && bottomClearance >= topClearance);

      if (bottomClearanceExists) {
        this.$container.css({
          top: 'calc(100% + ' + bottomAdjustment + 'px)',
          bottom: 'unset',
          maxHeight: bottomClearance - this.settings.windowSpacing,
        });
      } else {
        this.$container.css({
          bottom: 'calc(100% - ' + topAdjustment + 'px)',
          top: 'unset',
          maxHeight: topClearance - this.settings.windowSpacing,
        });
      }

      // Figure out how we're aliging it
      var align = this.$container.data('align');

      if (align !== 'left' && align !== 'center' && align !== 'right') {
        align = 'left';
      }

      if (align === 'center') {
        this._alignCenter();
      } else {
        // Figure out which options are actually possible
        var rightClearance =
            this._windowWidth +
            this._windowScrollLeft -
            (this._alignmentElementOffset.left + this._menuWidth),
          leftClearance = this._alignmentElementOffset.right - this._menuWidth;

        if ((align === 'right' && leftClearance >= 0) || rightClearance < 0) {
          this._alignRight();
        } else {
          this._alignLeft();
        }
      }

      delete this._windowWidth;
      delete this._windowHeight;
      delete this._windowScrollLeft;
      delete this._windowScrollTop;
      delete this._wrapperElementOffset;
      delete this._alignmentElementOffset;
      delete this._triggerWidth;
      delete this._triggerHeight;
      delete this._menuWidth;
      delete this._menuHeight;
    },

    _alignLeft: function () {
      var leftAdjustment = this._alignmentElementOffset.left - this._wrapperElementOffset.left;

      this.$container.css({
        right: 'unset',
        left: leftAdjustment + 'px',
      });
    },

    _alignRight: function () {
      var rightAdjustment = this._alignmentElementOffset.right - this._wrapperElementOffset.right;

      this.$container.css({
        left: 'unset',
        right: - rightAdjustment + 'px',
      });
    },

    _alignCenter: function () {
      var left = Math.round(this._triggerWidth / 2 - this._menuWidth / 2);
      var leftAdjustment = this._alignmentElementOffset.left - this._wrapperElementOffset.left;

      this.$container.css('left', left - leftAdjustment);
    },
  },
  {
    defaults: {
      windowSpacing: 5,
    },
  }
);
<|endoftext|>


<commit_before>/**
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */

import {
  GraphQLBoolean,
  GraphQLFloat,
  GraphQLID,
  GraphQLInt,
  GraphQLList,
  GraphQLNonNull,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} from 'graphql';

import {
  connectionArgs,
  connectionDefinitions,
  connectionFromArray,
  fromGlobalId,
  globalIdField,
  mutationWithClientMutationId,
  nodeDefinitions,
} from 'graphql-relay';

import {
  // Import methods that your schema can use to interact with your database
  User,
  Widget,
  getUser,
  getViewer,
  getWidget,
  getWidgets,
} from './database';

var fs = require('fs');

/**
 * We get the node interface and field from the Relay library.
 *
 * The first method defines the way we resolve an ID to its object.
 * The second defines the way we resolve an object to its GraphQL type.
 */
var {nodeInterface, nodeField} = nodeDefinitions(
  (globalId) => {
    var {type, id} = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    } else if (type === 'Widget') {
      return getWidget(id);
    } else {
      return null;
    }
  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    } else if (obj instanceof Widget)  {
      return widgetType;
    } else {
      return null;
    }
  }
);

/**
 * Define your own types here
 */

let getFiles = () => fs.readdirSync('public/files').map(path => ({url: path}))

var fileType = new GraphQLObjectType({
  name: 'File',
  description: 'An uploaded file',
  fields: () => ({
    id: globalIdField('File'),
    url: {
      type: GraphQLString,
    },
  }),
  interfaces: [nodeInterface],
})

var userType = new GraphQLObjectType({
  name: 'User',
  description: 'A person who uses our app',
  fields: () => ({
    id: globalIdField('User'),
    widgets: {
      type: widgetConnection,
      description: 'A person\'s collection of widgets',
      args: connectionArgs,
      resolve: (_, args) => connectionFromArray(getWidgets(), args),
    },
  }),
  interfaces: [nodeInterface],
});

var widgetType = new GraphQLObjectType({
  name: 'Widget',
  description: 'A shiny widget',
  fields: () => ({
    id: globalIdField('Widget'),
    name: {
      type: GraphQLString,
      description: 'The name of the widget',
    },
  }),
  interfaces: [nodeInterface],
});

/**
 * Define your own connection types here
 */
var {connectionType: widgetConnection} =
  connectionDefinitions({name: 'Widget', nodeType: widgetType});

/**
 * This is the type that will be the root of our query,
 * and the entry point into our schema.
 */
var queryType = new GraphQLObjectType({
  name: 'Query',
  fields: () => ({
    node: nodeField,
    // Add your own root fields here
    viewer: {
      type: userType,
      resolve: () => getViewer(),
    },
    files: {
      type: new GraphQLList(fileType),
      resolve: getFiles
    }
  }),
});

/**
 * This is the type that will be the root of our mutations,
 * and the entry point into performing writes in our schema.
 */
var mutationType = new GraphQLObjectType({
  name: 'Mutation',
  fields: () => ({
    // Add your own mutations here
  })
});

/**
 * Finally, we construct our schema (whose starting query type is the query
 * type we defined above) and export it.
 */
export var Schema = new GraphQLSchema({
  query: queryType,
  // Uncomment the following after adding some mutation fields:
  // mutation: mutationType
});
<commit_msg>file edges<commit_after>/**
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */

import {
  GraphQLBoolean,
  GraphQLFloat,
  GraphQLID,
  GraphQLInt,
  GraphQLList,
  GraphQLNonNull,
  GraphQLObjectType,
  GraphQLSchema,
  GraphQLString,
} from 'graphql';

import {
  connectionArgs,
  connectionDefinitions,
  connectionFromArray,
  fromGlobalId,
  globalIdField,
  mutationWithClientMutationId,
  nodeDefinitions,
} from 'graphql-relay';

import {
  // Import methods that your schema can use to interact with your database
  User,
  Widget,
  getUser,
  getViewer,
  getWidget,
  getWidgets,
} from './database';

var fs = require('fs');

/**
 * We get the node interface and field from the Relay library.
 *
 * The first method defines the way we resolve an ID to its object.
 * The second defines the way we resolve an object to its GraphQL type.
 */
var {nodeInterface, nodeField} = nodeDefinitions(
  (globalId) => {
    var {type, id} = fromGlobalId(globalId);
    if (type === 'User') {
      return getUser(id);
    } else if (type === 'Widget') {
      return getWidget(id);
    } else {
      return null;
    }
  },
  (obj) => {
    if (obj instanceof User) {
      return userType;
    } else if (obj instanceof Widget)  {
      return widgetType;
    } else {
      return null;
    }
  }
);

/**
 * Define your own types here
 */

let getFiles = () => fs.readdirSync('public/files').map(path => ({id: path, url: path}))

var fileType = new GraphQLObjectType({
  name: 'File',
  description: 'An uploaded file',
  fields: () => ({
    id: globalIdField('File'),
    url: {
      type: GraphQLString,
    },
  }),
  interfaces: [nodeInterface],
})

var userType = new GraphQLObjectType({
  name: 'User',
  description: 'A person who uses our app',
  fields: () => ({
    id: globalIdField('User'),
    widgets: {
      type: widgetConnection,
      description: 'A person\'s collection of widgets',
      args: connectionArgs,
      resolve: (_, args) => connectionFromArray(getWidgets(), args),
    },
  }),
  interfaces: [nodeInterface],
});

var widgetType = new GraphQLObjectType({
  name: 'Widget',
  description: 'A shiny widget',
  fields: () => ({
    id: globalIdField('Widget'),
    name: {
      type: GraphQLString,
      description: 'The name of the widget',
    },
  }),
  interfaces: [nodeInterface],
});

/**
 * Define your own connection types here
 */
var {connectionType: widgetConnection} =
  connectionDefinitions({name: 'Widget', nodeType: widgetType});

var {connectionType: fileConnection} =
  connectionDefinitions({name: 'File', nodeType: fileType});

/**
 * This is the type that will be the root of our query,
 * and the entry point into our schema.
 */
var queryType = new GraphQLObjectType({
  name: 'Query',
  fields: () => ({
    node: nodeField,
    // Add your own root fields here
    viewer: {
      type: userType,
      resolve: () => getViewer(),
    },
    files: {
      type: fileConnection,
      args: connectionArgs,
      resolve: (parent, args) => connectionFromArray(getFiles(), args)
    }
  }),
});

/**
 * This is the type that will be the root of our mutations,
 * and the entry point into performing writes in our schema.
 */
var mutationType = new GraphQLObjectType({
  name: 'Mutation',
  fields: () => ({
    // Add your own mutations here
  })
});

/**
 * Finally, we construct our schema (whose starting query type is the query
 * type we defined above) and export it.
 */
export var Schema = new GraphQLSchema({
  query: queryType,
  // Uncomment the following after adding some mutation fields:
  // mutation: mutationType
});
<|endoftext|>