<commit_before>angular.module('portal-filters', [])
	.filter('filter_name', function(){
		return function(text) {
			switch(text) {
				case 'q': return 'All Fields' ;break;
				case 'cq': return 'Advanced Query' ;break;
				case 'title': return 'Title' ;break;
				case 'identifier': return 'Identifier' ;break;
				case 'related_people': return 'Related People' ;break;
				case 'related_organisations': return 'Related Organisations' ;break;
				case 'description': return 'Description' ;break;
				case 'subject': return 'Subject' ;break;
				case 'access_rights': return 'Access'; break;
				case 'group': return 'Data Provider'; break;
				case 'license_class': return 'Licence'; break;
				case 'type': return 'Type'; break;
				case 'subject_vocab_uri': return 'Subject Vocabulary URI'; break;
				case 'anzsrc-for': return 'Subjects ANZSRC-FOR'; break;
				case 'anzsrc-seo': return 'Subjects ANZSRC-SEO'; break;
				case 'year_from': return 'Time Period (from)'; break;
				case 'year_to': return 'Time Period (to)'; break;
				case 'funding_scheme': return 'Funding Scheme'; break;
				case 'funding_from': return 'Funding From'; break;
				case 'funding_to': return 'Funding To'; break;
				case 'funders': return 'Funder'; break;
				case 'administering_institution': return 'Managing Institution'; break;
				case 'institution': return 'Institution'; break;
				case 'activity_status': return 'Status'; break;
				case 'researcher': return 'Researcher'; break;
				case 'related_party_one_id': return 'Related Researcher'; break;
				case 'scot': return 'Schools of Online Thesaurus'; break;
				case 'pont': return 'Powerhouse Museum Object Name Thesaurus'; break;
				case 'psychit': return 'Thesaurus of psychological index terms'; break;
				case 'anzsrc': return 'ANZSRC'; break;
				case 'apt': return 'Australian Pictorial Thesaurus'; break;
				case 'gcmd': return 'GCMD Keyword'; break;
				case 'iso639-3': return 'iso639-3 Language'; break;
				case 'lcsh': return 'LCSH'; break;
				case 'keywords': return 'Keyword'; break;
				case 'refine': return 'Keyword'; break;
				case 'subject_value_resolved': return 'Subject'; break;
				case 'commencement_to': return 'Commencement To'; break;
				case 'commencement_from': return 'Commencement From'; break;
				case 'completion_to': return 'Completion To'; break;
				case 'completion_from': return 'Completion From'; break;
				case 'spatial': return 'Location'; break;
				case 'access_methods_ss': return 'Access Method'; break;
				default: return text;
			}
		}
	})
	.filter('highlightreadable', function() {
		return function(text) {
			switch(text) {

				case 'identifier_value_search' : return 'Identifier' ; break;
				// case 'access' : return 'Access Details' ; break;
				case 'related_party_one_search' : return 'Related People' ; break;
				case 'related_party_multi_search' : return 'Related Organisations' ; break;
				case 'group_search' : return 'Data Provider' ; break;
				case 'related_info_search' : return 'Related Data' ; break;
				case 'related_activity_search' : return 'Related Project or Grant' ; break;
				case 'related_service_search' : return 'Related Tool or Service' ; break;
				case 'related_info_search' : return 'Related Resource' ; break;
				case 'subject_value_resolved_search' : return 'Subject' ; break;
				case 'description_value' : return 'Description' ; break;
				case 'date_to' : return 'Dates' ; break;
				case 'date_to' : return 'Dates' ; break;
				case 'date_from' : return 'Coverage' ; break;
				case 'citation_info_search' : return 'Citation ' ; break;
				default : return text;
			}
		}
	})
	.filter('socialreadable', function(){
		return function(text) {
			switch(text) {
				case 'AUTHENTICATION_SOCIAL_FACEBOOK' : return 'Facebook'; break;
				case 'AUTHENTICATION_SOCIAL_TWITTER' : return 'Twitter'; break;
				case 'AUTHENTICATION_SOCIAL_GOOGLE' : return 'Google'; break;
				case 'AUTHENTICATION_SOCIAL_LINKEDIN' : return 'LinkedIn'; break;
			}
		}
	})
	.filter('filter_value', function($sce){
		return function(text) {
			if (angular.isArray(text)) {
				var html = '
';
				angular.forEach(text, function(content) {
					html+='
'+content+'
';
				});
				html+='
';
				return $sce.trustAsHtml(html);
			} else {
				return $sce.trustAsHtml(text);
			}
		}
	})
	.filter('toTitleCase', function($log){
		return function(str){
			return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
		}
	})
	.filter('formatFacet', function () {
		return function (str) {
			switch (str) {
				case 'OGC:WFS': case 'ogc:wfs': return 'OGC Web Feature Service'; break;
				case 'OGC:WMS': case 'ogc:wms': return 'OGC Web Map Service'; break;
				case 'OGC:WCS': case 'ogc:wcs': return 'OGC Web Coverage Service'; break;
                case 'OGC:WPS': case 'ogc:wps': return 'OGC Web Processing Service'; break;
                case 'landingPage': return 'Landing Page'; break;
				case 'directDownload': return 'Direct Download'; break;
				case 'GeoServer': return 'GeoServer'; break;
				case 'THREDDS': case 'thredds': return 'THREDDS'; break;
                case 'THREDDS:WCS': case 'thredds:wcs': return 'THREDDS Web Coverage Service'; break;
                case 'THREDDS:WMS': case 'thredds:wms':return 'THREDDS Web Map Service'; break;
                case 'THREDDS:OPeNDAP': case 'thredds:opendap':return 'THREDDS OPeNDAP'; break;
                case 'contactCustodian': return 'Contact Custodian'; break;
				default:
					return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
					break;
			}
		}
	})
	.filter('getLabelFor', function($log){
		return function(value, filter) {
			var ret = '';
			angular.forEach(filter, function(f){
				if(f.value==value) {
					ret = f.label;
				}
			});
			return ret;
		}
	})
	.filter('truncate', function () {
		return function (text, length, end) {
			if(text){
				if (isNaN(length))
					length = 10;
				if (end === undefined)
					end = "...";
				if (text.length <= length || text.length - end.length <= length) {
					return text;
				}
				else {
					return String(text).substring(0, length-end.length) + end;
				}
			}
		};
	})
	.filter('text', ['$sce', function($sce){
		return function(text){
			var tmp = document.createElement("DIV");
			tmp.innerHTML = text;
			return tmp.textContent || tmp.innerText || "";
			// var decoded = $('
').html(text).text();
			// return decoded;
		}
	}])
	.filter('extractSentence', function($log){
		return function(text) {
            var sentences = text.split(/(.*?(?:\.|\?|!))(?: |$)/g);
			if (sentences) {
                if(sentences.length>0){
                        for(i=0;i<sentences.length;i++){
                            if(sentences[i].indexOf("<b&gt")>-1) {

                                var first = sentences[i].trim().charAt(0);
                                var last = sentences[i].trim().slice(-1);
                                if (first === first.toLowerCase() && first !== first.toUpperCase())
                                {
                                    // first character is a lowercase letter
                                    sentences[i] =  "..."+sentences[i];
                                }
                                if(last!=".")
                                {
                                    sentences[i] = sentences[i]+"...";
                                }

                                return sentences[i];}

                    }

                }
                var first = sentences[0].trim().charAt(0);
                var last = sentences[0].trim().slice(-1);
                if (first === first.toLowerCase() && first !== first.toUpperCase())
                {
                    // first character is a lowercase letter
                    sentences[0] =  "..."+sentences[0];
                }
                if(last!=".")
                {
                    sentences[0] = sentences[0]+"...";
                }
                return sentences[0]
			} else {
                var first = text.trim().charAt(0);
                var last = text.trim().slice(-1);
                if (first === first.toLowerCase() && first !== first.toUpperCase())
                {
                    // first character is a lowercase letter
                    text =  "..."+text;
                }
                if(last!=".")
                {
                    text = text+"...";
                }
				return text;
			}
		}
	})
	.filter('trustAsHtml', ['$sce', function($sce){
		return function(text){
			var decoded = $('
').html(text).text();
			return $sce.trustAsHtml(decoded);
		}
	}])
	.filter("timeago", function () {
	    //time: the time
	    //local: compared to what time? default: now
	    //raw: wheter you want in a format of "5 minutes ago", or "5 minutes"
	    return function (time, local, raw) {
	        if (!time) return "never";

	        if (!local) {
	            (local = Date.now())
	        }

	        if (angular.isDate(time)) {
	            time = time.getTime();
	        } else if (typeof time === "string") {
	        	var s = time;
				var bits = s.split(/\D/);
				var date = new Date(bits[0], --bits[1], bits[2], bits[3], bits[4]);
				time = date.getTime();
	        }

	        if (angular.isDate(local)) {
	            local = local.getTime();
	        }else if (typeof local === "string") {
	            local = new Date(local).getTime();
	        }

	        // console.log(local, time);

	        if (typeof time !== 'number' || typeof local !== 'number' || isNaN(time) || isNaN(local)) {
	            return;
	        }

	        var
	            offset = Math.abs((local - time) / 1000),
	            span = [],
	            MINUTE = 60,
	            HOUR = 3600,
	            DAY = 86400,
	            WEEK = 604800,
	            MONTH = 2629744,
	            YEAR = 31556926,
	            DECADE = 315569260;

	        if (offset <= MINUTE)              span = [ '', raw ? 'now' : parseInt(offset) + ' seconds' ];
	        else if (offset < (MINUTE * 60))   span = [ Math.round(Math.abs(offset / MINUTE)), 'min' ];
	        else if (offset < (HOUR * 24))     span = [ Math.round(Math.abs(offset / HOUR)), 'hr' ];
	        else if (offset < (DAY * 7))       span = [ Math.round(Math.abs(offset / DAY)), 'day' ];
	        else if (offset < (WEEK * 52))     span = [ Math.round(Math.abs(offset / WEEK)), 'week' ];
	        else if (offset < (YEAR * 10))     span = [ Math.round(Math.abs(offset / YEAR)), 'year' ];
	        else if (offset < (DECADE * 100))  span = [ Math.round(Math.abs(offset / DECADE)), 'decade' ];
	        else if (isNaN(offset))			   span = [''];
	        else                               span = [ '', 'a long time' ];

	        span[1] += (span[0] === 0 || span[0] > 1) ? 's' : '';
	        span = span.join(' ');

	        if (raw === true) {
	            return span;
	        }
	        return (time <= local && !isNaN(time)) ? span + ' ago' : 'in ' + span;
	    }
	})
	.filter('orderObjectBy', function($log) {
	  return function(items, field, reverse) {
	    var filtered = [];
	    angular.forEach(items, function(item) {
	      filtered.push(item);
	    });
	    filtered.sort(function (a, b) {
	    	var asort = (typeof(a[field])=='string' ? a[field].toLowerCase() : a[field]);
	    	var bsort = (typeof(b[field])=='string' ? b[field].toLowerCase() : b[field]);
	    	return (asort > bsort ? 1 : -1);
	    });
	    if(reverse) filtered.reverse();
	    return filtered;
	  };

}).filter('sortObjectBy', function($log) {
    return function(items, field, reverse) {
        var sortArray = ['open','conditional','restricted','open licence','non-commercial licence','non-derivative licence','restrictive licence','no licence','other','unknown']
        var filtered = [];
        sortArray.forEach(function(element){
            angular.forEach(items, function(item) {
                if(item.name==element){
                filtered.push(item);
                }
            });
        });
        return filtered;
    };

})

;

;<commit_msg>WMTS added again<commit_after>angular.module('portal-filters', [])
	.filter('filter_name', function(){
		return function(text) {
			switch(text) {
				case 'q': return 'All Fields' ;break;
				case 'cq': return 'Advanced Query' ;break;
				case 'title': return 'Title' ;break;
				case 'identifier': return 'Identifier' ;break;
				case 'related_people': return 'Related People' ;break;
				case 'related_organisations': return 'Related Organisations' ;break;
				case 'description': return 'Description' ;break;
				case 'subject': return 'Subject' ;break;
				case 'access_rights': return 'Access'; break;
				case 'group': return 'Data Provider'; break;
				case 'license_class': return 'Licence'; break;
				case 'type': return 'Type'; break;
				case 'subject_vocab_uri': return 'Subject Vocabulary URI'; break;
				case 'anzsrc-for': return 'Subjects ANZSRC-FOR'; break;
				case 'anzsrc-seo': return 'Subjects ANZSRC-SEO'; break;
				case 'year_from': return 'Time Period (from)'; break;
				case 'year_to': return 'Time Period (to)'; break;
				case 'funding_scheme': return 'Funding Scheme'; break;
				case 'funding_from': return 'Funding From'; break;
				case 'funding_to': return 'Funding To'; break;
				case 'funders': return 'Funder'; break;
				case 'administering_institution': return 'Managing Institution'; break;
				case 'institution': return 'Institution'; break;
				case 'activity_status': return 'Status'; break;
				case 'researcher': return 'Researcher'; break;
				case 'related_party_one_id': return 'Related Researcher'; break;
				case 'scot': return 'Schools of Online Thesaurus'; break;
				case 'pont': return 'Powerhouse Museum Object Name Thesaurus'; break;
				case 'psychit': return 'Thesaurus of psychological index terms'; break;
				case 'anzsrc': return 'ANZSRC'; break;
				case 'apt': return 'Australian Pictorial Thesaurus'; break;
				case 'gcmd': return 'GCMD Keyword'; break;
				case 'iso639-3': return 'iso639-3 Language'; break;
				case 'lcsh': return 'LCSH'; break;
				case 'keywords': return 'Keyword'; break;
				case 'refine': return 'Keyword'; break;
				case 'subject_value_resolved': return 'Subject'; break;
				case 'commencement_to': return 'Commencement To'; break;
				case 'commencement_from': return 'Commencement From'; break;
				case 'completion_to': return 'Completion To'; break;
				case 'completion_from': return 'Completion From'; break;
				case 'spatial': return 'Location'; break;
				case 'access_methods_ss': return 'Access Method'; break;
				default: return text;
			}
		}
	})
	.filter('highlightreadable', function() {
		return function(text) {
			switch(text) {

				case 'identifier_value_search' : return 'Identifier' ; break;
				// case 'access' : return 'Access Details' ; break;
				case 'related_party_one_search' : return 'Related People' ; break;
				case 'related_party_multi_search' : return 'Related Organisations' ; break;
				case 'group_search' : return 'Data Provider' ; break;
				case 'related_info_search' : return 'Related Data' ; break;
				case 'related_activity_search' : return 'Related Project or Grant' ; break;
				case 'related_service_search' : return 'Related Tool or Service' ; break;
				case 'related_info_search' : return 'Related Resource' ; break;
				case 'subject_value_resolved_search' : return 'Subject' ; break;
				case 'description_value' : return 'Description' ; break;
				case 'date_to' : return 'Dates' ; break;
				case 'date_to' : return 'Dates' ; break;
				case 'date_from' : return 'Coverage' ; break;
				case 'citation_info_search' : return 'Citation ' ; break;
				default : return text;
			}
		}
	})
	.filter('socialreadable', function(){
		return function(text) {
			switch(text) {
				case 'AUTHENTICATION_SOCIAL_FACEBOOK' : return 'Facebook'; break;
				case 'AUTHENTICATION_SOCIAL_TWITTER' : return 'Twitter'; break;
				case 'AUTHENTICATION_SOCIAL_GOOGLE' : return 'Google'; break;
				case 'AUTHENTICATION_SOCIAL_LINKEDIN' : return 'LinkedIn'; break;
			}
		}
	})
	.filter('filter_value', function($sce){
		return function(text) {
			if (angular.isArray(text)) {
				var html = '
';
				angular.forEach(text, function(content) {
					html+='
'+content+'
';
				});
				html+='
';
				return $sce.trustAsHtml(html);
			} else {
				return $sce.trustAsHtml(text);
			}
		}
	})
	.filter('toTitleCase', function($log){
		return function(str){
			return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
		}
	})
	.filter('formatFacet', function () {
		return function (str) {
			switch (str) {
				case 'OGC:WMTS': case 'ogc:wmts': return 'OGC Web Map Tile Service'; break;
				case 'OGC:WFS': case 'ogc:wfs': return 'OGC Web Feature Service'; break;
				case 'OGC:WMS': case 'ogc:wms': return 'OGC Web Map Service'; break;
				case 'OGC:WCS': case 'ogc:wcs': return 'OGC Web Coverage Service'; break;
                case 'OGC:WPS': case 'ogc:wps': return 'OGC Web Processing Service'; break;
                case 'landingPage': return 'Landing Page'; break;
				case 'directDownload': return 'Direct Download'; break;
				case 'GeoServer': return 'GeoServer'; break;
				case 'THREDDS': case 'thredds': return 'THREDDS'; break;
                case 'THREDDS:WCS': case 'thredds:wcs': return 'THREDDS Web Coverage Service'; break;
                case 'THREDDS:WMS': case 'thredds:wms':return 'THREDDS Web Map Service'; break;
                case 'THREDDS:OPeNDAP': case 'thredds:opendap':return 'THREDDS OPeNDAP'; break;
                case 'contactCustodian': return 'Contact Custodian'; break;
				default:
					return str.replace(/\w\S*/g, function(txt){return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();});
					break;
			}
		}
	})
	.filter('getLabelFor', function($log){
		return function(value, filter) {
			var ret = '';
			angular.forEach(filter, function(f){
				if(f.value==value) {
					ret = f.label;
				}
			});
			return ret;
		}
	})
	.filter('truncate', function () {
		return function (text, length, end) {
			if(text){
				if (isNaN(length))
					length = 10;
				if (end === undefined)
					end = "...";
				if (text.length <= length || text.length - end.length <= length) {
					return text;
				}
				else {
					return String(text).substring(0, length-end.length) + end;
				}
			}
		};
	})
	.filter('text', ['$sce', function($sce){
		return function(text){
			var tmp = document.createElement("DIV");
			tmp.innerHTML = text;
			return tmp.textContent || tmp.innerText || "";
			// var decoded = $('
').html(text).text();
			// return decoded;
		}
	}])
	.filter('extractSentence', function($log){
		return function(text) {
            var sentences = text.split(/(.*?(?:\.|\?|!))(?: |$)/g);
			if (sentences) {
                if(sentences.length>0){
                        for(i=0;i<sentences.length;i++){
                            if(sentences[i].indexOf("<b&gt")>-1) {

                                var first = sentences[i].trim().charAt(0);
                                var last = sentences[i].trim().slice(-1);
                                if (first === first.toLowerCase() && first !== first.toUpperCase())
                                {
                                    // first character is a lowercase letter
                                    sentences[i] =  "..."+sentences[i];
                                }
                                if(last!=".")
                                {
                                    sentences[i] = sentences[i]+"...";
                                }

                                return sentences[i];}

                    }

                }
                var first = sentences[0].trim().charAt(0);
                var last = sentences[0].trim().slice(-1);
                if (first === first.toLowerCase() && first !== first.toUpperCase())
                {
                    // first character is a lowercase letter
                    sentences[0] =  "..."+sentences[0];
                }
                if(last!=".")
                {
                    sentences[0] = sentences[0]+"...";
                }
                return sentences[0]
			} else {
                var first = text.trim().charAt(0);
                var last = text.trim().slice(-1);
                if (first === first.toLowerCase() && first !== first.toUpperCase())
                {
                    // first character is a lowercase letter
                    text =  "..."+text;
                }
                if(last!=".")
                {
                    text = text+"...";
                }
				return text;
			}
		}
	})
	.filter('trustAsHtml', ['$sce', function($sce){
		return function(text){
			var decoded = $('
').html(text).text();
			return $sce.trustAsHtml(decoded);
		}
	}])
	.filter("timeago", function () {
	    //time: the time
	    //local: compared to what time? default: now
	    //raw: wheter you want in a format of "5 minutes ago", or "5 minutes"
	    return function (time, local, raw) {
	        if (!time) return "never";

	        if (!local) {
	            (local = Date.now())
	        }

	        if (angular.isDate(time)) {
	            time = time.getTime();
	        } else if (typeof time === "string") {
	        	var s = time;
				var bits = s.split(/\D/);
				var date = new Date(bits[0], --bits[1], bits[2], bits[3], bits[4]);
				time = date.getTime();
	        }

	        if (angular.isDate(local)) {
	            local = local.getTime();
	        }else if (typeof local === "string") {
	            local = new Date(local).getTime();
	        }

	        // console.log(local, time);

	        if (typeof time !== 'number' || typeof local !== 'number' || isNaN(time) || isNaN(local)) {
	            return;
	        }

	        var
	            offset = Math.abs((local - time) / 1000),
	            span = [],
	            MINUTE = 60,
	            HOUR = 3600,
	            DAY = 86400,
	            WEEK = 604800,
	            MONTH = 2629744,
	            YEAR = 31556926,
	            DECADE = 315569260;

	        if (offset <= MINUTE)              span = [ '', raw ? 'now' : parseInt(offset) + ' seconds' ];
	        else if (offset < (MINUTE * 60))   span = [ Math.round(Math.abs(offset / MINUTE)), 'min' ];
	        else if (offset < (HOUR * 24))     span = [ Math.round(Math.abs(offset / HOUR)), 'hr' ];
	        else if (offset < (DAY * 7))       span = [ Math.round(Math.abs(offset / DAY)), 'day' ];
	        else if (offset < (WEEK * 52))     span = [ Math.round(Math.abs(offset / WEEK)), 'week' ];
	        else if (offset < (YEAR * 10))     span = [ Math.round(Math.abs(offset / YEAR)), 'year' ];
	        else if (offset < (DECADE * 100))  span = [ Math.round(Math.abs(offset / DECADE)), 'decade' ];
	        else if (isNaN(offset))			   span = [''];
	        else                               span = [ '', 'a long time' ];

	        span[1] += (span[0] === 0 || span[0] > 1) ? 's' : '';
	        span = span.join(' ');

	        if (raw === true) {
	            return span;
	        }
	        return (time <= local && !isNaN(time)) ? span + ' ago' : 'in ' + span;
	    }
	})
	.filter('orderObjectBy', function($log) {
	  return function(items, field, reverse) {
	    var filtered = [];
	    angular.forEach(items, function(item) {
	      filtered.push(item);
	    });
	    filtered.sort(function (a, b) {
	    	var asort = (typeof(a[field])=='string' ? a[field].toLowerCase() : a[field]);
	    	var bsort = (typeof(b[field])=='string' ? b[field].toLowerCase() : b[field]);
	    	return (asort > bsort ? 1 : -1);
	    });
	    if(reverse) filtered.reverse();
	    return filtered;
	  };

}).filter('sortObjectBy', function($log) {
    return function(items, field, reverse) {
        var sortArray = ['open','conditional','restricted','open licence','non-commercial licence','non-derivative licence','restrictive licence','no licence','other','unknown']
        var filtered = [];
        sortArray.forEach(function(element){
            angular.forEach(items, function(item) {
                if(item.name==element){
                filtered.push(item);
                }
            });
        });
        return filtered;
    };

})

;

;<|endoftext|>


<commit_before>'use strict';

var chalk = require('chalk'),
    fs = require('graceful-fs'),
    path = require('path'),
    Q = require('q'),
    utils = require('./utils');

/**
 * Gets local content collection file
 * @author Steven Britton
 * @date   2016-04-12
 * @param  {String}   sitemapFile Sitemap file name
 * @param  {Function} callback    callback
 * @return {Function}             callback
 */
function getLocalFile(localFile, callback) {
    fs.readFile(localFile, function(err, data) {
        return callback(err, data);
    });
}

/**
 * Website Object
 * @author Steven Britton
 * @date   2016-04-14
 * @param  {Object}  options [description]
 */
function Website(parameters) {

    utils.log.verbose('Website: constructor', parameters);

    this.options = parameters;

    this.contentCollection = {
        pages: []
    };

    this.contentFile = 'content-collection.json';
    this.uri = this.options || null;

}

Website.prototype.get = function() {

    console.log(chalk.yellow.bold(' ⤷ Gathering Website Information'));

    var deferred = Q.defer(),
        error = [];

    getLocalFile(this.contentFile, function(err, data) {

        if (err) {
            utils.q.throwError(deferred, err);
        }

        console.log(JSON.parse(data));

        deferred.resolve(data);
    });

    return deferred.promise;
};

module.exports = Website;
<commit_msg>polishing website module<commit_after>'use strict';

var chalk = require('chalk'),
    fs = require('graceful-fs'),
    path = require('path'),
    Q = require('q'),
    utils = require('./utils');

/**
 * Gets local content collection file
 * @author Steven Britton
 * @date   2016-04-12
 * @param  {String}   sitemapFile Sitemap file name
 * @param  {Function} callback    callback
 * @return {Function}             callback
 */
function getLocalFile(localFile, callback) {
    fs.readFile(localFile, function(err, data) {
        return callback(err, data);
    });
}

/**
 * Website Object
 * @author Steven Britton
 * @date   2016-04-14
 * @param  {Object}  options [description]
 */
function Website(parameters) {

    utils.log.verbose('Website: constructor', parameters);

    this.options = parameters;

    this.contentCollection = {
        pages: []
    };

    this.contentFile = 'content-collection.json';
    this.uri = this.options || null;

}

Website.prototype.get = function() {

    console.log(chalk.yellow.bold(' ⤷ Gathering Website Information'));

    var deferred = Q.defer(),
        website = this;

    getLocalFile(this.contentFile, function(err, data) {

        if (err) {
            utils.q.throwError(deferred, err);
        }

        website.contentCollection = JSON.parse(data);

        deferred.resolve(data);
    });

    return deferred.promise;
};

module.exports = Website;
<|endoftext|>


<commit_before>// Feature-detect XMLHttpRequest implementation
// More robust detecting of ActiveX implementations
(function(){
  var xhr;
    if (window.XMLHttpRequest) {
      xhr = new XMLHttpRequest();
      alert("Supports newer XHR implementations");
    } else {
      try {
        xhr = new ActiveXObject("Msxml2.XMLHTTP");
        alert("Supports one version of ActiveX");
      } catch (e) {
        try {
          xhr = new ActiveXObject("Microsoft.XMLHTTP");
          alert("Supports another version of ActiveX");
        } catch (e) {
          xhr = false;
          alert("Sorry...xhr is not supported");
        }
      }
    }
  return xhr;
})();
<commit_msg>change alerts, add whitespace, update comments<commit_after>// Feature-detect XMLHttpRequest implementation
// More robust detecting of ActiveX implementations
function getXHR() {
  var xhr;
  if (window.XMLHttpRequest) {
    xhr = new XMLHttpRequest();
    alert("Supports newer XHR implementations");
  } else {
    try {
      xhr = new ActiveXObject("Msxml2.XMLHTTP");
      alert("Supports one version of ActiveX");
    } catch (e) {
      try {
        xhr = new ActiveXObject("Microsoft.XMLHTTP");
        alert("Supports another version of ActiveX");
      } catch (e) {
        xhr = false;
        alert("Sorry...this browser doesn't support XMLHttpRequest");
      }
    }
  }
  return xhr;
}
<|endoftext|>


<commit_before>import React, { Component } from 'react';

class CardPicker extends Component {
    render() {
        return
Hello

    }
}

export default CardPicker;<commit_msg>Base form structure<commit_after>import React, { Component } from 'react';

class CardPicker extends Component {
    render() {
        return (
            <form className="card-picker">

Please enter your card title

                <input type="text" placeholder="Card Name" required />
                <button type="submit">View Card</button>
            </form>
        )
    }
}

export default CardPicker;<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { noop } from 'lodash';
import Suggestions from './Suggestions';
import PropTypes from 'prop-types';
import Tag from './Tag';

//Constants
import { KEYS, DEFAULT_PLACEHOLDER, DEFAULT_CLASSNAMES } from './constants';

class ReactTags extends Component {
  constructor(props) {
    super(props);

    this.state = {
      suggestions: this.props.suggestions,
      query: '',
      isFocused: false,
      selectedIndex: -1,
      selectionMode: false,
    };

    this.handleFocus = this.handleFocus.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.moveTag = this.moveTag.bind(this);
    this.handlePaste = this.handlePaste.bind(this);
    this.resetAndFocusInput = this.resetAndFocusInput.bind(this);
    this.handleSuggestionHover = this.handleSuggestionHover.bind(this);
    this.handleSuggestionClick = this.handleSuggestionClick.bind(this);
  }

  componentWillMount() {
    this.setState({
      classNames: { ...DEFAULT_CLASSNAMES, ...this.props.classNames },
    });
  }

  resetAndFocusInput() {
    this.setState({ query: '' });
    if (this.textInput) {
      this.textInput.value = '';
      this.textInput.focus();
    }
  }

  componentDidMount() {
    const { autofocus, readOnly } = this.props;
    if (autofocus && !readOnly) {
      this.resetAndFocusInput();
    }
  }

  filteredSuggestions(query, suggestions) {
    if (this.props.handleFilterSuggestions) {
      return this.props.handleFilterSuggestions(query, suggestions);
    }

    return suggestions.filter(function(item) {
      return item.text.toLowerCase().indexOf(query.toLowerCase()) === 0;
    });
  }

  componentWillReceiveProps(props) {
    const suggestions = this.filteredSuggestions(
      this.state.query,
      props.suggestions
    );
    this.setState({
      suggestions,
      classNames: { ...DEFAULT_CLASSNAMES, ...props.classNames },
    });
  }

  handleDelete(i, e) {
    this.props.handleDelete(i, e);
    if (!this.props.resetInputOnDelete) {
      this.textInput && this.textInput.focus();
    } else {
      this.resetAndFocusInput();
    }
    e.stopPropagation();
  }

  handleTagClick(i, e) {
    if (this.props.handleTagClick) {
      this.props.handleTagClick(i, e);
    }
    if (!this.props.resetInputOnDelete) {
      this.textInput && this.textInput.focus();
    } else {
      this.resetAndFocusInput();
    }
  }

  handleChange(e) {
    if (this.props.handleInputChange) {
      this.props.handleInputChange(e.target.value.trim());
    }

    const query = e.target.value.trim();
    const suggestions = this.filteredSuggestions(query, this.props.suggestions);

    const { selectedIndex } = this.state;

    this.setState({
      query: query,
      suggestions: suggestions,
      selectedIndex:
        selectedIndex >= suggestions.length
          ? suggestions.length - 1
          : selectedIndex,
    });
  }

  handleFocus(e) {
    const value = e.target.value.trim();
    if (this.props.handleInputFocus) {
      this.props.handleInputFocus(value);
    }
    this.setState({ isFocused: true });
  }

  handleBlur(e) {
    const value = e.target.value.trim();
    if (this.props.handleInputBlur) {
      this.props.handleInputBlur(value);
      if (this.textInput) {
        this.textInput.value = '';
      }
    }
    this.setState({ isFocused: false });
  }

  handleKeyDown(e) {
    const { query, selectedIndex, suggestions, selectionMode } = this.state;

    // hide suggestions menu on escape
    if (e.keyCode === KEYS.ESCAPE) {
      e.preventDefault();
      e.stopPropagation();
      this.setState({
        selectedIndex: -1,
        selectionMode: false,
        suggestions: [],
      });
    }

    // When one of the terminating keys is pressed, add current query to the tags.
    // If no text is typed in so far, ignore the action - so we don't end up with a terminating
    // character typed in.
    if (this.props.delimiters.indexOf(e.keyCode) !== -1 && !e.shiftKey) {
      if (e.keyCode !== KEYS.TAB || query !== '') {
        e.preventDefault();
      }

      const selectedQuery =
        selectionMode && selectedIndex !== -1
          ? suggestions[selectedIndex]
          : { id: query, text: query };

      if (selectedQuery !== '') {
        this.addTag(selectedQuery);
      }
    }

    // when backspace key is pressed and query is blank, delete tag
    if (
      e.keyCode === KEYS.BACKSPACE &&
      query == '' &&
      this.props.allowDeleteFromEmptyInput
    ) {
      this.handleDelete(this.props.tags.length - 1, e);
    }

    // up arrow
    if (e.keyCode === KEYS.UP_ARROW) {
      e.preventDefault();
      this.setState({
        selectedIndex:
          selectedIndex <= 0 ? suggestions.length - 1 : selectedIndex - 1,
        selectionMode: true,
      });
    }

    // down arrow
    if (e.keyCode === KEYS.DOWN_ARROW) {
      e.preventDefault();
      this.setState({
        selectedIndex:
          suggestions.length === 0
            ? -1
            : (selectedIndex + 1) % suggestions.length,
        selectionMode: true,
      });
    }
  }

  handlePaste(e) {
    if (!this.props.allowAdditionFromPaste) {
      return;
    }

    e.preventDefault();

    // See: http://stackoverflow.com/a/6969486/1463681
    const escapeRegex = (str) =>
      str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');

    // Used to determine how the pasted content is split.
    const delimiterChars = escapeRegex(
      this.props.delimiters
        .map((delimiter) => {
          // See: http://stackoverflow.com/a/34711175/1463681
          const chrCode = delimiter - 48 * Math.floor(delimiter / 48);
          return String.fromCharCode(96 <= delimiter ? chrCode : delimiter);
        })
        .join('')
    );

    const clipboardData = e.clipboardData || window.clipboardData;
    const string = clipboardData.getData('text');
    const regExp = new RegExp(`[${delimiterChars}]+`);
    string.split(regExp).forEach((tag) => this.props.handleAddition(tag));
  }

  addTag(tag) {
    if (!tag.id && !tag.text) {
      return;
    }
    const { tags } = this.props;
    const existingKeys = tags.map((tag) => tag.id.toLowerCase());
    // Return if tag has been already added
    if (existingKeys.indexOf(tag.id.toLowerCase()) >= 0) {
      return;
    }
    if (this.props.autocomplete) {
      const possibleMatches = this.filteredSuggestions(
        tag,
        this.props.suggestions
      );

      if (
        (this.props.autocomplete === 1 && possibleMatches.length === 1) ||
        (this.props.autocomplete === true && possibleMatches.length)
      ) {
        tag = possibleMatches[0];
      }
    }

    // call method to add
    this.props.handleAddition(tag);

    // reset the state
    this.setState({
      query: '',
      selectionMode: false,
      selectedIndex: -1,
    });

    this.resetAndFocusInput();
  }

  handleSuggestionClick(i, e) {
    this.addTag(this.state.suggestions[i]);
  }

  handleSuggestionHover(i, e) {
    this.setState({
      selectedIndex: i,
      selectionMode: true,
    });
  }

  moveTag(dragIndex, hoverIndex) {
    const tags = this.props.tags;

    // locate tags
    const dragTag = tags[dragIndex];

    // call handler with the index of the dragged tag
    // and the tag that is hovered
    this.props.handleDrag(dragTag, dragIndex, hoverIndex);
  }

  getTagItems = () => {
    const {
      tags,
      labelField,
      removeComponent,
      readOnly,
      handleDrag,
    } = this.props;
    const { classNames } = this.state;
    const moveTag = handleDrag ? this.moveTag : null;
    return tags.map((tag, index) => {
      return (
        <Tag
          key={tag.id}
          index={index}
          tag={tag}
          labelField={labelField}
          onDelete={this.handleDelete.bind(this, index)}
          moveTag={moveTag}
          removeComponent={removeComponent}
          onTagClicked={this.handleTagClick.bind(this, index)}
          readOnly={readOnly}
          classNames={classNames}
        />
      );
    });
  };

  render() {
    const moveTag = this.props.handleDrag ? this.moveTag : null;

    const tagItems = this.getTagItems();

    // get the suggestions for the given query
    const query = this.state.query.trim(),
      selectedIndex = this.state.selectedIndex,
      suggestions = this.state.suggestions,
      placeholder = this.props.placeholder,
      inputName = this.props.name,
      inputId = this.props.id,
      maxLength = this.props.maxLength;

    const tagInput = !this.props.readOnly ? (

        <input
          ref={(input) => {
            this.textInput = input;
          }}
          className={this.state.classNames.tagInputField}
          type="text"
          placeholder={placeholder}
          aria-label={placeholder}
          onFocus={this.handleFocus}
          onBlur={this.handleBlur}
          onChange={this.handleChange}
          onKeyDown={this.handleKeyDown}
          onPaste={this.handlePaste}
          name={inputName}
          id={inputId}
          maxLength={maxLength}
          value={this.props.inputValue}
        />

        <Suggestions
          query={query}
          suggestions={suggestions}
          selectedIndex={selectedIndex}
          handleClick={this.handleSuggestionClick}
          handleHover={this.handleSuggestionHover}
          minQueryLength={this.props.minQueryLength}
          shouldRenderSuggestions={this.props.shouldRenderSuggestions}
          isFocused={this.state.isFocused}
          classNames={this.state.classNames}
        />

    ) : null;

    return (

          {tagItems}
          {this.props.inline && tagInput}

        {!this.props.inline && tagInput}

    );
  }
}

ReactTags.propTypes = {
  placeholder: PropTypes.string,
  labelField: PropTypes.string,
  suggestions: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.string.isRequired,
    text: PropTypes.string.isRequired
  })),
  delimiters: PropTypes.array,
  autofocus: PropTypes.bool,
  inline: PropTypes.bool,
  handleDelete: PropTypes.func,
  handleAddition: PropTypes.func,
  handleDrag: PropTypes.func,
  handleFilterSuggestions: PropTypes.func,
  handleTagClick: PropTypes.func,
  allowDeleteFromEmptyInput: PropTypes.bool,
  allowAdditionFromPaste: PropTypes.bool,
  resetInputOnDelete: PropTypes.bool,
  handleInputChange: PropTypes.func,
  handleInputFocus: PropTypes.func,
  handleInputBlur: PropTypes.func,
  minQueryLength: PropTypes.number,
  shouldRenderSuggestions: PropTypes.func,
  removeComponent: PropTypes.func,
  autocomplete: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
  readOnly: PropTypes.bool,
  classNames: PropTypes.object,
  name: PropTypes.string,
  id: PropTypes.string,
  maxLength: PropTypes.string,
  inputValue: PropTypes.string,
  tags: PropTypes.arrayOf(PropTypes.shape({
    id: PropTypes.string.isRequired,
    text: PropTypes.any.isRequired
  }))
};

ReactTags.defaultProps = {
  placeholder: DEFAULT_PLACEHOLDER,
  suggestions: [],
  delimiters: [KEYS.ENTER, KEYS.TAB],
  autofocus: true,
  inline: true,
  handleDelete: noop,
  handleAddition: noop,
  allowDeleteFromEmptyInput: true,
  allowAdditionFromPaste: true,
  resetInputOnDelete: true,
  minQueryLength: 2,
  autocomplete: false,
  readOnly: false,
};

module.exports = {
  WithContext: DragDropContext(HTML5Backend)(ReactTags),
  WithOutContext: ReactTags,
  KEYS: KEYS,
};
<commit_msg>Move the props and default props into the class (#308)<commit_after>import React, { Component } from 'react';
import { DragDropContext } from 'react-dnd';
import HTML5Backend from 'react-dnd-html5-backend';
import { noop } from 'lodash';
import Suggestions from './Suggestions';
import PropTypes from 'prop-types';
import Tag from './Tag';

//Constants
import { KEYS, DEFAULT_PLACEHOLDER, DEFAULT_CLASSNAMES } from './constants';

class ReactTags extends Component {
  static propTypes = {
    placeholder: PropTypes.string,
    labelField: PropTypes.string,
    suggestions: PropTypes.arrayOf(PropTypes.shape({
      id: PropTypes.string.isRequired,
      text: PropTypes.string.isRequired
    })),
    delimiters: PropTypes.arrayOf(PropTypes.number),
    autofocus: PropTypes.bool,
    inline: PropTypes.bool,
    handleDelete: PropTypes.func,
    handleAddition: PropTypes.func,
    handleDrag: PropTypes.func,
    handleFilterSuggestions: PropTypes.func,
    handleTagClick: PropTypes.func,
    allowDeleteFromEmptyInput: PropTypes.bool,
    allowAdditionFromPaste: PropTypes.bool,
    resetInputOnDelete: PropTypes.bool,
    handleInputChange: PropTypes.func,
    handleInputFocus: PropTypes.func,
    handleInputBlur: PropTypes.func,
    minQueryLength: PropTypes.number,
    shouldRenderSuggestions: PropTypes.func,
    removeComponent: PropTypes.func,
    autocomplete: PropTypes.oneOfType([PropTypes.bool, PropTypes.number]),
    readOnly: PropTypes.bool,
    classNames: PropTypes.object,
    name: PropTypes.string,
    id: PropTypes.string,
    maxLength: PropTypes.string,
    inputValue: PropTypes.string,
    tags: PropTypes.arrayOf(PropTypes.shape({
      id: PropTypes.string.isRequired,
      text: PropTypes.any.isRequired
    }))
  };

  static defaultProps = {
    placeholder: DEFAULT_PLACEHOLDER,
    suggestions: [],
    delimiters: [KEYS.ENTER, KEYS.TAB],
    autofocus: true,
    inline: true,
    handleDelete: noop,
    handleAddition: noop,
    allowDeleteFromEmptyInput: true,
    allowAdditionFromPaste: true,
    resetInputOnDelete: true,
    minQueryLength: 2,
    autocomplete: false,
    readOnly: false,
  };

  constructor(props) {
    super(props);

    this.state = {
      suggestions: this.props.suggestions,
      query: '',
      isFocused: false,
      selectedIndex: -1,
      selectionMode: false,
    };

    this.handleFocus = this.handleFocus.bind(this);
    this.handleBlur = this.handleBlur.bind(this);
    this.handleKeyDown = this.handleKeyDown.bind(this);
    this.handleChange = this.handleChange.bind(this);
    this.moveTag = this.moveTag.bind(this);
    this.handlePaste = this.handlePaste.bind(this);
    this.resetAndFocusInput = this.resetAndFocusInput.bind(this);
    this.handleSuggestionHover = this.handleSuggestionHover.bind(this);
    this.handleSuggestionClick = this.handleSuggestionClick.bind(this);
  }

  componentWillMount() {
    this.setState({
      classNames: { ...DEFAULT_CLASSNAMES, ...this.props.classNames },
    });
  }

  resetAndFocusInput() {
    this.setState({ query: '' });
    if (this.textInput) {
      this.textInput.value = '';
      this.textInput.focus();
    }
  }

  componentDidMount() {
    const { autofocus, readOnly } = this.props;
    if (autofocus && !readOnly) {
      this.resetAndFocusInput();
    }
  }

  filteredSuggestions(query, suggestions) {
    if (this.props.handleFilterSuggestions) {
      return this.props.handleFilterSuggestions(query, suggestions);
    }

    return suggestions.filter(function(item) {
      return item.text.toLowerCase().indexOf(query.toLowerCase()) === 0;
    });
  }

  componentWillReceiveProps(props) {
    const suggestions = this.filteredSuggestions(
      this.state.query,
      props.suggestions
    );
    this.setState({
      suggestions,
      classNames: { ...DEFAULT_CLASSNAMES, ...props.classNames },
    });
  }

  handleDelete(i, e) {
    this.props.handleDelete(i, e);
    if (!this.props.resetInputOnDelete) {
      this.textInput && this.textInput.focus();
    } else {
      this.resetAndFocusInput();
    }
    e.stopPropagation();
  }

  handleTagClick(i, e) {
    if (this.props.handleTagClick) {
      this.props.handleTagClick(i, e);
    }
    if (!this.props.resetInputOnDelete) {
      this.textInput && this.textInput.focus();
    } else {
      this.resetAndFocusInput();
    }
  }

  handleChange(e) {
    if (this.props.handleInputChange) {
      this.props.handleInputChange(e.target.value.trim());
    }

    const query = e.target.value.trim();
    const suggestions = this.filteredSuggestions(query, this.props.suggestions);

    const { selectedIndex } = this.state;

    this.setState({
      query: query,
      suggestions: suggestions,
      selectedIndex:
        selectedIndex >= suggestions.length
          ? suggestions.length - 1
          : selectedIndex,
    });
  }

  handleFocus(e) {
    const value = e.target.value.trim();
    if (this.props.handleInputFocus) {
      this.props.handleInputFocus(value);
    }
    this.setState({ isFocused: true });
  }

  handleBlur(e) {
    const value = e.target.value.trim();
    if (this.props.handleInputBlur) {
      this.props.handleInputBlur(value);
      if (this.textInput) {
        this.textInput.value = '';
      }
    }
    this.setState({ isFocused: false });
  }

  handleKeyDown(e) {
    const { query, selectedIndex, suggestions, selectionMode } = this.state;

    // hide suggestions menu on escape
    if (e.keyCode === KEYS.ESCAPE) {
      e.preventDefault();
      e.stopPropagation();
      this.setState({
        selectedIndex: -1,
        selectionMode: false,
        suggestions: [],
      });
    }

    // When one of the terminating keys is pressed, add current query to the tags.
    // If no text is typed in so far, ignore the action - so we don't end up with a terminating
    // character typed in.
    if (this.props.delimiters.indexOf(e.keyCode) !== -1 && !e.shiftKey) {
      if (e.keyCode !== KEYS.TAB || query !== '') {
        e.preventDefault();
      }

      const selectedQuery =
        selectionMode && selectedIndex !== -1
          ? suggestions[selectedIndex]
          : { id: query, text: query };

      if (selectedQuery !== '') {
        this.addTag(selectedQuery);
      }
    }

    // when backspace key is pressed and query is blank, delete tag
    if (
      e.keyCode === KEYS.BACKSPACE &&
      query == '' &&
      this.props.allowDeleteFromEmptyInput
    ) {
      this.handleDelete(this.props.tags.length - 1, e);
    }

    // up arrow
    if (e.keyCode === KEYS.UP_ARROW) {
      e.preventDefault();
      this.setState({
        selectedIndex:
          selectedIndex <= 0 ? suggestions.length - 1 : selectedIndex - 1,
        selectionMode: true,
      });
    }

    // down arrow
    if (e.keyCode === KEYS.DOWN_ARROW) {
      e.preventDefault();
      this.setState({
        selectedIndex:
          suggestions.length === 0
            ? -1
            : (selectedIndex + 1) % suggestions.length,
        selectionMode: true,
      });
    }
  }

  handlePaste(e) {
    if (!this.props.allowAdditionFromPaste) {
      return;
    }

    e.preventDefault();

    // See: http://stackoverflow.com/a/6969486/1463681
    const escapeRegex = (str) =>
      str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&');

    // Used to determine how the pasted content is split.
    const delimiterChars = escapeRegex(
      this.props.delimiters
        .map((delimiter) => {
          // See: http://stackoverflow.com/a/34711175/1463681
          const chrCode = delimiter - 48 * Math.floor(delimiter / 48);
          return String.fromCharCode(96 <= delimiter ? chrCode : delimiter);
        })
        .join('')
    );

    const clipboardData = e.clipboardData || window.clipboardData;
    const string = clipboardData.getData('text');
    const regExp = new RegExp(`[${delimiterChars}]+`);
    string.split(regExp).forEach((tag) => this.props.handleAddition(tag));
  }

  addTag(tag) {
    if (!tag.id && !tag.text) {
      return;
    }
    const { tags } = this.props;
    const existingKeys = tags.map((tag) => tag.id.toLowerCase());
    // Return if tag has been already added
    if (existingKeys.indexOf(tag.id.toLowerCase()) >= 0) {
      return;
    }
    if (this.props.autocomplete) {
      const possibleMatches = this.filteredSuggestions(
        tag,
        this.props.suggestions
      );

      if (
        (this.props.autocomplete === 1 && possibleMatches.length === 1) ||
        (this.props.autocomplete === true && possibleMatches.length)
      ) {
        tag = possibleMatches[0];
      }
    }

    // call method to add
    this.props.handleAddition(tag);

    // reset the state
    this.setState({
      query: '',
      selectionMode: false,
      selectedIndex: -1,
    });

    this.resetAndFocusInput();
  }

  handleSuggestionClick(i, e) {
    this.addTag(this.state.suggestions[i]);
  }

  handleSuggestionHover(i, e) {
    this.setState({
      selectedIndex: i,
      selectionMode: true,
    });
  }

  moveTag(dragIndex, hoverIndex) {
    const tags = this.props.tags;

    // locate tags
    const dragTag = tags[dragIndex];

    // call handler with the index of the dragged tag
    // and the tag that is hovered
    this.props.handleDrag(dragTag, dragIndex, hoverIndex);
  }

  getTagItems = () => {
    const {
      tags,
      labelField,
      removeComponent,
      readOnly,
      handleDrag,
    } = this.props;
    const { classNames } = this.state;
    const moveTag = handleDrag ? this.moveTag : null;
    return tags.map((tag, index) => {
      return (
        <Tag
          key={tag.id}
          index={index}
          tag={tag}
          labelField={labelField}
          onDelete={this.handleDelete.bind(this, index)}
          moveTag={moveTag}
          removeComponent={removeComponent}
          onTagClicked={this.handleTagClick.bind(this, index)}
          readOnly={readOnly}
          classNames={classNames}
        />
      );
    });
  };

  render() {
    const moveTag = this.props.handleDrag ? this.moveTag : null;

    const tagItems = this.getTagItems();

    // get the suggestions for the given query
    const query = this.state.query.trim(),
      selectedIndex = this.state.selectedIndex,
      suggestions = this.state.suggestions,
      placeholder = this.props.placeholder,
      inputName = this.props.name,
      inputId = this.props.id,
      maxLength = this.props.maxLength;

    const tagInput = !this.props.readOnly ? (

        <input
          ref={(input) => {
            this.textInput = input;
          }}
          className={this.state.classNames.tagInputField}
          type="text"
          placeholder={placeholder}
          aria-label={placeholder}
          onFocus={this.handleFocus}
          onBlur={this.handleBlur}
          onChange={this.handleChange}
          onKeyDown={this.handleKeyDown}
          onPaste={this.handlePaste}
          name={inputName}
          id={inputId}
          maxLength={maxLength}
          value={this.props.inputValue}
        />

        <Suggestions
          query={query}
          suggestions={suggestions}
          selectedIndex={selectedIndex}
          handleClick={this.handleSuggestionClick}
          handleHover={this.handleSuggestionHover}
          minQueryLength={this.props.minQueryLength}
          shouldRenderSuggestions={this.props.shouldRenderSuggestions}
          isFocused={this.state.isFocused}
          classNames={this.state.classNames}
        />

    ) : null;

    return (

          {tagItems}
          {this.props.inline && tagInput}

        {!this.props.inline && tagInput}

    );
  }
}

module.exports = {
  WithContext: DragDropContext(HTML5Backend)(ReactTags),
  WithOutContext: ReactTags,
  KEYS: KEYS,
};
<|endoftext|>


<commit_before>const moment = require('moment');

const db = require('../orm.js');
const config = require('../../config');
const email = require('../email.js');
const log = require('../logging.js');
const updateAssociation = require('./util.js').updateAssociation;
const Op = db.Sequelize.Op;
const wrapper = require('../errors');
const feeFactory = require('../../shared/fee/feeFactory');

const bookings = {};

bookings.getUserBookings = (req, res) => {

    db.booking.findAll({
        where:
            {
                $or:
                    [{guestUUID: req.cookies.guestUUID},
                        {
                            $and:
                                [{userId: req.user.id},
                                    {userId: {$not: 1}}
                                ]
                        }]
            }, include: [{model: db.participant}]
    })
        .then(bookings => {
            let data = {bookings};
            res.json(data);
        });
};

const getUserScopes = (user, event) => {

    const scopes = [];

    if (user.roles.find(role => role.name === "admin") || user.id === event.userId) scopes.push({method: ['Limited', event.id, null, null, 'defaultScope', true]});

    user.roles.filter(r => r.eventId === event.id).forEach(r => {

        let participantScope = null;
        let includePayments = false;
        switch (r.name) {
            case "KP":
                participantScope = "KP";
                break;
            case "Money":
                participantScope = "Money";
                includePayments = true;
                break;
            default:
                participantScope = "defaultScope";
        }

        scopes.push({method: ['Limited', event.id, r.villageId, r.organisationId, participantScope, includePayments]})
    });

    return scopes;

};

bookings.getEventBookings = async function (req, res) {
    //need to loop over a users roles and assemble the data they are allowed to see
    event = await db.event.findOne({where: {id: {[Op.eq]: req.params.eventId}}});

    const scopes = getUserScopes(req.user, event);
    const results = await Promise.all(scopes.map(s => db.booking.scope(s).findAll()));

    const flat = results.reduce((a, b) => a.concat(b), []);

    res.json({bookings: flat});

};

bookings.getBooking = (req, res) => {
    db.booking.findOne({where: {id: req.params.bookingId}, include: [{model: db.participant}, {model: db.event}]})
        .then(booking => {
            let data = {};
            data.bookings = [booking];
            res.json(data);
        });
};

bookings.createBooking = (req, res) => {

    let newBooking = req.body;
    newBooking.guestUUID = req.cookies.guestUUID;
    newBooking.userId = newBooking.userId || req.user.id;
    newBooking.maxParticipants = newBooking.participants.length;

    db.booking.create(newBooking, {
        include: [{
            association: 'participants'
        }]
    }).then((booking) => {
        return db.booking.findOne({where: {id: booking.id}, include: [{model: db.participant}, {model: db.event}]})
    }).then(booking => {
        log.log("debug", "Created new booking id %s for %s", booking.id, booking.userName);
        let data = {};
        data.bookings = [booking];
        res.json(data);

        //send an e-mail
        const fees = feeFactory(booking.event);
        const emailData = booking.get({plain: true});
        emailData.editURL = config.BASE_PATH + '/' + (emailData.userId === 1 ? "guestUUID/" + emailData.eventId + "/" + emailData.guestUUID : "event/" + emailData.eventId + "/book");
        email(booking.userEmail, 'confirmation', emailData);
        return null;//Don't want the request to wait on e-amil promise
    }).catch(e => {
        console.log(e);
        res.status(500).end();
    });
};

/*
bookings.editBooking = (req, res) => {
    Booking.findOne({ where: { id: req.body.id } })
        .then(booking => {
            booking.userName = req.body.user.name;
            booking.userEmail = req.body.user.email;
            booking.userContact = req.body.user.phone;
            booking.paymentType = req.body.paymentType;
            booking.emergencyName = req.body.emergencyName;
            booking.emergencyPhone = req.body.emergencyPhone;
            booking.note = req.body.note;
            Participant.destroy({ where: { bookingId: req.body.id } })//delete previous partiticpants
                .then(() => Promise.all(
                    req.body.participants.map(p => {
                        p.bookingId = req.body.id;
                        return Participant.upsert(p); //insert new ones
                    })))
                .then(() => booking.save())
                .then(() => Booking.findOne({ where: { id: req.body.id }, include: [{ model: Participant }] }))
                .then((booking) => {
                    let data = {};
                    data[booking.id] = booking;
                    res.json(data);
                });
        });
}
*/

bookings.editBooking = (req, res) => {
    db.booking.findOne({where: {id: req.body.id}})
        .then(booking => {
            req.body.maxParticipants = Math.max(booking.maxParticipants, req.body.participants.length);
            return booking.update(req.body)//this ignores partitipants!
        })
        .then(booking => db.booking.findOne({where: {id: booking.id}, include: [{model: db.participant}]}))
        .then(booking => updateAssociation(booking, 'participants', db.participant, req.body.participants))
        .then(() => db.booking.findOne({where: {id: req.body.id}, include: [{model: db.participant}]}))
        .then(booking => {
            log.log("debug", "User %s Editing Booking id %s", req.user.userName, booking.id);
            let data = {};
            data.bookings = [booking];
            res.json(data);
        });
};

bookings.togglePaid = (req, res) => {
    db.booking.findOne({where: {id: req.body.id}, include: [{model: db.participant}]})
        .then(booking => {
            booking.paid = !booking.paid;
            return booking.save()
        })
        .then((booking) => {
            let data = {};
            data.bookings = [booking];
            res.json(data);
        });
};

bookings.deleteBooking = (req, res) => {
    db.booking.findOne({where: {id: req.body.id}})
        .then(booking => booking.destroy())
        .then(() => db.booking.findAll({
            where:
                {
                    $or:
                        [{guestUUID: req.cookies.guestUUID},
                            {
                                $and:
                                    [{userId: req.user.id},
                                        {userId: {$not: 1}}
                                    ]
                            }]
                }, include: [{model: db.participant}]
        }))
        .then(bookings => {
            let data = {bookings};
            res.json(data);
        });
};

bookings.assignVillage = async function (req, res) {
    booking = await db.booking.findOne({where: {id: req.body.bookingId}, include: [{model: db.participant}]});
    booking.villageId = req.body.villageId;
    await booking.save();
    const data = {};
    data.bookings = [booking];
    res.json(data);
};

bookings.addPayment = async function (req, res, next) {

    await db.payment.create(req.body);

    const booking = await db.booking.findOne({
        where: {id: {[Op.eq]: req.body.bookingId}},
        include: [{model: db.event}]
    }); //get the booking, but we can't send this as dangerous scope.

    const scopes = getUserScopes(req.user, booking.event);
    const results = await Promise.all(scopes.map(s => db.booking.scope(s).findOne({where: {id: booking.id}})));

    const flat = results.reduce((a, b) => a.concat(b), []);

    res.json({bookings: flat});
};

bookings.deletePayment = async function (req, res, next) {

    const payment = await db.payment.findOne({where: {id: {[Op.eq]: req.body.id}}});

    const booking = await db.booking.findOne({
        where: {id: {[Op.eq]: payment.bookingId}},
        include: [{model: db.event}]
    }); //get the booking, but we can't send this as dangerous scope.

    await payment.destroy();

    const scopes = getUserScopes(req.user, booking.event);
    const results = await Promise.all(scopes.map(s => db.booking.scope(s).findOne({where: {id: booking.id}})));

    const flat = results.reduce((a, b) => a.concat(b), []);

    res.json({bookings: flat});
};

/**
 *  Test function to update a paricipants updatedAt, disabled in production enviroments.
 *
 */

bookings.updateParticipantDate = async function (req, res) {

    const results = await db.sequelize.query('UPDATE participants SET "updatedAt" = $date WHERE id = $id',
        {
            bind: {id: req.params.participantId, date: moment(req.params.date).format('YYYY-MM-DD HH:mm:ss.SSS')},
            type: db.sequelize.QueryTypes.UPDATE
        });

    const paricipant = await db.participant.findOne({where: {id: req.params.participantId}});

    res.json(paricipant);

};

module.exports = wrapper(bookings);

<commit_msg>Fix syntax error<commit_after>const moment = require('moment');

const db = require('../orm.js');
const config = require('../../config');
const email = require('../email.js');
const log = require('../logging.js');
const updateAssociation = require('./util.js').updateAssociation;
const Op = db.Sequelize.Op;
const wrapper = require('../errors');
const feeFactory = require('../../shared/fee/feeFactory');

const bookings = {};

bookings.getUserBookings = (req, res) => {

    db.booking.findAll({
        where:
            {
                $or:
                    [{guestUUID: req.cookies.guestUUID},
                        {
                            $and:
                                [{userId: req.user.id},
                                    {userId: {$not: 1}}
                                ]
                        }]
            }, include: [{model: db.participant}]
    })
        .then(bookings => {
            let data = {bookings};
            res.json(data);
        });
};

const getUserScopes = (user, event) => {

    const scopes = [];

    if (user.roles.find(role => role.name === "admin") || user.id === event.userId) scopes.push({method: ['Limited', event.id, null, null, 'defaultScope', true]});

    user.roles.filter(r => r.eventId === event.id).forEach(r => {

        let participantScope = null;
        let includePayments = false;
        switch (r.name) {
            case "KP":
                participantScope = "KP";
                break;
            case "Money":
                participantScope = "Money";
                includePayments = true;
                break;
            default:
                participantScope = "defaultScope";
        }

        scopes.push({method: ['Limited', event.id, r.villageId, r.organisationId, participantScope, includePayments]})
    });

    return scopes;

};

bookings.getEventBookings = async function (req, res) {
    //need to loop over a users roles and assemble the data they are allowed to see
    const event = await db.event.findOne({where: {id: {[Op.eq]: req.params.eventId}}});

    const scopes = getUserScopes(req.user, event);
    const results = await Promise.all(scopes.map(s => db.booking.scope(s).findAll()));

    const flat = results.reduce((a, b) => a.concat(b), []);

    res.json({bookings: flat});

};

bookings.getBooking = (req, res) => {
    db.booking.findOne({where: {id: req.params.bookingId}, include: [{model: db.participant}, {model: db.event}]})
        .then(booking => {
            let data = {};
            data.bookings = [booking];
            res.json(data);
        });
};

bookings.createBooking = (req, res) => {

    let newBooking = req.body;
    newBooking.guestUUID = req.cookies.guestUUID;
    newBooking.userId = newBooking.userId || req.user.id;
    newBooking.maxParticipants = newBooking.participants.length;

    db.booking.create(newBooking, {
        include: [{
            association: 'participants'
        }]
    }).then((booking) => {
        return db.booking.findOne({where: {id: booking.id}, include: [{model: db.participant}, {model: db.event}]})
    }).then(booking => {
        log.log("debug", "Created new booking id %s for %s", booking.id, booking.userName);
        let data = {};
        data.bookings = [booking];
        res.json(data);

        //send an e-mail
        const fees = feeFactory(booking.event);
        const emailData = booking.get({plain: true});
        emailData.editURL = config.BASE_PATH + '/' + (emailData.userId === 1 ? "guestUUID/" + emailData.eventId + "/" + emailData.guestUUID : "event/" + emailData.eventId + "/book");
        email(booking.userEmail, 'confirmation', emailData);
        return null;//Don't want the request to wait on e-amil promise
    }).catch(e => {
        console.log(e);
        res.status(500).end();
    });
};

/*
bookings.editBooking = (req, res) => {
    Booking.findOne({ where: { id: req.body.id } })
        .then(booking => {
            booking.userName = req.body.user.name;
            booking.userEmail = req.body.user.email;
            booking.userContact = req.body.user.phone;
            booking.paymentType = req.body.paymentType;
            booking.emergencyName = req.body.emergencyName;
            booking.emergencyPhone = req.body.emergencyPhone;
            booking.note = req.body.note;
            Participant.destroy({ where: { bookingId: req.body.id } })//delete previous partiticpants
                .then(() => Promise.all(
                    req.body.participants.map(p => {
                        p.bookingId = req.body.id;
                        return Participant.upsert(p); //insert new ones
                    })))
                .then(() => booking.save())
                .then(() => Booking.findOne({ where: { id: req.body.id }, include: [{ model: Participant }] }))
                .then((booking) => {
                    let data = {};
                    data[booking.id] = booking;
                    res.json(data);
                });
        });
}
*/

bookings.editBooking = (req, res) => {
    db.booking.findOne({where: {id: req.body.id}})
        .then(booking => {
            req.body.maxParticipants = Math.max(booking.maxParticipants, req.body.participants.length);
            return booking.update(req.body)//this ignores partitipants!
        })
        .then(booking => db.booking.findOne({where: {id: booking.id}, include: [{model: db.participant}]}))
        .then(booking => updateAssociation(booking, 'participants', db.participant, req.body.participants))
        .then(() => db.booking.findOne({where: {id: req.body.id}, include: [{model: db.participant}]}))
        .then(booking => {
            log.log("debug", "User %s Editing Booking id %s", req.user.userName, booking.id);
            let data = {};
            data.bookings = [booking];
            res.json(data);
        });
};

bookings.togglePaid = (req, res) => {
    db.booking.findOne({where: {id: req.body.id}, include: [{model: db.participant}]})
        .then(booking => {
            booking.paid = !booking.paid;
            return booking.save()
        })
        .then((booking) => {
            let data = {};
            data.bookings = [booking];
            res.json(data);
        });
};

bookings.deleteBooking = (req, res) => {
    db.booking.findOne({where: {id: req.body.id}})
        .then(booking => booking.destroy())
        .then(() => db.booking.findAll({
            where:
                {
                    $or:
                        [{guestUUID: req.cookies.guestUUID},
                            {
                                $and:
                                    [{userId: req.user.id},
                                        {userId: {$not: 1}}
                                    ]
                            }]
                }, include: [{model: db.participant}]
        }))
        .then(bookings => {
            let data = {bookings};
            res.json(data);
        });
};

bookings.assignVillage = async function (req, res) {
    booking = await db.booking.findOne({where: {id: req.body.bookingId}, include: [{model: db.participant}]});
    booking.villageId = req.body.villageId;
    await booking.save();
    const data = {};
    data.bookings = [booking];
    res.json(data);
};

bookings.addPayment = async function (req, res, next) {

    await db.payment.create(req.body);

    const booking = await db.booking.findOne({
        where: {id: {[Op.eq]: req.body.bookingId}},
        include: [{model: db.event}]
    }); //get the booking, but we can't send this as dangerous scope.

    const scopes = getUserScopes(req.user, booking.event);
    const results = await Promise.all(scopes.map(s => db.booking.scope(s).findOne({where: {id: booking.id}})));

    const flat = results.reduce((a, b) => a.concat(b), []);

    res.json({bookings: flat});
};

bookings.deletePayment = async function (req, res, next) {

    const payment = await db.payment.findOne({where: {id: {[Op.eq]: req.body.id}}});

    const booking = await db.booking.findOne({
        where: {id: {[Op.eq]: payment.bookingId}},
        include: [{model: db.event}]
    }); //get the booking, but we can't send this as dangerous scope.

    await payment.destroy();

    const scopes = getUserScopes(req.user, booking.event);
    const results = await Promise.all(scopes.map(s => db.booking.scope(s).findOne({where: {id: booking.id}})));

    const flat = results.reduce((a, b) => a.concat(b), []);

    res.json({bookings: flat});
};

/**
 *  Test function to update a paricipants updatedAt, disabled in production enviroments.
 *
 */

bookings.updateParticipantDate = async function (req, res) {

    const results = await db.sequelize.query('UPDATE participants SET "updatedAt" = $date WHERE id = $id',
        {
            bind: {id: req.params.participantId, date: moment(req.params.date).format('YYYY-MM-DD HH:mm:ss.SSS')},
            type: db.sequelize.QueryTypes.UPDATE
        });

    const paricipant = await db.participant.findOne({where: {id: req.params.participantId}});

    res.json(paricipant);

};

module.exports = wrapper(bookings);

<|endoftext|>


<commit_before>/* eslint no-console : 0 */

const objfmt = require('object-format');

const Bluez     = require('bluez');
const bluetooth = new Bluez();

function event_log(action, type, properties) {
	console.log('\n======== Event : %s (%s) ========', type, action);
	console.log(objfmt(properties));
	console.log('======== Event : %s (%s) ========\n', type, action);
}

// Register callbacks for changed properties
bluetooth.on('changed-Adapter',        async (properties) => { event_log('Changed', 'Adapter',        properties); });
bluetooth.on('changed-Device',         async (properties) => { event_log('Changed', 'Device',         properties); });
bluetooth.on('changed-Filesystem',     async (properties) => { event_log('Changed', 'Filesystem',     properties); });
bluetooth.on('changed-MediaControl',   async (properties) => { event_log('Changed', 'MediaControl',   properties); });
bluetooth.on('changed-MediaItem',      async (properties) => { event_log('Changed', 'MediaItem',      properties); });
bluetooth.on('changed-MediaPlayer',    async (properties) => { event_log('Changed', 'MediaPlayer',    properties); });
bluetooth.on('changed-MediaTransport', async (properties) => { event_log('Changed', 'MediaTransport', properties); });
bluetooth.on('changed-Network',        async (properties) => { event_log('Changed', 'Network',        properties); });

// Register callbacks for new interfaces
bluetooth.on('added-Adapter',        async (properties) => { event_log('Added', 'Adapter',        properties); });
bluetooth.on('added-Filesystem',     async (properties) => { event_log('Added', 'Filesystem',     properties); });
bluetooth.on('added-MediaControl',   async (properties) => { event_log('Added', 'MediaControl',   properties); });
bluetooth.on('added-MediaItem',      async (properties) => { event_log('Added', 'MediaItem',      properties); });
bluetooth.on('added-MediaPlayer',    async (properties) => { event_log('Added', 'MediaPlayer',    properties); });
bluetooth.on('added-MediaTransport', async (properties) => { event_log('Added', 'MediaTransport', properties); });
bluetooth.on('added-Network',        async (properties) => { event_log('Added', 'Network',        properties); });

bluetooth.on('added-Device', async (properties) => {
	event_log('Added', 'Device', properties);

	event_log('DeviceInterface', 'Log', 'Attempting to get interface of device with address ' + properties.Address);
	let device = await bluetooth.getDevice(properties.Address);

	if (properties.Connected === false) {
		event_log('DeviceConnect', 'Log', 'Attempting to connect to device with address ' + properties.Address);

		await device.Connect().catch((err) => {
			event_log('DeviceConnect', 'Error', 'Error while attempting to connect to device with address ' + properties.Address + ': ' + err.message);
		});
	}
});

// Initialize bluetooth interface
bluetooth.init().then(async () => {
	event_log('Init', 'Log', 'bluetooth.init()');
});
<commit_msg>Update<commit_after>/* eslint no-console : 0 */

const objfmt = require('object-format');

const Bluez     = require('bluez');
const bluetooth = new Bluez();

function event_log(action, type, data) {
	console.log('\n======== Event : %s (%s) ========', type, action);
	console.log(objfmt(data));
	console.log('======== Event : %s (%s) ========\n', type, action);
}

// Register callbacks for changed properties
bluetooth.on('changed-Adapter',        async (data) => { event_log('Changed', 'Adapter',        data); });
bluetooth.on('changed-Device',         async (data) => { event_log('Changed', 'Device',         data); });
bluetooth.on('changed-Filesystem',     async (data) => { event_log('Changed', 'Filesystem',     data); });
bluetooth.on('changed-MediaControl',   async (data) => { event_log('Changed', 'MediaControl',   data); });
bluetooth.on('changed-MediaItem',      async (data) => { event_log('Changed', 'MediaItem',      data); });
bluetooth.on('changed-MediaPlayer',    async (data) => { event_log('Changed', 'MediaPlayer',    data); });
bluetooth.on('changed-MediaTransport', async (data) => { event_log('Changed', 'MediaTransport', data); });
bluetooth.on('changed-Network',        async (data) => { event_log('Changed', 'Network',        data); });

// Register callbacks for new interfaces
bluetooth.on('added-Adapter',        async (data) => { event_log('Added', 'Adapter',        data); });
bluetooth.on('added-Filesystem',     async (data) => { event_log('Added', 'Filesystem',     data); });
bluetooth.on('added-MediaControl',   async (data) => { event_log('Added', 'MediaControl',   data); });
bluetooth.on('added-MediaItem',      async (data) => { event_log('Added', 'MediaItem',      data); });
bluetooth.on('added-MediaPlayer',    async (data) => { event_log('Added', 'MediaPlayer',    data); });
bluetooth.on('added-MediaTransport', async (data) => { event_log('Added', 'MediaTransport', data); });
bluetooth.on('added-Network',        async (data) => { event_log('Added', 'Network',        data); });

bluetooth.on('added-Device', async (data) => {
	event_log('Added', 'Device', data);

	event_log('DeviceInterface', 'Log', 'Attempting to get interface of device with address ' + data.properties.Address);
	let device = await bluetooth.getDevice(data.properties.Address);

	if (data.Connected === false) {
		event_log('DeviceConnect', 'Log', 'Attempting to connect to device with address ' + data.properties.Address);

		await device.Connect().catch((err) => {
			event_log('DeviceConnect', 'Error', 'Error while attempting to connect to device with address ' + data.properties.Address + ': ' + err.message);
		});
	}
});

// Initialize bluetooth interface
bluetooth.init().then(async () => {
	event_log('Init', 'Log', 'bluetooth.init()');
});
<|endoftext|>


<commit_before>// This will be injected dynamically at extension creation time
var appConfig = {inject-background-script-config};

/**
 * Listens for the app launching then creates the window
 *
 * @see http://developer.chrome.com/apps/app.runtime.html
 * @see http://developer.chrome.com/apps/app.window.html
 */
chrome.app.runtime.onLaunched.addListener(function () {
    runApp();
});

/**
 * Listens for the app restarting then re-creates the window.
 *
 * @see http://developer.chrome.com/apps/app.runtime.html
 */
chrome.app.runtime.onRestarted.addListener(function () {
    runApp();
});

/**
 * Creates the window for the application.
 *
 * @see http://developer.chrome.com/apps/app.window.html
 */
function runApp() {
    // Creat a new Chrome app window
    chrome.app.window.create('html/embed.html', appConfig.chromeAppWindow, onWindowLoaded());
}

/**
 * Called before the contentWindow's onload event
 *
 * @see http://developer.chrome.com/apps/app.window.html
 */
function onWindowLoaded(popup) {
    return function (win) {
        // On window loaded event
        win.contentWindow.onload = function () {
            // Get webview
            var webview = win.contentWindow.document.getElementById('webview');

            // Override default user agent if provided
            if (appConfig.userAgent) {
                webview.setUserAgentOverride(appConfig.userAgent);
            }

            // Sign up for 'permissionrequest' event
            webview.addEventListener('permissionrequest', function (e) {
                // Allow all permission requests
                e.request.allow();
            });

            // Sign up for 'newwindow' event
            // Emitted when a target='_blank' link is clicked within the webview
            webview.addEventListener('newwindow', function (e) {
                // Parse target window URL to extract hostname
                var parsedUrl = document.createElement('a');
                parsedUrl.href = e.targetUrl;

                // Popup?
                if (e.initialWidth > 0 && e.initialHeight > 0) {
                    // Open it in a popup window with a set width and height
                    return chrome.app.window.create('html/embed.html', { frame: { type: 'chrome' }, innerBounds: { width: e.initialWidth, height: e.initialHeight } }, onWindowLoaded(e));
                }
                // Open app links internally?
                else if (appConfig.behavior.internalLinks && parsedUrl.hostname === appConfig.hostname) {
                    return chrome.app.window.create('html/embed.html', { frame: { type: 'chrome' }, innerBounds: appConfig.chromeAppWindow.innerBounds }, onWindowLoaded(e));
                }

                // Open the link in a new browser tab/window
                win.contentWindow.open(e.targetUrl);
            });

            // Is this a popup window?
            if (popup) {
                // Override webview source with popup's target URL
                webview.src = popup.targetUrl;
            }
        };
    };
}
<commit_msg>Support for subdomains of a domain to open internally as popups<commit_after>// This will be injected dynamically at extension creation time
var appConfig = {inject-background-script-config};

/**
 * Listens for the app launching then creates the window
 *
 * @see http://developer.chrome.com/apps/app.runtime.html
 * @see http://developer.chrome.com/apps/app.window.html
 */
chrome.app.runtime.onLaunched.addListener(function () {
    runApp();
});

/**
 * Listens for the app restarting then re-creates the window.
 *
 * @see http://developer.chrome.com/apps/app.runtime.html
 */
chrome.app.runtime.onRestarted.addListener(function () {
    runApp();
});

/**
 * Creates the window for the application.
 *
 * @see http://developer.chrome.com/apps/app.window.html
 */
function runApp() {
    // Creat a new Chrome app window
    chrome.app.window.create('html/embed.html', appConfig.chromeAppWindow, onWindowLoaded());
}

/**
 * Called before the contentWindow's onload event
 *
 * @see http://developer.chrome.com/apps/app.window.html
 */
function onWindowLoaded(popup) {
    return function (win) {
        // On window loaded event
        win.contentWindow.onload = function () {
            // Get webview
            var webview = win.contentWindow.document.getElementById('webview');

            // Override default user agent if provided
            if (appConfig.userAgent) {
                webview.setUserAgentOverride(appConfig.userAgent);
            }

            // Sign up for 'permissionrequest' event
            webview.addEventListener('permissionrequest', function (e) {
                // Allow all permission requests
                e.request.allow();
            });

            // Sign up for 'newwindow' event
            // Emitted when a target='_blank' link is clicked within the webview
            webview.addEventListener('newwindow', function (e) {
                // Parse target window URL to extract hostname
                var parsedUrl = document.createElement('a');
                parsedUrl.href = e.targetUrl;

                // Popup?
                if (e.initialWidth > 0 && e.initialHeight > 0) {
                    // Open it in a popup window with a set width and height
                    return chrome.app.window.create('html/embed.html', { frame: { type: 'chrome' }, innerBounds: { width: e.initialWidth, height: e.initialHeight } }, onWindowLoaded(e));
                }
                // Open app links internally?
                else if (appConfig.behavior.internalLinks && parsedUrl.hostname.includes(appConfig.hostname)) {
                    return chrome.app.window.create('html/embed.html', { frame: { type: 'chrome' }, innerBounds: appConfig.chromeAppWindow.innerBounds }, onWindowLoaded(e));
                }

                // Open the link in a new browser tab/window
                win.contentWindow.open(e.targetUrl);
            });

            // Is this a popup window?
            if (popup) {
                // Override webview source with popup's target URL
                webview.src = popup.targetUrl;
            }
        };
    };
}
<|endoftext|>