<commit_before>/** MIT License (c) copyright B Cavalier & J Hann */

(function (define) {
define(function (require) {
"use strict";

	var SortedMap = require('./SortedMap');

	/**
	 * Decorator that applies transforms to properties flowing in
	 * and out of an ObjectAdapter (or similar).
	 * @param adapter {Object}
	 * @param transforms {Object}
	 */
	function addPropertyTransforms (adapter, transforms) {
		var origGet, origAdd, origUpdate, origForEach, origGetItemForEvent,
			transformedItemMap;

		// only override if transforms has properties
		if (transforms && hasProperties(transforms)) {

			origGet = adapter.get;
			origAdd = adapter.add;
			origUpdate = adapter.update;
			origForEach = adapter.forEach;
			origGetItemForEvent = adapter.getItemForEvent;
			transformedItemMap = new SortedMap(adapter.identifier, adapter.comparator);

			if (origGet) {
				adapter.get = function transformedGet (id) {
					return untransformItem(origGet.call(adapter, id), transforms, transformedItemMap);
				};
			}

			if (origAdd) {
				adapter.add = function transformedAdd (item) {
					return origAdd.call(adapter, transformItem(item, transforms, transformedItemMap));
				};
			}

			if (origUpdate) {
				adapter.update = function transformedUpdate (item) {
					return origUpdate.call(adapter, transformItem(item, transforms, transformedItemMap));
				};
			}

			if (origForEach) {
				adapter.forEach = function transformedForEach (lambda) {
					// Note: potential performance improvement if we cache the
					// transformed lambdas in a hashmap.
					function transformedLambda (item, key) {
						var inverted = untransformItem(item, transforms, transformedItemMap);
						return lambda(inverted, key);
					}

					return origForEach.call(adapter, transformedLambda);
				};
			}

			if (origGetItemForEvent) {
				adapter.getItemForEvent = function transformedGetItemForEvent (it) {
					return untransformItem(origGetItemForEvent.call(adapter, it), transforms, transformedItemMap);
				};
			}

		}

		return adapter;
	}

	return addPropertyTransforms;

	function identity (val) { return val; }

	function hasProperties (obj) {
		for (var p in obj) return true;
	}

	function transformItem (item, transforms, map) {
		var transformed, name, transform;

		transformed = {};

		// direct transforms
		for (name in item) {
			transform = transforms[name] || identity;
			transformed[name] = transform(item[name], name, item);
		}

		// derived transforms
		for (name in transforms) {
			if (!(name in item)) {
				transformed[name] = transforms[name](null, name, item);
			}
		}

		map.add(transformed, item);

		return transformed;
	}

	function untransformItem (transformed, transforms, map) {
		var origItem, name, transform;

		// get original item
		origItem = map.get(transformed);

		for (name in origItem) {
			transform = transforms[name] && transforms[name].inverse;
			if (transform) {
				origItem[name] = transform(transformed[name], name, transformed);
			}
		}

		return origItem;
	}

});
}(
	typeof define == 'function'
		? define
		: function (factory) { module.exports = factory(require); }
));
<commit_msg>refreshes cached data item when it's updated<commit_after>/** MIT License (c) copyright B Cavalier & J Hann */

(function (define) {
define(function (require) {
"use strict";

	var SortedMap = require('./SortedMap');

	/**
	 * Decorator that applies transforms to properties flowing in
	 * and out of an ObjectAdapter (or similar).
	 * @param adapter {Object}
	 * @param transforms {Object}
	 */
	function addPropertyTransforms (adapter, transforms) {
		var origGet, origAdd, origUpdate, origForEach, origGetItemForEvent,
			transformedItemMap;

		// only override if transforms has properties
		if (transforms && hasProperties(transforms)) {

			origGet = adapter.get;
			origAdd = adapter.add;
			origUpdate = adapter.update;
			origForEach = adapter.forEach;
			origGetItemForEvent = adapter.getItemForEvent;
			transformedItemMap = new SortedMap(adapter.identifier, adapter.comparator);

			if (origGet) {
				adapter.get = function transformedGet (id) {
					return untransformItem(origGet.call(adapter, id), transforms, transformedItemMap);
				};
			}

			if (origAdd) {
				adapter.add = function transformedAdd (item) {
					return origAdd.call(adapter, transformItem(item, transforms, transformedItemMap));
				};
			}

			if (origUpdate) {
				adapter.update = function transformedUpdate (item) {
					return origUpdate.call(adapter, transformItem(item, transforms, transformedItemMap));
				};
			}

			if (origForEach) {
				adapter.forEach = function transformedForEach (lambda) {
					// Note: potential performance improvement if we cache the
					// transformed lambdas in a hashmap.
					function transformedLambda (item, key) {
						var inverted = untransformItem(item, transforms, transformedItemMap);
						return lambda(inverted, key);
					}

					return origForEach.call(adapter, transformedLambda);
				};
			}

			if (origGetItemForEvent) {
				adapter.getItemForEvent = function transformedGetItemForEvent (it) {
					return untransformItem(origGetItemForEvent.call(adapter, it), transforms, transformedItemMap);
				};
			}

		}

		return adapter;
	}

	return addPropertyTransforms;

	function identity (val) { return val; }

	function hasProperties (obj) {
		for (var p in obj) return true;
	}

	function transformItem (item, transforms, map) {
		var transformed, name, transform;

		transformed = {};

		// direct transforms
		for (name in item) {
			transform = transforms[name] || identity;
			transformed[name] = transform(item[name], name, item);
		}

		// derived transforms
		for (name in transforms) {
			if (!(name in item)) {
				transformed[name] = transforms[name](null, name, item);
			}
		}

		// remove should be a noop if we don't already have it
		map.remove(transformed);
		map.add(transformed, item);

		return transformed;
	}

	function untransformItem (transformed, transforms, map) {
		var origItem, name, transform;

		// get original item
		origItem = map.get(transformed);

		for (name in origItem) {
			transform = transforms[name] && transforms[name].inverse;
			if (transform) {
				origItem[name] = transform(transformed[name], name, transformed);
			}
		}

		return origItem;
	}

});
}(
	typeof define == 'function'
		? define
		: function (factory) { module.exports = factory(require); }
));
<|endoftext|>


<commit_before>/**
 * @namespace hs.compositions
 * @memberOf hs
 */

define(['angular', 'ol', 'map'],

    function(angular, ol) {
        var module = angular.module('hs.compositions', ['hs.map', 'hs.core'])
            .directive('hs.compositions.directive', function() {
                return {
                    templateUrl: hsl_path + 'components/compositions/partials/compositions.html',
                    link: function(scope, element) {
                        $('.mid-pane').prepend($('

').addClass('composition-info'));
                        $('.mid-pane').css('margin-top', '0px');
                        $(".keywords-panel").hide();
                    }
                };
            })
            .directive('hs.compositions.overwriteDialogDirective', function() {
                return {
                    templateUrl: hsl_path + 'components/compositions/partials/dialog_overwriteconfirm.html',
                    link: function(scope, element, attrs) {
                        $('#composition-overwrite-dialog').modal('show');
                    }
                };
            })

        .service('hs.compositions.service_parser', ['hs.map.service', 'Core', '$rootScope', function(OlMap, Core, $rootScope) {
            var me = {
                composition_loaded: null,
                load: function(url, overwrite, callback) {
                    url = url.replace('&', '&');
                    if (typeof use_proxy === 'undefined' || use_proxy === true) {
                        url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + window.escape(url);
                    } else {
                        url = url;
                    }
                    $.ajax({
                            url: url
                        })
                        .done(function(response) {
                            me.composition_loaded = url;
                            if (angular.isUndefined(overwrite) || overwrite == true) {
                                var to_be_removed = [];
                                OlMap.map.getLayers().forEach(function(lyr) {
                                    if (lyr.get('from_composition'))
                                        to_be_removed.push(lyr);
                                });
                                while (to_be_removed.length > 0) {
                                    OlMap.map.removeLayer(to_be_removed.shift());
                                }
                            }
                            $('.composition-info').html($('').html($('
').html(response.title || response.data.title)).click(function() {
                                $('.composition-abstract').toggle()
                            }));
                            $('.composition-info').append($('
').html(response.abstract || response.data.abstract).addClass('well composition-abstract'));
                            OlMap.map.getView().fit(me.parseExtent(response.extent || response.data.extent), OlMap.map.getSize());
                            var layers = me.jsonToLayers(response);
                            for (var i = 0; i < layers.length; i++) {
                                OlMap.map.addLayer(layers[i]);
                            }
                            Core.setMainPanel('layermanager');
                            $rootScope.$broadcast('compositions.composition_loaded', response);
                            if (typeof callback !== 'undefined' && callback !== null) callback();
                        })
                },
                parseExtent: function(b) {
                    if (typeof b == 'string')
                        b = b.split(" ");
                    var first_pair = [parseFloat(b[0]), parseFloat(b[1])]
                    var second_pair = [parseFloat(b[2]), parseFloat(b[3])];
                    first_pair = ol.proj.transform(first_pair, 'EPSG:4326', OlMap.map.getView().getProjection());
                    second_pair = ol.proj.transform(second_pair, 'EPSG:4326', OlMap.map.getView().getProjection());
                    return [first_pair[0], first_pair[1], second_pair[0], second_pair[1]];
                },
                jsonToLayers: function(j) {
                    var layers = [];
                    if (j.data) j = j.data;
                    for (var i = 0; i < j.layers.length; i++) {
                        var lyr_def = j.layers[i];
                        switch (lyr_def.className) {
                            case "HSLayers.Layer.WMS":
                                var source_class = lyr_def.singleTile ? ol.source.ImageWMS : ol.source.TileWMS;
                                var layer_class = lyr_def.singleTile ? ol.layer.Image : ol.layer.Tile;
                                var params = lyr_def.params;
                                delete params.REQUEST;
                                delete params.FORMAT;
                                var new_layer = new layer_class({
                                    title: lyr_def.title,
                                    from_composition: true,
                                    maxResolution: lyr_def.maxResolution,
                                    minResolution: lyr_def.minResolution,
                                    minScale: lyr_def.minScale,
                                    maxScale: lyr_def.maxScale,
                                    show_in_manager: lyr_def.displayInLayerSwitcher,
                                    abstract: lyr_def.name,
                                    metadata: lyr_def.metadata,
                                    saveState: true,
                                    source: new source_class({
                                        url: lyr_def.url,
                                        attributions: lyr_def.attribution ? [new ol.Attribution({
                                            html: '' + lyr_def.attribution.Title + ''
                                        })] : undefined,
                                        styles: lyr_def.metadata.styles,
                                        params: params,
                                        crossOrigin: 'anonymous',
                                        projection: lyr_def.projection,
                                        ratio: lyr_def.ratio,
                                        crossOrigin: null
                                    })
                                });
                                layers.push(new_layer);
                                break;
                            case 'OpenLayers.Layer.Vector':
                                if (lyr_def.protocol && lyr_def.protocol.format.className == 'OpenLayers.Format.KML') {
                                    var url = lyr_def.protocol.options.url;
                                    if (typeof use_proxy === 'undefined' || use_proxy === true) {
                                        url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                                    }
                                    var src = new ol.source.KML({
                                        projection: ol.proj.get(lyr_def.projection),
                                        url: url,
                                        extractStyles: true
                                    })
                                    var lyr = new ol.layer.Vector({
                                        from_composition: true,
                                        source: src,
                                        title: lyr_def.title
                                    });
                                    layers.push(lyr);
                                }
                                break;
                        }

                    }
                    return layers;
                }
            };
            return me;
        }])

        .controller('hs.compositions.controller', ['$scope', '$rootScope', 'hs.map.service', 'Core', 'hs.compositions.service_parser', 'config', 'hs.permalink.service_url', '$compile', '$cookies',
            function($scope, $rootScope, OlMap, Core, composition_parser, config, permalink, $compile, $cookies) {
                $scope.page_size = 15;
                $scope.page_count = 1000;
                $scope.panel_name = 'composition_browser';
                $scope.keywords = {
                    "Basemap": false,
                    "Borders": false,
                    "PhysicalGeography": false,
                    "Demographics": false,
                    "Economics": false,
                    "SocioPoliticalConditions": false,
                    "Culture": false,
                    "Transport": false,
                    "LandUse": false,
                    "Environment": false,
                    "Water": false,
                    "Hazards": false,
                    "Cadastre": false,
                    "Infrastructure": false,
                    "RealEstate": false,
                    "Planning": false,
                    "ComplexInformation": false
                };
                $scope.filter_by_extent = true;

                var ajax_req = null;
                $scope.loadCompositions = function(page) {
                    if (typeof page === 'undefined') page = 1;
                    if ($scope.page_count == 0) $scope.page_count = 1;
                    if (page == 0 || page > $scope.page_count) return;
                    extent_layer.getSource().clear();
                    $scope.current_page = page;
                    $scope.first_composition_ix = (page - 1) * $scope.page_size;
                    var text_filter = $scope.query && $scope.query.title != '' ? encodeURIComponent(" AND AnyText like '*" + $scope.query.title + "*'") : '';
                    var keyword_filter = "";
                    var selected = [];
                    angular.forEach($scope.keywords, function(value, key) {
                        if (value) selected.push("subject='" + key + "'");
                    });
                    if (selected.length > 0)
                        keyword_filter = encodeURIComponent(' AND (' + selected.join(' OR ') + ')');
                    var b = ol.proj.transformExtent(OlMap.map.getView().calculateExtent(OlMap.map.getSize()), OlMap.map.getView().getProjection(), 'EPSG:4326');
                    var bbox_delimiter = config.compositions_catalogue_url.indexOf('cswClientRun.php') > 0 ? ',' : ' ';
                    var bbox = ($scope.filter_by_extent ? encodeURIComponent(" and BBOX='" + b.join(bbox_delimiter) + "'") : '');
                    var url = config.compositions_catalogue_url + "?format=json&serviceName=p4b&query=type%3Dapplication" + bbox + text_filter + keyword_filter + "&lang=eng&sortBy=bbox&detail=summary&start=" + $scope.first_composition_ix + "&page=1&limit=" + $scope.page_size;
                    if (typeof use_proxy === 'undefined' || use_proxy === true) {
                        url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                    } else {
                        url = url;
                    }
                    if (ajax_req != null) ajax_req.abort();
                    ajax_req = $.ajax({
                            url: url
                        })
                        .done(function(response) {
                            ajax_req = null;
                            $scope.compositions = response.records;
                            $scope.pages = [];
                            $scope.page_count = Math.ceil(response.matched / $scope.page_size);
                            if (response.matched > response.returned) {
                                for (var i = 1; i <= Math.ceil(response.matched / $scope.page_size); i++)
                                    $scope.pages.push(i);
                            }
                            $(response.records).each(function() {
                                var attributes = {
                                    record: this,
                                    hs_notqueryable: true,
                                    highlighted: false
                                };
                                var extent = composition_parser.parseExtent(this.bbox);
                                attributes.geometry = ol.geom.Polygon.fromExtent(extent);
                                var new_feature = new ol.Feature(attributes);
                                this.feature = new_feature;
                                extent_layer.getSource().addFeatures([new_feature]);
                            })
                            if (!$scope.$$phase) $scope.$digest();
                            $('[data-toggle="tooltip"]').tooltip();
                            $scope.loadStatusManagerCompositions();
                        })
                }

                $scope.loadStatusManagerCompositions = function() {
                    var url = config.status_manager_url;

                    url += '?request=list&project=' + encodeURIComponent(config.project_name) + '&_dc=1448532698819&page=1&start=0&limit=1000&sort=%5B%7B%22property%22%3A%22title%22%2C%22direction%22%3A%22ASC%22%7D%5D';
                    if(config.status_manager_url.indexOf(window.location.origin)==-1){
                        if (typeof use_proxy === 'undefined' || use_proxy === true) {
                            url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                        } else {
                            url = url;
                        }
                    }
                    var jsessionid = $cookies.get("JSESSIONID");
                    ajax_req = $.ajax({
                            url: url,
                            data: {JSESSIONID: jsessionid},
                            cache: false
                        })
                        .done(function(response) {
                            ajax_req = null;
                            angular.forEach(response.results, function(record) {
                                var found = false;
                                angular.forEach($scope.compositions, function(composition) {
                                    if (composition.id == record.id && record.edit) {
                                        composition.editable = true;
                                        found = true;
                                    }
                                })
                                if (!found) {
                                    record.editable = record.edit;
                                    if (angular.isUndefined(record.link)) {
                                        record.link = config.status_manager_url + '?request=load&id=' + record.id;
                                    }
                                    $scope.compositions.push(record);
                                }
                            });
                            if (!$scope.$$phase) $scope.$digest();
                        })
                }

                $scope.delete = function(composition) {
                    if (confirm("Do you realy want to delete the composition?")) {
                        var url = config.status_manager_url + '?request=delete&id=' + composition.id + '&project=' + encodeURIComponent(config.project_name);
                        if (typeof use_proxy === 'undefined' || use_proxy === true) {
                            url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                        } else {
                            url = url;
                        }
                        ajax_req = $.ajax({
                                url: url
                            })
                            .done(function(response) {
                                $scope.loadCompositions();
                            })
                    }

                }

                $scope.edit = function(composition) {
                    $scope.use_callback_for_edit = true;
                    $scope.loadComposition(composition.link);
                }
                $scope.use_callback_for_edit = false;

                function callbackForEdit() {
                    Core.openStatusCreator();
                }

                $scope.highlightComposition = function(composition, state) {
                    composition.feature.set('highlighted', state)
                }

                OlMap.map.on('pointermove', function(evt) {
                    var features = extent_layer.getSource().getFeaturesAtCoordinate(evt.coordinate);
                    var something_done = false;
                    $(extent_layer.getSource().getFeatures()).each(function() {
                        if (this.get("record").highlighted) {
                            this.get("record").highlighted = false;
                            something_done = true;
                        }
                    });
                    if (features.length) {
                        $(features).each(function() {
                            if (!this.get("record").highlighted) {
                                this.get("record").highlighted = true;
                                something_done = true;
                            }
                        })
                    }
                    if (something_done && !$scope.$$phase) $scope.$digest();
                });

                var extent_layer = new ol.layer.Vector({
                    title: "Composition extents",
                    show_in_manager: false,
                    source: new ol.source.Vector(),
                    style: function(feature, resolution) {
                        return [new ol.style.Style({
                            stroke: new ol.style.Stroke({
                                color: '#005CB6',
                                width: feature.get('highlighted') ? 4 : 1
                            }),
                            fill: new ol.style.Fill({
                                color: 'rgba(0, 0, 255, 0.01)'
                            })
                        })]
                    }
                });

                OlMap.map.addLayer(extent_layer);

                var timer;
                OlMap.map.getView().on('change:center', function(e) {
                    if (timer != null) clearTimeout(timer);
                    timer = setTimeout(function() {
                        if ($scope.filter_by_extent) $scope.loadCompositions();
                    }, 500);
                });
                OlMap.map.getView().on('change:resolution', function(e) {
                    if (timer != null) clearTimeout(timer);
                    timer = setTimeout(function() {
                        if ($scope.filter_by_extent) $scope.loadCompositions();
                    }, 500);
                });

                $scope.loadComposition = function(url) {
                    if (composition_parser.composition_loaded != null) {
                        $scope.composition_to_be_loaded = url;
                        if ($("#hs-dialog-area #composition-overwrite-dialog").length == 0) {
                            var el = angular.element('
');
                            $("#hs-dialog-area").append(el);
                            $compile(el)($scope);
                        } else {
                            $('#composition-overwrite-dialog').modal('show');
                        }
                    } else {
                        composition_parser.load(url, true, $scope.use_callback_for_edit ? callbackForEdit : null);
                    }
                }

                $scope.overwrite = function() {
                    composition_parser.load($scope.composition_to_be_loaded, true, $scope.use_callback_for_edit ? callbackForEdit : null);
                }

                $scope.add = function() {
                    composition_parser.load($scope.composition_to_be_loaded, false, $scope.use_callback_for_edit ? callbackForEdit : null);
                }

                $scope.loadCompositions();
                $scope.toggleKeywords = function() {
                    $(".keywords-panel").slideToggle();
                }
                if (permalink.getParamValue('composition')) {
                    var id = permalink.getParamValue('composition');
                    if (id.indexOf('http') == -1 && id.indexOf('statusmanager2') == -1)
                        id = '/wwwlibs/statusmanager2/index.php?request=load&id=' + id;
                    composition_parser.load(id);
                }

                $scope.$on('core.map_reset', function(event, data) {
                    composition_parser.composition_loaded = null;
                });
                $scope.$emit('scope_loaded', "Compositions");
                $scope.$on('core.mainpanel_changed', function(event) {
                    extent_layer.setVisible(Core.panelVisible($scope.panel_name, $scope));
                });
            }
        ]);

    })
<commit_msg>set editable correct way<commit_after>/**
 * @namespace hs.compositions
 * @memberOf hs
 */

define(['angular', 'ol', 'map'],

    function(angular, ol) {
        var module = angular.module('hs.compositions', ['hs.map', 'hs.core'])
            .directive('hs.compositions.directive', function() {
                return {
                    templateUrl: hsl_path + 'components/compositions/partials/compositions.html',
                    link: function(scope, element) {
                        $('.mid-pane').prepend($('

').addClass('composition-info'));
                        $('.mid-pane').css('margin-top', '0px');
                        $(".keywords-panel").hide();
                    }
                };
            })
            .directive('hs.compositions.overwriteDialogDirective', function() {
                return {
                    templateUrl: hsl_path + 'components/compositions/partials/dialog_overwriteconfirm.html',
                    link: function(scope, element, attrs) {
                        $('#composition-overwrite-dialog').modal('show');
                    }
                };
            })

        .service('hs.compositions.service_parser', ['hs.map.service', 'Core', '$rootScope', function(OlMap, Core, $rootScope) {
            var me = {
                composition_loaded: null,
                load: function(url, overwrite, callback) {
                    url = url.replace('&', '&');
                    if (typeof use_proxy === 'undefined' || use_proxy === true) {
                        url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + window.escape(url);
                    } else {
                        url = url;
                    }
                    $.ajax({
                            url: url
                        })
                        .done(function(response) {
                            me.composition_loaded = url;
                            if (angular.isUndefined(overwrite) || overwrite == true) {
                                var to_be_removed = [];
                                OlMap.map.getLayers().forEach(function(lyr) {
                                    if (lyr.get('from_composition'))
                                        to_be_removed.push(lyr);
                                });
                                while (to_be_removed.length > 0) {
                                    OlMap.map.removeLayer(to_be_removed.shift());
                                }
                            }
                            $('.composition-info').html($('').html($('
').html(response.title || response.data.title)).click(function() {
                                $('.composition-abstract').toggle()
                            }));
                            $('.composition-info').append($('
').html(response.abstract || response.data.abstract).addClass('well composition-abstract'));
                            OlMap.map.getView().fit(me.parseExtent(response.extent || response.data.extent), OlMap.map.getSize());
                            var layers = me.jsonToLayers(response);
                            for (var i = 0; i < layers.length; i++) {
                                OlMap.map.addLayer(layers[i]);
                            }
                            Core.setMainPanel('layermanager');
                            $rootScope.$broadcast('compositions.composition_loaded', response);
                            if (typeof callback !== 'undefined' && callback !== null) callback();
                        })
                },
                parseExtent: function(b) {
                    if (typeof b == 'string')
                        b = b.split(" ");
                    var first_pair = [parseFloat(b[0]), parseFloat(b[1])]
                    var second_pair = [parseFloat(b[2]), parseFloat(b[3])];
                    first_pair = ol.proj.transform(first_pair, 'EPSG:4326', OlMap.map.getView().getProjection());
                    second_pair = ol.proj.transform(second_pair, 'EPSG:4326', OlMap.map.getView().getProjection());
                    return [first_pair[0], first_pair[1], second_pair[0], second_pair[1]];
                },
                jsonToLayers: function(j) {
                    var layers = [];
                    if (j.data) j = j.data;
                    for (var i = 0; i < j.layers.length; i++) {
                        var lyr_def = j.layers[i];
                        switch (lyr_def.className) {
                            case "HSLayers.Layer.WMS":
                                var source_class = lyr_def.singleTile ? ol.source.ImageWMS : ol.source.TileWMS;
                                var layer_class = lyr_def.singleTile ? ol.layer.Image : ol.layer.Tile;
                                var params = lyr_def.params;
                                delete params.REQUEST;
                                delete params.FORMAT;
                                var new_layer = new layer_class({
                                    title: lyr_def.title,
                                    from_composition: true,
                                    maxResolution: lyr_def.maxResolution,
                                    minResolution: lyr_def.minResolution,
                                    minScale: lyr_def.minScale,
                                    maxScale: lyr_def.maxScale,
                                    show_in_manager: lyr_def.displayInLayerSwitcher,
                                    abstract: lyr_def.name,
                                    metadata: lyr_def.metadata,
                                    saveState: true,
                                    source: new source_class({
                                        url: lyr_def.url,
                                        attributions: lyr_def.attribution ? [new ol.Attribution({
                                            html: '' + lyr_def.attribution.Title + ''
                                        })] : undefined,
                                        styles: lyr_def.metadata.styles,
                                        params: params,
                                        crossOrigin: 'anonymous',
                                        projection: lyr_def.projection,
                                        ratio: lyr_def.ratio,
                                        crossOrigin: null
                                    })
                                });
                                layers.push(new_layer);
                                break;
                            case 'OpenLayers.Layer.Vector':
                                if (lyr_def.protocol && lyr_def.protocol.format.className == 'OpenLayers.Format.KML') {
                                    var url = lyr_def.protocol.options.url;
                                    if (typeof use_proxy === 'undefined' || use_proxy === true) {
                                        url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                                    }
                                    var src = new ol.source.KML({
                                        projection: ol.proj.get(lyr_def.projection),
                                        url: url,
                                        extractStyles: true
                                    })
                                    var lyr = new ol.layer.Vector({
                                        from_composition: true,
                                        source: src,
                                        title: lyr_def.title
                                    });
                                    layers.push(lyr);
                                }
                                break;
                        }

                    }
                    return layers;
                }
            };
            return me;
        }])

        .controller('hs.compositions.controller', ['$scope', '$rootScope', 'hs.map.service', 'Core', 'hs.compositions.service_parser', 'config', 'hs.permalink.service_url', '$compile', '$cookies',
            function($scope, $rootScope, OlMap, Core, composition_parser, config, permalink, $compile, $cookies) {
                $scope.page_size = 15;
                $scope.page_count = 1000;
                $scope.panel_name = 'composition_browser';
                $scope.keywords = {
                    "Basemap": false,
                    "Borders": false,
                    "PhysicalGeography": false,
                    "Demographics": false,
                    "Economics": false,
                    "SocioPoliticalConditions": false,
                    "Culture": false,
                    "Transport": false,
                    "LandUse": false,
                    "Environment": false,
                    "Water": false,
                    "Hazards": false,
                    "Cadastre": false,
                    "Infrastructure": false,
                    "RealEstate": false,
                    "Planning": false,
                    "ComplexInformation": false
                };
                $scope.filter_by_extent = true;

                var ajax_req = null;
                $scope.loadCompositions = function(page) {
                    if (typeof page === 'undefined') page = 1;
                    if ($scope.page_count == 0) $scope.page_count = 1;
                    if (page == 0 || page > $scope.page_count) return;
                    extent_layer.getSource().clear();
                    $scope.current_page = page;
                    $scope.first_composition_ix = (page - 1) * $scope.page_size;
                    var text_filter = $scope.query && $scope.query.title != '' ? encodeURIComponent(" AND AnyText like '*" + $scope.query.title + "*'") : '';
                    var keyword_filter = "";
                    var selected = [];
                    angular.forEach($scope.keywords, function(value, key) {
                        if (value) selected.push("subject='" + key + "'");
                    });
                    if (selected.length > 0)
                        keyword_filter = encodeURIComponent(' AND (' + selected.join(' OR ') + ')');
                    var b = ol.proj.transformExtent(OlMap.map.getView().calculateExtent(OlMap.map.getSize()), OlMap.map.getView().getProjection(), 'EPSG:4326');
                    var bbox_delimiter = config.compositions_catalogue_url.indexOf('cswClientRun.php') > 0 ? ',' : ' ';
                    var bbox = ($scope.filter_by_extent ? encodeURIComponent(" and BBOX='" + b.join(bbox_delimiter) + "'") : '');
                    var url = config.compositions_catalogue_url + "?format=json&serviceName=p4b&query=type%3Dapplication" + bbox + text_filter + keyword_filter + "&lang=eng&sortBy=bbox&detail=summary&start=" + $scope.first_composition_ix + "&page=1&limit=" + $scope.page_size;
                    if (typeof use_proxy === 'undefined' || use_proxy === true) {
                        url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                    } else {
                        url = url;
                    }
                    if (ajax_req != null) ajax_req.abort();
                    ajax_req = $.ajax({
                            url: url
                        })
                        .done(function(response) {
                            ajax_req = null;
                            $scope.compositions = response.records;
                            $scope.pages = [];
                            $scope.page_count = Math.ceil(response.matched / $scope.page_size);
                            if (response.matched > response.returned) {
                                for (var i = 1; i <= Math.ceil(response.matched / $scope.page_size); i++)
                                    $scope.pages.push(i);
                            }
                            $(response.records).each(function() {
                                var attributes = {
                                    record: this,
                                    hs_notqueryable: true,
                                    highlighted: false
                                };
                                var extent = composition_parser.parseExtent(this.bbox);
                                attributes.geometry = ol.geom.Polygon.fromExtent(extent);
                                var new_feature = new ol.Feature(attributes);
                                this.feature = new_feature;
                                extent_layer.getSource().addFeatures([new_feature]);
                            })
                            if (!$scope.$$phase) $scope.$digest();
                            $('[data-toggle="tooltip"]').tooltip();
                            $scope.loadStatusManagerCompositions();
                        })
                }

                $scope.loadStatusManagerCompositions = function() {
                    var url = config.status_manager_url;

                    url += '?request=list&project=' + encodeURIComponent(config.project_name) + '&_dc=1448532698819&page=1&start=0&limit=1000&sort=%5B%7B%22property%22%3A%22title%22%2C%22direction%22%3A%22ASC%22%7D%5D';
                    if(config.status_manager_url.indexOf(window.location.origin)==-1){
                        if (typeof use_proxy === 'undefined' || use_proxy === true) {
                            url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                        } else {
                            url = url;
                        }
                    }
                    var jsessionid = $cookies.get("JSESSIONID");
                    ajax_req = $.ajax({
                            url: url,
                            data: {JSESSIONID: jsessionid},
                            cache: false
                        })
                        .done(function(response) {
                            ajax_req = null;
                            angular.forEach(response.results, function(record) {
                                var found = false;
                                angular.forEach($scope.compositions, function(composition) {
                                    if (composition.id == record.id) {
                                        composition.editable = record.edit;
                                        found = true;
                                    }
                                })
                                if (!found) {
                                    record.editable = record.edit;
                                    if (angular.isUndefined(record.link)) {
                                        record.link = config.status_manager_url + '?request=load&id=' + record.id;
                                    }
                                    $scope.compositions.push(record);
                                }
                            });
                            if (!$scope.$$phase) $scope.$digest();
                        })
                }

                $scope.delete = function(composition) {
                    if (confirm("Do you realy want to delete the composition?")) {
                        var url = config.status_manager_url + '?request=delete&id=' + composition.id + '&project=' + encodeURIComponent(config.project_name);
                        if (typeof use_proxy === 'undefined' || use_proxy === true) {
                            url = "/cgi-bin/hsproxy.cgi?toEncoding=utf-8&url=" + encodeURIComponent(url);
                        } else {
                            url = url;
                        }
                        ajax_req = $.ajax({
                                url: url
                            })
                            .done(function(response) {
                                $scope.loadCompositions();
                            })
                    }

                }

                $scope.edit = function(composition) {
                    $scope.use_callback_for_edit = true;
                    $scope.loadComposition(composition.link);
                }
                $scope.use_callback_for_edit = false;

                function callbackForEdit() {
                    Core.openStatusCreator();
                }

                $scope.highlightComposition = function(composition, state) {
                    composition.feature.set('highlighted', state)
                }

                OlMap.map.on('pointermove', function(evt) {
                    var features = extent_layer.getSource().getFeaturesAtCoordinate(evt.coordinate);
                    var something_done = false;
                    $(extent_layer.getSource().getFeatures()).each(function() {
                        if (this.get("record").highlighted) {
                            this.get("record").highlighted = false;
                            something_done = true;
                        }
                    });
                    if (features.length) {
                        $(features).each(function() {
                            if (!this.get("record").highlighted) {
                                this.get("record").highlighted = true;
                                something_done = true;
                            }
                        })
                    }
                    if (something_done && !$scope.$$phase) $scope.$digest();
                });

                var extent_layer = new ol.layer.Vector({
                    title: "Composition extents",
                    show_in_manager: false,
                    source: new ol.source.Vector(),
                    style: function(feature, resolution) {
                        return [new ol.style.Style({
                            stroke: new ol.style.Stroke({
                                color: '#005CB6',
                                width: feature.get('highlighted') ? 4 : 1
                            }),
                            fill: new ol.style.Fill({
                                color: 'rgba(0, 0, 255, 0.01)'
                            })
                        })]
                    }
                });

                OlMap.map.addLayer(extent_layer);

                var timer;
                OlMap.map.getView().on('change:center', function(e) {
                    if (timer != null) clearTimeout(timer);
                    timer = setTimeout(function() {
                        if ($scope.filter_by_extent) $scope.loadCompositions();
                    }, 500);
                });
                OlMap.map.getView().on('change:resolution', function(e) {
                    if (timer != null) clearTimeout(timer);
                    timer = setTimeout(function() {
                        if ($scope.filter_by_extent) $scope.loadCompositions();
                    }, 500);
                });

                $scope.loadComposition = function(url) {
                    if (composition_parser.composition_loaded != null) {
                        $scope.composition_to_be_loaded = url;
                        if ($("#hs-dialog-area #composition-overwrite-dialog").length == 0) {
                            var el = angular.element('
');
                            $("#hs-dialog-area").append(el);
                            $compile(el)($scope);
                        } else {
                            $('#composition-overwrite-dialog').modal('show');
                        }
                    } else {
                        composition_parser.load(url, true, $scope.use_callback_for_edit ? callbackForEdit : null);
                    }
                }

                $scope.overwrite = function() {
                    composition_parser.load($scope.composition_to_be_loaded, true, $scope.use_callback_for_edit ? callbackForEdit : null);
                }

                $scope.add = function() {
                    composition_parser.load($scope.composition_to_be_loaded, false, $scope.use_callback_for_edit ? callbackForEdit : null);
                }

                $scope.loadCompositions();
                $scope.toggleKeywords = function() {
                    $(".keywords-panel").slideToggle();
                }
                if (permalink.getParamValue('composition')) {
                    var id = permalink.getParamValue('composition');
                    if (id.indexOf('http') == -1 && id.indexOf('statusmanager2') == -1)
                        id = '/wwwlibs/statusmanager2/index.php?request=load&id=' + id;
                    composition_parser.load(id);
                }

                $scope.$on('core.map_reset', function(event, data) {
                    composition_parser.composition_loaded = null;
                });
                $scope.$emit('scope_loaded', "Compositions");
                $scope.$on('core.mainpanel_changed', function(event) {
                    extent_layer.setVisible(Core.panelVisible($scope.panel_name, $scope));
                });
            }
        ]);

    })
<|endoftext|>


<commit_before>/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

export function watchForEmbedLoaded(container) {
  const windowLoaded = new Promise(resolve => {
    window.addEventListener("load", resolve);
  });

  const startTime = new Date();

  return new Promise((resolve, reject) => {
    const resolveWithResolution = () => {
      resolve({
        duration: new Date().valueOf() - startTime.valueOf(),
        width: container.offsetWidth,
        height: container.offsetHeight
      });
    };

    // Allow up to 5 seconds to size the embed.
    setTimeout(resolveWithResolution, 5000);

    // If there is no JS script in the embed, resolve once window loaded.
    // This allows us to obtain dimensions for an image/video that lacks
    // width/height attributes.
    const script = container.querySelector(
      'script:not([type]), script[type="module"], script[type~="javascript"], *[onload]'
    );
    if (!script) {
      const dimensionLessVideo = container.querySelector(
        "video:not([width][height])"
      );
      if (dimensionLessVideo) {
        if (dimensionLessVideo.videoWidth && dimensionLessVideo.videoHeight) {
          resolveWithResolution();
        } else {
          dimensionLessVideo.addEventListener(
            "loadedmetadata",
            resolveWithResolution
          );
        }
      } else {
        windowLoaded.then(resolveWithResolution);
      }
      return;
    }

    // Warning: the embed may be wise enough to implement lazy-loading.

    // TODO: Consider using ResizeObserver. The following is commented out because it triggers before a resize happens.
    // const resizeObserver = new ResizeObserver(
    //   ( entries ) => {
    //
    //     for ( const entry of entries ) {
    //       console.info(entry)
    //       const iframe = container.querySelector('iframe');
    //       if (iframe) {
    //         console.info('offsetHeight', iframe.offsetHeight)
    //       }
    //
    //       console.info(  entry.contentBoxSize, entry.contentRect.height )
    //       if ( entry.contentRect.height > 0 ) {
    //         //console.info(  entry.contentBoxSize, entry.contentRect )
    //
    //         // resolveWithResolution();
    //         break;
    //       }
    //     }
    //   }
    // );
    // resizeObserver.observe( container );

    // Start listening for DOM changes, and stop once a 2.5-second pause is encountered.
    let resolveTimeoutId = 0;
    const mutationObserver = new MutationObserver(() => {
      clearTimeout(resolveTimeoutId);

      const complete = () => {
        mutationObserver.disconnect();
        resolveWithResolution();
      };

      // As a shortcut, complete as soon as am iframe with a non-zero height is encountered.
      // TODO: Sometimes the mutation seems to trigger before layout happens.
      const iframe = container.querySelector('iframe');
      if ( iframe && iframe.offsetHeight > 0 ) {
        complete();
      }

      resolveTimeoutId = setTimeout(complete, 2500);
    });
    mutationObserver.observe(container, {
      subtree: true,
      childList: true,
      attributes: true
    });
  });
}
<commit_msg>Remove shortcut since unreliable<commit_after>/*
 * Copyright 2021 Google LLC
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

export function watchForEmbedLoaded(container) {
  const windowLoaded = new Promise(resolve => {
    window.addEventListener("load", resolve);
  });

  const startTime = new Date();

  return new Promise((resolve, reject) => {
    const resolveWithResolution = () => {
      resolve({
        duration: new Date().valueOf() - startTime.valueOf(),
        width: container.offsetWidth,
        height: container.offsetHeight
      });
    };

    // Allow up to 5 seconds to size the embed.
    setTimeout(resolveWithResolution, 5000);

    // If there is no JS script in the embed, resolve once window loaded.
    // This allows us to obtain dimensions for an image/video that lacks
    // width/height attributes.
    const script = container.querySelector(
      'script:not([type]), script[type="module"], script[type~="javascript"], *[onload]'
    );
    if (!script) {
      const dimensionLessVideo = container.querySelector(
        "video:not([width][height])"
      );
      if (dimensionLessVideo) {
        if (dimensionLessVideo.videoWidth && dimensionLessVideo.videoHeight) {
          resolveWithResolution();
        } else {
          dimensionLessVideo.addEventListener(
            "loadedmetadata",
            resolveWithResolution
          );
        }
      } else {
        windowLoaded.then(resolveWithResolution);
      }
      return;
    }

    // Warning: the embed may be wise enough to implement lazy-loading.

    // TODO: Consider using ResizeObserver. The following is commented out because it triggers before a resize happens.
    // const resizeObserver = new ResizeObserver(
    //   ( entries ) => {
    //
    //     for ( const entry of entries ) {
    //       console.info(entry)
    //       const iframe = container.querySelector('iframe');
    //       if (iframe) {
    //         console.info('offsetHeight', iframe.offsetHeight)
    //       }
    //
    //       console.info(  entry.contentBoxSize, entry.contentRect.height )
    //       if ( entry.contentRect.height > 0 ) {
    //         //console.info(  entry.contentBoxSize, entry.contentRect )
    //
    //         // resolveWithResolution();
    //         break;
    //       }
    //     }
    //   }
    // );
    // resizeObserver.observe( container );

    // Start listening for DOM changes, and stop once a 2.5-second pause is encountered.
    let resolveTimeoutId = 0;
    const mutationObserver = new MutationObserver(() => {
      clearTimeout(resolveTimeoutId);

      const complete = () => {
        mutationObserver.disconnect();
        resolveWithResolution();
      };

      resolveTimeoutId = setTimeout(complete, 2500);
    });
    mutationObserver.observe(container, {
      subtree: true,
      childList: true,
      attributes: true
    });
  });
}
<|endoftext|>


<commit_before>(function (module, undefined) {

  function getStyle(element, property) {
    return window.getComputedStyle(element)[property];
  }

  function height(element) {
    return element.clientHeight - parseFloat(getStyle(element, 'paddingTop')) - parseFloat(getStyle(element, 'paddingBottom'));
  }

  function trim(str) {
    return (str || '').replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, ''); // from jQuery
  }

  function getHTMLInRange(node, startIndex, endIndex) {
    var index, childNode;
    var childNodes = node.childNodes,
        length = childNodes.length,
        html = '';

    for (index = startIndex; index <= endIndex && index < length; index++) {
      childNode = childNodes[index];
      if (childNode.nodeType === childNode.COMMENT_NODE) {
        html += '';
      } else {
        html += childNode.outerHTML || childNode.nodeValue;
      }
    }
    return html;
  }

  // Truncate text node using binary search
  function truncateTextNode(textNode, rootNode, options) {
    var originalHTML = textNode.nodeValue,
        mid,
        low = 0,
        high = originalHTML.length,
        chunk,
        maxChunk = '';

    // Binary Search
    while (low <= high) {
      mid = low + ((high - low) >> 1); // Integer division

      chunk = trim(originalHTML.substr(0, mid + 1)) + options.showMore;
      textNode.nodeValue = chunk;

      if (height(rootNode) > options.maxHeight) {
        high = mid - 1;
      } else {
        low = mid + 1;
        maxChunk = maxChunk.length > chunk.length ? maxChunk : chunk;
      }
    }

    textNode.nodeValue = maxChunk;
  }

  function truncateNestedNode(element, rootNode, options) {

    var childNodes = element.childNodes,
        length = childNodes.length;

    if (length === 0) {

      // Base case: single element remaining

      if (element.nodeType === element.TEXT_NODE) {
        // Truncate the text node
        truncateTextNode(element, rootNode, options);
      } else {
        // Remove the node itself
        element.parentNode.removeChild(element);
      }

      return;

    } else {

      // Recursive case: iterate backwards on children nodes until tipping node is found

      var index, node, chunk;
      var originalHTML = element.innerHTML;

      for (index = length - 1; index >= 0; index--) {
        node = childNodes[index];

        chunk = getHTMLInRange(element, 0, index);
        element.innerHTML = chunk;

        if (height(rootNode) <= options.maxHeight) {

          // Check if element is not the last child
          if (index + 1 <= length - 1) {
            // Reset HTML so original childNodes tree is available
            element.innerHTML = originalHTML;

            chunk += getHTMLInRange(element, index + 1, index + 1);
            element.innerHTML = chunk;

            index += 1;
          }

          return truncateNestedNode(childNodes[index], rootNode, options);
        }
      }

      return truncateNestedNode(childNodes[0], rootNode, options);

    }
  }

  /* Public: Creates an instance of Truncate.
   *
   * element - A DOM element to be truncated.
   * options - An Object literal containing setup options.
   *
   * Examples:
   *
   *   var element = document.createElement('span');
   *   element.innerHTML = 'This is
odd.';
   *   var truncated = new Truncate(element, {
   *     lines: 1,
   *     lineHeight: 16,
   *     showMore: 'Show More',
   *     showLess: 'Show Less'
   *   });
   *
   *   // Update HTML
   *   truncated.update('This is not very odd.');
   *
   *   // Undo truncation
   *   truncated.expand();
   *
   *   // Redo truncation
   *   truncated.collapse();
   */
  function Truncate(element, options) {
    this.options = options || {};
    options.showMore = typeof options.showMore !== 'undefined' ? options.showMore : '…';
    options.showLess = typeof options.showLess !== 'undefined' ? options.showLess : '';

    this.options.maxHeight = options.lines * options.lineHeight;

    this.element = element;
    this.originalHTML = element.innerHTML;
    this.cachedHTML = null;

    this.update();
  }

  Truncate.prototype.update = function (newHTML) {
    // Update HTML if provided, otherwise default to current inner HTML.
    if (newHTML) {
      this.originalHTML = this.element.innerHTML = newHTML;
    }

    // Already meets height requirement
    if (height(this.element) <= this.options.maxHeight) {
      return;
    }

    var visibility = this.element.style.visibility;
    this.element.style.visibility = 'hidden';

    truncateNestedNode(this.element, this.element, this.options);
    this.cachedHTML = this.element.innerHTML;

    this.element.style.visibility = visibility;
  };

  Truncate.prototype.expand = function () {
    this.element.innerHTML = this.originalHTML + this.options.showLess;
  };

  Truncate.prototype.collapse = function () {
    this.element.innerHTML = this.cachedHTML;
  };

  module.Truncate = Truncate;

})(this);
<commit_msg>More comments<commit_after>(function (module, undefined) {

  function getStyle(element, property) {
    return window.getComputedStyle(element)[property];
  }

  function height(element) {
    return element.clientHeight - parseFloat(getStyle(element, 'paddingTop')) - parseFloat(getStyle(element, 'paddingBottom'));
  }

  function trim(str) {
    return (str || '').replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g, ''); // from jQuery
  }

  function getHTMLInRange(node, startIndex, endIndex) {
    var index, childNode;
    var childNodes = node.childNodes,
        length = childNodes.length,
        html = '';

    for (index = startIndex; index <= endIndex && index < length; index++) {
      childNode = childNodes[index];
      if (childNode.nodeType === childNode.COMMENT_NODE) {
        // Need the commend node HTML in order to reconstruct original DOM structure
        // This manual way is the only way to get a comment node's HTML
        html += '';
      } else {
        html += childNode.outerHTML || childNode.nodeValue;
      }
    }
    return html;
  }

  // Truncate text node using binary search
  function truncateTextNode(textNode, rootNode, options) {
    var originalHTML = textNode.nodeValue,
        mid,
        low = 0,
        high = originalHTML.length,
        chunk,
        maxChunk = '';

    // Binary Search
    while (low <= high) {
      mid = low + ((high - low) >> 1); // Integer division

      chunk = trim(originalHTML.substr(0, mid + 1)) + options.showMore;
      textNode.nodeValue = chunk;

      if (height(rootNode) > options.maxHeight) {
        high = mid - 1;
      } else {
        low = mid + 1;
        maxChunk = maxChunk.length > chunk.length ? maxChunk : chunk;
      }
    }

    textNode.nodeValue = maxChunk;
  }

  function truncateNestedNode(element, rootNode, options) {

    var childNodes = element.childNodes,
        length = childNodes.length;

    if (length === 0) {

      // Base case: single element remaining

      if (element.nodeType === element.TEXT_NODE) {
        // Truncate the text node
        truncateTextNode(element, rootNode, options);
      } else {
        // Remove the node itself
        element.parentNode.removeChild(element);
      }

      return;

    } else {

      // Recursive case: iterate backwards on children nodes until tipping node is found

      var index, node, chunk;
      var originalHTML = element.innerHTML;

      for (index = length - 1; index >= 0; index--) {
        node = childNodes[index];

        chunk = getHTMLInRange(element, 0, index);
        element.innerHTML = chunk;

        if (height(rootNode) <= options.maxHeight) {

          // Check if element is not the last child
          if (index + 1 <= length - 1) {
            // Reset HTML so original childNodes tree is available
            element.innerHTML = originalHTML;

            chunk += getHTMLInRange(element, index + 1, index + 1);
            element.innerHTML = chunk;

            index += 1;
          }

          return truncateNestedNode(childNodes[index], rootNode, options);
        }
      }

      return truncateNestedNode(childNodes[0], rootNode, options);

    }
  }

  /* Public: Creates an instance of Truncate.
   *
   * element - A DOM element to be truncated.
   * options - An Object literal containing setup options.
   *
   * Examples:
   *
   *   var element = document.createElement('span');
   *   element.innerHTML = 'This is
odd.';
   *   var truncated = new Truncate(element, {
   *     lines: 1,
   *     lineHeight: 16,
   *     showMore: 'Show More',
   *     showLess: 'Show Less'
   *   });
   *
   *   // Update HTML
   *   truncated.update('This is not very odd.');
   *
   *   // Undo truncation
   *   truncated.expand();
   *
   *   // Redo truncation
   *   truncated.collapse();
   */
  function Truncate(element, options) {
    this.options = options || {};
    options.showMore = typeof options.showMore !== 'undefined' ? options.showMore : '…';
    options.showLess = typeof options.showLess !== 'undefined' ? options.showLess : '';

    this.options.maxHeight = options.lines * options.lineHeight;

    this.element = element;
    this.originalHTML = element.innerHTML;
    this.cachedHTML = null;

    this.update();
  }

  Truncate.prototype.update = function (newHTML) {
    // Update HTML if provided, otherwise default to current inner HTML.
    if (newHTML) {
      this.originalHTML = this.element.innerHTML = newHTML;
    }

    // Already meets height requirement
    if (height(this.element) <= this.options.maxHeight) {
      return;
    }

    var visibility = this.element.style.visibility;
    this.element.style.visibility = 'hidden';

    truncateNestedNode(this.element, this.element, this.options);
    this.cachedHTML = this.element.innerHTML;

    this.element.style.visibility = visibility;
  };

  Truncate.prototype.expand = function () {
    this.element.innerHTML = this.originalHTML + this.options.showLess;
  };

  Truncate.prototype.collapse = function () {
    this.element.innerHTML = this.cachedHTML;
  };

  module.Truncate = Truncate;

})(this);
<|endoftext|>


<commit_before>var players = [];
var guardians = [];
var frogStatus = 0;
var kingStrength = 100; //can use this to extrapolate enemy strength.
var queenStrength = 100;
var jackStrength = 50;
var hardStrength = 250;  //what consititutes a  'hard' game.
var democracyStrength = 0;
var queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
var reckoningStarted = false; //can't god tier if you are definitely on skaia.
var ectoBiologyStarted = false;
var doomedTimeline = false;
var scratched = false;
var debugMode = false;
var introScene;
var currentSceneNum = 0;
var spriteWidth = 400;
var spriteHeight = 300;
var canvasWidth = 1000;
var canvasHeight = 300;
var repeatTime = 500;
var version2 = true;
var timeTillReckoning = getRandomInt(10,30);
//have EVERYTHING be a scene, don't put any story in v2.0's controller
//every scene can update the narration, or the canvas.
//should there be only one canvas?  Can have player sprites be written to a virtual canvas first, then copied to main one.
//main canvas is either Leader + PesterChumWindow + 1 or more Players (in chat or group chat with leader)
//or Leader + 1 or more Players  (leader doing bullshit side quests with someone)
window.onload = function() {
   init();
	if(!debugMode){
		randomizeEntryOrder();
	}
	//easter egg ^_^
	if(window.location.search.substr(1) == "royalRumble=true"){
		debugRoyalRumble();
	}
	//authorMessage();
	makeGuardians(); //after entry order established
	load(players, guardians); //in loading.js

	//intro();  //~~~~~~LOADING SCRIPT WILL CALL THIS~~~~~~~~~

	//debugRelationshipDrama();
	//debugTriggerLevel();
	//debugGrimDark();
	//debugJackScheme();
	//debugLevelTheHellUp();
	//debugGodTierLevelTheHellUp();
	//debugCorpseLevelTheHellUp();
	//debugGodTierRevive();
	//debugCorpseSmooch();

	//make a new intro scene that has characters talk about their lands with their best friends/worst enemies.
	//refacor other scenario controller to use special scenes (not part of scene controller) rather than
	//have messy internal methods.
	//all other scenes are handled through the scene controller like normal, which will check if var version2 = true;
	//and if so will call "render" rather than "content"

	//tick();  dont tick here, tick after intro
}

function renderScratchButton(){
	//alert("scratch [possible]");
	//can't scratch if it was a a total party wipe. just a regular doomed timeline.
	var living = findLivingPlayers(players);
	if(living.length > 0){
		var timePlayer = findAspectPlayer(players, "Time");
		if(!scratched){
			alert(living.length  + " living players and the " + timePlayer.land + " makes a scratch available!");
			var html = '<button type="button" onclick="scratchConfirm()">Would You Like To Scratch Session?</button>';
			$("#story").append(html);
		}else{
			$("#story").append("
This session is already scratched. No further scratches available.");
		}
	}
}

function scratchConfirm(){
	var scratchConfirmed = confirm("This session is doomed. Scratching this session will erase it. A new session will be generated, but you will no longer be able to view this session. Is this okay?");
	if(scratchConfirmed){
		scratch();
	}
}

//TODO if i wanted to, I could have mixed sessions like in canon.
//not erasing the players, after all.
//or could have an afterlife where they meet guardian players???
function scratch(){
	timeTillReckoning = getRandomInt(10,30);
	frogStatus = 0;
	kingStrength = 100; //can use this to extrapolate enemy strength.
	queenStrength = 100;
	jackStrength = 50;
	hardStrength = 250;  //what consititutes a  'hard' game.
	democracyStrength = 0;
	queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
	reckoningStarted = false; //can't god tier if you are definitely on skaia.
	//ectobiology not reset. if performed in previous session, it's done.
	//if not, it's not. like how the alpha session trolls didn't perform ectobiology, so Karkat did.
  doomedTimeline = false;
	scratched = true;
	var scratch = "The session has been scratched. The " + getPlayersTitlesBasic(players) + " will now be the beloved guardians.";
  scratch += " Their former guardians, the " + getPlayersTitlesBasic(guardians) + " will now be the players.";
	scratch += " The new players will be given stat boosts to give them a better chance than the previous generation."
	scratch += " What will happen?"
	var tmp = players;
	players = guardians;
	guardians = tmp;
	$("#story").html(scratch);
	window.scrollTo(0, 0);

	var guardianDiv = newScene();
	var guardianID = (guardianDiv.attr("id")) + "_guardians" ;
	var ch = canvasHeight;
	if(guardians.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + guardianID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	guardianDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ guardianID);
	poseAsATeam(canvasDiv, guardians, 2000); //everybody, even corpses, pose as a team.

	var playerDiv = newScene();
	var playerID = (playerDiv.attr("id")) + "_players" ;
	var ch = canvasHeight;
	if(players.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + playerID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	playerDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ playerID);
	poseAsATeam(canvasDiv, players, 2000); //everybody, even corpses, pose as a team.

	intro();

}

function tick(){
	if(timeTillReckoning > 0 && !doomedTimeline){
		setTimeout(function(){
			timeTillReckoning += -1;
			processScenes2(players);
			tick();
		},repeatTime); //or availablePlayers.length * *1000?
	}else{

		reckoning();
	}
}

function reckoning(){
	var s = new Reckoning();
	s.trigger(players)
	s.renderContent(newScene());
	if(!doomedTimeline){
		reckoningTick();
	}
}

function reckoningTick(){
	if(timeTillReckoning > -10){
		setTimeout(function(){
			timeTillReckoning += -1;
			processReckoning2(players)
			reckoningTick();
		},repeatTime);
	}else{
		var s = new Aftermath();
		s.trigger(players)
		s.renderContent(newScene());
	}

}

//scenes call this
function chatLine(start, player, line){
  if(player.grimDark == true){
    return start + line.trim()+"\n"; //no whimsy for grim dark players
  }else{
    return start + player.quirk.translate(line).trim()+"\n";
  }
}

function newScene(){
	currentSceneNum ++;
	var div = "

";
	$("#story").append(div);
	return $("#scene"+currentSceneNum);
}

function authorMessage(){
	makeAuthorAvatar();
	introScene = new AuthorMessage();
	introScene.trigger(players, players[0])
	introScene.renderContent(newScene(),0); //new scenes take care of displaying on their own.
}

function callNextIntroWithDelay(player_index){
	if(player_index >= players.length){
    tick();//NOW start ticking
		return;
	}
	setTimeout(function(){
		var s = new Intro();
		var p = players[player_index];
		var playersInMedium = players.slice(0, player_index+1); //anybody past me isn't in the medium, yet.
		s.trigger(playersInMedium, p)
		s.renderContent(newScene(),player_index); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
		player_index += 1;
		callNextIntroWithDelay(player_index)
	},  repeatTime);  //want all players to be done with their setTimeOuts players.length*1000+2000
}

function intro(){
  //delay is needed here because this is when images are first loaded.
	callNextIntroWithDelay(0);
  /* //
	introScene = new Intro();

	for(var i = 0; i<players.length; i++){
		var playersInMedium = players.slice(0, i+1); //anybody past me isn't in the medium, yet.
		var p = players[i];
		introScene.trigger(players, p)
		//$("#story").append(introScene.content());
		introScene.renderContent(newScene(),i); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
	}*/

}

function randomizeEntryOrder(){
	players = shuffle(players);
	players[0].leader = true;
}

function makeAuthorAvatar(){
	players[0].grimDark = false;
	players[0].aspect = "Mind"
	players[0].class_name = "Maid"
	players[0].hair = 13;
	players[0].hairColor = "#291200";
	players[0].quirk.punctuation = 3;
	players[0].quirk.capitalization = 1;
	players[0].quirk.favoriteNumber = 3;
	players[0].chatHandle = "jadedResearcher"
	players[0].isTroll = false
	players[0].bloodColor = "#ff0000"
	players[0].mylevels = ["INSTEAD","a CORPSE JUST RENDERS HERE","STILL CAN LEVEL UP.","OH, AND CORPSES.","SAME LEVELS","BUT STILL HAVE","IMAGE","THEY GET A DIFFERENT","BEFORE MAXING OUT","IF THEY GODTIER","AND GO UP THE LADDER","LEVELS NOW","16 PREDETERMINED","HAVE","PLAYERS","I FINISHED ECHELADDERS."];
}

function decideHemoCaste(player){
	if(player.aspect != "Blood"){  //sorry karkat
		player.bloodColor = getRandomElementFromArray(bloodColors);
	}
}

function decideLusus(player){
	if(player.bloodColor == "#610061" || player.bloodColor == "#99004d" || players.bloodColor == "#631db4" ){
		player.lusus = getRandomElementFromArray(seaLususTypes);
	}else{
		player.lusus = getRandomElementFromArray(landlususTypes);
	}
}

function decideTroll(player){
	if(Math.random() > 0.55 ){
		player.isTroll = true;
		player.triggerLevel ++;//trolls are less stable
		decideHemoCaste(player);
		decideLusus(player);
		player.kernel_sprite = player.lusus;
	}
}
//species, hair and blood color is the same, horns and favorite number. aspect.  Thats it.
//when scratch, get rid of story dif. make blank. scratch has to be button press.
function makeGuardians(){
	//console.log("Making guardians")
	available_classes = classes.slice(0);
	available_aspects = nonrequired_aspects.slice(0); //required_aspects
	available_aspects = available_aspects.concat(required_aspects.slice(0));
	for(var i = 0; i<players.length; i++){
		  var player = players[i];
			//console.log("guardian for " + player.titleBasic());
			var guardian = randomPlayerWithoutRemoving();
			guardian.isTroll = player.isTroll;
			if(guardian.isTroll){
				guardian.quirk = randomTrollSim(guardian)
			}else{
				guardian.quirk = randomHumanSim(guardian);
			}
			guardian.quirk.favoriteNumber = player.quirk.favoriteNumber;
			guardian.bloodColor = player.bloodColor;
			guardian.lusus = player.lusus;
			guardian.hairColor = player.hairColor;
			guardian.aspect = player.aspect;
			guardian.leftHorn = player.leftHorn;
			guardian.rightHorn = player.rightHorn;
			guardian.level_index = 5; //scratched kids start more leveled up
			guardian.power = 50;
			guardian.leader = player.leader;
			if(Math.random() >0.5){ //have SOMETHING in common with your ectorelative.
				guardian.interest1 = player.interest1;
			}else{
				guardian.interest2 = player.interest2;
			}
			guardian.reinit();//redo levels and land based on real aspect
			guardians.push(guardian);
	}

	for(var j = 0; j<guardians.length; j++){
		var g = guardians[j];
		g.generateRelationships(guardians);
	}
}

function init(){
	available_classes = classes.slice(0); //re-init available classes.
	available_aspects = nonrequired_aspects.slice(0);
	var numPlayers = getRandomInt(2,12);
	players.push(randomSpacePlayer());
	players.push(randomTimePlayer());

	for(var i = 2; i<numPlayers; i++){
		players.push(randomPlayer());
	}

	for(var j = 0; j<players.length; j++){
		var p = players[j];
		decideTroll(p);
		p.generateRelationships(players);
		if(p.isTroll){
			p.quirk = randomTrollSim(p)
		}else{
			p.quirk = randomHumanSim(p);
		}
	}

}
<commit_msg>classes shouldn't be able to be repeated in scratched sessions anymore<commit_after>var players = [];
var guardians = [];
var frogStatus = 0;
var kingStrength = 100; //can use this to extrapolate enemy strength.
var queenStrength = 100;
var jackStrength = 50;
var hardStrength = 250;  //what consititutes a  'hard' game.
var democracyStrength = 0;
var queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
var reckoningStarted = false; //can't god tier if you are definitely on skaia.
var ectoBiologyStarted = false;
var doomedTimeline = false;
var scratched = false;
var debugMode = false;
var introScene;
var currentSceneNum = 0;
var spriteWidth = 400;
var spriteHeight = 300;
var canvasWidth = 1000;
var canvasHeight = 300;
var repeatTime = 500;
var version2 = true;
var timeTillReckoning = getRandomInt(10,30);
//have EVERYTHING be a scene, don't put any story in v2.0's controller
//every scene can update the narration, or the canvas.
//should there be only one canvas?  Can have player sprites be written to a virtual canvas first, then copied to main one.
//main canvas is either Leader + PesterChumWindow + 1 or more Players (in chat or group chat with leader)
//or Leader + 1 or more Players  (leader doing bullshit side quests with someone)
window.onload = function() {
   init();
	if(!debugMode){
		randomizeEntryOrder();
	}
	//easter egg ^_^
	if(window.location.search.substr(1) == "royalRumble=true"){
		debugRoyalRumble();
	}
	//authorMessage();
	makeGuardians(); //after entry order established
	load(players, guardians); //in loading.js

	//intro();  //~~~~~~LOADING SCRIPT WILL CALL THIS~~~~~~~~~

	//debugRelationshipDrama();
	//debugTriggerLevel();
	//debugGrimDark();
	//debugJackScheme();
	//debugLevelTheHellUp();
	//debugGodTierLevelTheHellUp();
	//debugCorpseLevelTheHellUp();
	//debugGodTierRevive();
	//debugCorpseSmooch();

	//make a new intro scene that has characters talk about their lands with their best friends/worst enemies.
	//refacor other scenario controller to use special scenes (not part of scene controller) rather than
	//have messy internal methods.
	//all other scenes are handled through the scene controller like normal, which will check if var version2 = true;
	//and if so will call "render" rather than "content"

	//tick();  dont tick here, tick after intro
}

function renderScratchButton(){
	//alert("scratch [possible]");
	//can't scratch if it was a a total party wipe. just a regular doomed timeline.
	var living = findLivingPlayers(players);
	if(living.length > 0){
		var timePlayer = findAspectPlayer(players, "Time");
		if(!scratched){
			alert(living.length  + " living players and the " + timePlayer.land + " makes a scratch available!");
			var html = '<button type="button" onclick="scratchConfirm()">Would You Like To Scratch Session?</button>';
			$("#story").append(html);
		}else{
			$("#story").append("
This session is already scratched. No further scratches available.");
		}
	}
}

function scratchConfirm(){
	var scratchConfirmed = confirm("This session is doomed. Scratching this session will erase it. A new session will be generated, but you will no longer be able to view this session. Is this okay?");
	if(scratchConfirmed){
		scratch();
	}
}

//TODO if i wanted to, I could have mixed sessions like in canon.
//not erasing the players, after all.
//or could have an afterlife where they meet guardian players???
function scratch(){
	timeTillReckoning = getRandomInt(10,30);
	frogStatus = 0;
	kingStrength = 100; //can use this to extrapolate enemy strength.
	queenStrength = 100;
	jackStrength = 50;
	hardStrength = 250;  //what consititutes a  'hard' game.
	democracyStrength = 0;
	queenUncrowned = false;  //if she loses her ring, she doesn't get stronger with further prototypes
	reckoningStarted = false; //can't god tier if you are definitely on skaia.
	//ectobiology not reset. if performed in previous session, it's done.
	//if not, it's not. like how the alpha session trolls didn't perform ectobiology, so Karkat did.
	doomedTimeline = false;
	scratched = true;
	var scratch = "The session has been scratched. The " + getPlayersTitlesBasic(players) + " will now be the beloved guardians.";
	scratch += " Their former guardians, the " + getPlayersTitlesBasic(guardians) + " will now be the players.";
	scratch += " The new players will be given stat boosts to give them a better chance than the previous generation."
	scratch += " What will happen?"
	var tmp = players;
	players = guardians;
	guardians = tmp;
	$("#story").html(scratch);
	window.scrollTo(0, 0);

	var guardianDiv = newScene();
	var guardianID = (guardianDiv.attr("id")) + "_guardians" ;
	var ch = canvasHeight;
	if(guardians.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + guardianID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	guardianDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ guardianID);
	poseAsATeam(canvasDiv, guardians, 2000); //everybody, even corpses, pose as a team.

	var playerDiv = newScene();
	var playerID = (playerDiv.attr("id")) + "_players" ;
	var ch = canvasHeight;
	if(players.length > 6){
		ch = canvasHeight*1.5; //a little bigger than two rows, cause time clones
	}
	var canvasHTML = "
<canvas id='canvas" + playerID+"' width='" +canvasWidth + "' height="+ch + "'>  </canvas>";

	playerDiv.append(canvasHTML);
	var canvasDiv = document.getElementById("canvas"+ playerID);
	poseAsATeam(canvasDiv, players, 2000); //everybody, even corpses, pose as a team.

	intro();

}

function tick(){
	if(timeTillReckoning > 0 && !doomedTimeline){
		setTimeout(function(){
			timeTillReckoning += -1;
			processScenes2(players);
			tick();
		},repeatTime); //or availablePlayers.length * *1000?
	}else{

		reckoning();
	}
}

function reckoning(){
	var s = new Reckoning();
	s.trigger(players)
	s.renderContent(newScene());
	if(!doomedTimeline){
		reckoningTick();
	}
}

function reckoningTick(){
	if(timeTillReckoning > -10){
		setTimeout(function(){
			timeTillReckoning += -1;
			processReckoning2(players)
			reckoningTick();
		},repeatTime);
	}else{
		var s = new Aftermath();
		s.trigger(players)
		s.renderContent(newScene());
	}

}

//scenes call this
function chatLine(start, player, line){
  if(player.grimDark == true){
    return start + line.trim()+"\n"; //no whimsy for grim dark players
  }else{
    return start + player.quirk.translate(line).trim()+"\n";
  }
}

function newScene(){
	currentSceneNum ++;
	var div = "

";
	$("#story").append(div);
	return $("#scene"+currentSceneNum);
}

function authorMessage(){
	makeAuthorAvatar();
	introScene = new AuthorMessage();
	introScene.trigger(players, players[0])
	introScene.renderContent(newScene(),0); //new scenes take care of displaying on their own.
}

function callNextIntroWithDelay(player_index){
	if(player_index >= players.length){
    tick();//NOW start ticking
		return;
	}
	setTimeout(function(){
		var s = new Intro();
		var p = players[player_index];
		var playersInMedium = players.slice(0, player_index+1); //anybody past me isn't in the medium, yet.
		s.trigger(playersInMedium, p)
		s.renderContent(newScene(),player_index); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
		player_index += 1;
		callNextIntroWithDelay(player_index)
	},  repeatTime);  //want all players to be done with their setTimeOuts players.length*1000+2000
}

function intro(){
  //delay is needed here because this is when images are first loaded.
	callNextIntroWithDelay(0);
  /* //
	introScene = new Intro();

	for(var i = 0; i<players.length; i++){
		var playersInMedium = players.slice(0, i+1); //anybody past me isn't in the medium, yet.
		var p = players[i];
		introScene.trigger(players, p)
		//$("#story").append(introScene.content());
		introScene.renderContent(newScene(),i); //new scenes take care of displaying on their own.
		processScenes2(playersInMedium);
	}*/

}

function randomizeEntryOrder(){
	players = shuffle(players);
	players[0].leader = true;
}

function makeAuthorAvatar(){
	players[0].grimDark = false;
	players[0].aspect = "Mind"
	players[0].class_name = "Maid"
	players[0].hair = 13;
	players[0].hairColor = "#291200";
	players[0].quirk.punctuation = 3;
	players[0].quirk.capitalization = 1;
	players[0].quirk.favoriteNumber = 3;
	players[0].chatHandle = "jadedResearcher"
	players[0].isTroll = false
	players[0].bloodColor = "#ff0000"
	players[0].mylevels = ["INSTEAD","a CORPSE JUST RENDERS HERE","STILL CAN LEVEL UP.","OH, AND CORPSES.","SAME LEVELS","BUT STILL HAVE","IMAGE","THEY GET A DIFFERENT","BEFORE MAXING OUT","IF THEY GODTIER","AND GO UP THE LADDER","LEVELS NOW","16 PREDETERMINED","HAVE","PLAYERS","I FINISHED ECHELADDERS."];
}

function decideHemoCaste(player){
	if(player.aspect != "Blood"){  //sorry karkat
		player.bloodColor = getRandomElementFromArray(bloodColors);
	}
}

function decideLusus(player){
	if(player.bloodColor == "#610061" || player.bloodColor == "#99004d" || players.bloodColor == "#631db4" ){
		player.lusus = getRandomElementFromArray(seaLususTypes);
	}else{
		player.lusus = getRandomElementFromArray(landlususTypes);
	}
}

function decideTroll(player){
	if(Math.random() > 0.55 ){
		player.isTroll = true;
		player.triggerLevel ++;//trolls are less stable
		decideHemoCaste(player);
		decideLusus(player);
		player.kernel_sprite = player.lusus;
	}
}
//species, hair and blood color is the same, horns and favorite number. aspect.  Thats it.
//when scratch, get rid of story dif. make blank. scratch has to be button press.
function makeGuardians(){
	//console.log("Making guardians")
	available_classes = classes.slice(0);
	available_aspects = nonrequired_aspects.slice(0); //required_aspects
	available_aspects = available_aspects.concat(required_aspects.slice(0));
	for(var i = 0; i<players.length; i++){
		  var player = players[i];
			//console.log("guardian for " + player.titleBasic());
			var guardian = randomPlayer();
			guardian.isTroll = player.isTroll;
			if(guardian.isTroll){
				guardian.quirk = randomTrollSim(guardian)
			}else{
				guardian.quirk = randomHumanSim(guardian);
			}
			guardian.quirk.favoriteNumber = player.quirk.favoriteNumber;
			guardian.bloodColor = player.bloodColor;
			guardian.lusus = player.lusus;
			guardian.hairColor = player.hairColor;
			guardian.aspect = player.aspect;
			guardian.leftHorn = player.leftHorn;
			guardian.rightHorn = player.rightHorn;
			guardian.level_index = 5; //scratched kids start more leveled up
			guardian.power = 50;
			guardian.leader = player.leader;
			if(Math.random() >0.5){ //have SOMETHING in common with your ectorelative.
				guardian.interest1 = player.interest1;
			}else{
				guardian.interest2 = player.interest2;
			}
			guardian.reinit();//redo levels and land based on real aspect
			guardians.push(guardian);
	}

	for(var j = 0; j<guardians.length; j++){
		var g = guardians[j];
		g.generateRelationships(guardians);
	}
}

function init(){
	available_classes = classes.slice(0); //re-init available classes.
	available_aspects = nonrequired_aspects.slice(0);
	var numPlayers = getRandomInt(2,12);
	players.push(randomSpacePlayer());
	players.push(randomTimePlayer());

	for(var i = 2; i<numPlayers; i++){
		players.push(randomPlayer());
	}

	for(var j = 0; j<players.length; j++){
		var p = players[j];
		decideTroll(p);
		p.generateRelationships(players);
		if(p.isTroll){
			p.quirk = randomTrollSim(p)
		}else{
			p.quirk = randomHumanSim(p);
		}
	}

}
<|endoftext|>


<commit_before>import Ember from 'ember'
const {$, RSVP} = Ember
import {validate} from 'bunsen-core/actions'

import {PropTypes} from 'ember-prop-types'
import DetailComponent from './detail'
import layout from 'ember-frost-bunsen/templates/components/frost-bunsen-form'

export default DetailComponent.extend({
  // == Component Properties ===================================================

  layout,

  // == State Properties =======================================================

  propTypes: {
    autofocus: PropTypes.bool,
    bunsenModel: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.object
    ]).isRequired,
    bunsenView: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.object
    ]),
    disabled: PropTypes.bool,
    hook: PropTypes.string,
    onChange: PropTypes.func,
    onError: PropTypes.func,
    onValidation: PropTypes.func,
    registeredComponents: PropTypes.array,
    renderers: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.object
    ]),
    showAllErrors: PropTypes.bool,
    validators: PropTypes.array,
    value: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.null,
      PropTypes.object
    ])
  },

  getDefaultProps () {
    return {
      autofocus: true,
      classNames: ['frost-bunsen-form'],
      disabled: false,
      hook: 'bunsenForm',
      renderers: {},
      registeredComponents: [],
      showAllErrors: false,
      validators: [],
      value: null
    }
  },

  // == Functions ==============================================================

  /**
   * After render select first input unless something else already has focus on page
   */
  didRender () {
    if (!this.get('autofocus')) {
      return
    }

    // If there is already an element in focus do nothing
    if ($(':focus').length !== 0) {
      return
    }

    // Focus on first input in busen form
    this.$(':input:enabled:visible:first').focus()
  },

  // == Actions ================================================================

  actions: {
    /**
     * Handle when user updates form value
     * @param {String} bunsenId - ID of input that changed
     * @param {Object} inputValue - new value for input that changed
     */
    handleChange (bunsenId, inputValue) {
      const reduxStore = this.get('reduxStore')

      reduxStore.dispatch(
        validate(bunsenId, inputValue, this.get('renderModel'), this.get('validators'), RSVP.all)
      )
    }
  }
})
<commit_msg>Add visibility API to re-trigger validation<commit_after>import Ember from 'ember'
const {$, RSVP} = Ember
import {validate} from 'bunsen-core/actions'

import {PropTypes} from 'ember-prop-types'
import DetailComponent from './detail'
import layout from 'ember-frost-bunsen/templates/components/frost-bunsen-form'

export default DetailComponent.extend({
  // == Component Properties ===================================================

  layout,

  // == State Properties =======================================================

  propTypes: {
    autofocus: PropTypes.bool,
    bunsenModel: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.object
    ]).isRequired,
    bunsenView: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.object
    ]),
    disabled: PropTypes.bool,
    hook: PropTypes.string,
    onChange: PropTypes.func,
    onError: PropTypes.func,
    onValidation: PropTypes.func,
    registeredComponents: PropTypes.array,
    renderers: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.object
    ]),
    showAllErrors: PropTypes.bool,
    validators: PropTypes.array,
    value: PropTypes.oneOfType([
      PropTypes.EmberObject,
      PropTypes.null,
      PropTypes.object
    ])
  },

  getDefaultProps () {
    return {
      autofocus: true,
      classNames: ['frost-bunsen-form'],
      disabled: false,
      hook: 'bunsenForm',
      renderers: {},
      registeredComponents: [],
      showAllErrors: false,
      validators: [],
      value: null
    }
  },

  // == Functions ==============================================================

  _onVisiblityChange (e) {
    // Nothing to do when page/tab loses visiblity
    if (e.target.hidden) {
      return
    }

    const model = this.get('renderModel')
    const reduxStore = this.get('reduxStore')
    const validators = this.get('validators')
    const value = this.get('renderValue')

    reduxStore.dispatch(
      validate(null, value, model, validators, RSVP.all)
    )
  },

  // == Events =================================================================

  didInsertElement () {
    this._visibilityChangeHandler = this._onVisiblityChange.bind(this)
    document.addEventListener('visibilitychange', this._visibilityChangeHandler, false)
  },

  /**
   * After render select first input unless something else already has focus on page
   */
  didRender () {
    if (!this.get('autofocus')) {
      return
    }

    // If there is already an element in focus do nothing
    if ($(':focus').length !== 0) {
      return
    }

    // Focus on first input in busen form
    this.$(':input:enabled:visible:first').focus()
  },

  willDestroyElement () {
    document.removeEventListener('visibilitychange', this._visibilityChangeHandler)
  },

  // == Actions ================================================================

  actions: {
    /**
     * Handle when user updates form value
     * @param {String} bunsenId - ID of input that changed
     * @param {Object} inputValue - new value for input that changed
     */
    handleChange (bunsenId, inputValue) {
      const reduxStore = this.get('reduxStore')

      reduxStore.dispatch(
        validate(bunsenId, inputValue, this.get('renderModel'), this.get('validators'), RSVP.all)
      )
    }
  }
})
<|endoftext|>