<commit_before>const googlemaps = {
	provider_name: "maps.google.com",
	endpoints: [{
		schemes: [/.*google\.[^/]+\/maps\/place\/.+/],
		builder: function(urlObj, obj) {
			var match = /.*google\.[^/]+\/maps\/place\/([\w+]*)\/.*/.exec(urlObj.href);
			if (!match || match.length != 2) return;
			var place = encodeURIComponent(match[1]);
			obj.type = "embed";
			obj.html = `<iframe src="//maps.google.com/maps?t=m&q=${place}&output=embed"></iframe>`;
		}
	}]
};

const youtube = {
	provider_name: "youtube.com",
	endpoints: [{
		schemes: [
			'https://*.youtube.com/v/*',
			'https://*.youtube.com/embed/*',
			'https://youtu.be/*'
		],
		url: 'https://www.youtube.com/oembed', // TODO ?maxwidth=1024&maxheight=1024
		redirect: function(obj) {
			if (obj.pathname == "/watch") return;
			var videoId;
			if (obj.pathname.startsWith("/embed/")) {
				videoId = obj.pathname.split('/').pop();
			} else if (obj.hostname == "youtu.be") {
				videoId = obj.pathname.substring(1);
			}
			if (!videoId) return;
			delete obj.href;
			delete obj.pathname;
			delete obj.search;
			delete obj.query;
			obj.path = "/watch?v=" + encodeURIComponent(videoId);
			obj.hostname = "www.youtube.com";
			return true;
		}
	}]
};

const twitter = {
	provider_name: "twitter.com",
	endpoints: [{
		schemes: [
			'https://twitter.com/*/status/*'
		],
		redirect: function(obj) {
			return true;
		}
	}]
};

const instagram = {
	provider_name: "instagram.com",
	endpoints: [{
		schemes: [
			'https://www.instagram.com/*/*/'
		],
		redirect: function (obj) {
			obj.headers["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15";
			return true;
		}
	}]
};

module.exports = [googlemaps, youtube, twitter, instagram];

<commit_msg>Find date from twitter<commit_after>const googlemaps = {
	provider_name: "maps.google.com",
	endpoints: [{
		schemes: [/.*google\.[^/]+\/maps\/place\/.+/],
		builder: function(urlObj, obj) {
			var match = /.*google\.[^/]+\/maps\/place\/([\w+]*)\/.*/.exec(urlObj.href);
			if (!match || match.length != 2) return;
			var place = encodeURIComponent(match[1]);
			obj.type = "embed";
			obj.html = `<iframe src="//maps.google.com/maps?t=m&q=${place}&output=embed"></iframe>`;
		}
	}]
};

const youtube = {
	provider_name: "youtube.com",
	endpoints: [{
		schemes: [
			'https://*.youtube.com/v/*',
			'https://*.youtube.com/embed/*',
			'https://youtu.be/*'
		],
		url: 'https://www.youtube.com/oembed', // TODO ?maxwidth=1024&maxheight=1024
		redirect: function(obj) {
			if (obj.pathname == "/watch") return;
			var videoId;
			if (obj.pathname.startsWith("/embed/")) {
				videoId = obj.pathname.split('/').pop();
			} else if (obj.hostname == "youtu.be") {
				videoId = obj.pathname.substring(1);
			}
			if (!videoId) return;
			delete obj.href;
			delete obj.pathname;
			delete obj.search;
			delete obj.query;
			obj.path = "/watch?v=" + encodeURIComponent(videoId);
			obj.hostname = "www.youtube.com";
			return true;
		}
	}]
};

const twitter = {
	provider_name: "twitter.com",
	endpoints: [{
		schemes: [
			'https://twitter.com/*/status/*'
		],
		builder: function (urlObj, obj) {
			const reg = />(?<date>[\w,\s]+)<\/a><\/blockquote>/.exec(obj.html);
			if (reg) {
				const date = new Date(reg.groups.date);
				if (!Number.isNaN(date.getTime())) obj.date = date.toISOString();
			}
		},
		redirect: function(obj) {
			return true;
		}
	}]
};

const instagram = {
	provider_name: "instagram.com",
	endpoints: [{
		schemes: [
			'https://www.instagram.com/*/*/'
		],
		redirect: function (obj) {
			obj.headers["User-Agent"] = "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/13.0 Safari/605.1.15";
			return true;
		}
	}]
};

module.exports = [googlemaps, youtube, twitter, instagram];

<|endoftext|>


<commit_before>var pocketciv = require("../../core/pocketciv");
var pocketcivApp = angular.module('pocketcivApp', ['ngStorage']);
var runplay = require("../../core/runplay")

pp = pocketciv

function getMovement(areas) {
    return _.object(_.map(pocketciv.Map.areas, function (area, id) {
        return [id, area.tribes ? area.tribes : 0 ];
    }));
}

gameLog = {
    "move": [],
    "deck": [],
    "reduce": [],
    "areas": [],
    "advance": []
};

var scenarios = {
    "1": require("../scenarios/scenario1")
}

pocketcivApp.controller('MainGame', function ($scope, $localStorage) {
    $scope.$storage = $localStorage;
    $scope.map = pocketciv.Map;
    $scope.deck = pocketciv.EventDeck;

    var moveFunc = undefined;
    $scope.moveTribes = function() {
        var mover = new pocketciv.TribeMover(pocketciv.Map.areas);
        mover.init(getMovement(pocketciv.Map.areas));
        if (mover.ok($scope.movement))
        {
            console.log("OK MOVE!");
            moveFunc.call(pocketciv.Engine, $scope.movement);
            $scope.hideMover = true;
            gameLog.move.push($scope.movement)
        } else {
            console.log("FAILED MOVE")
        }
    }
    $scope.hideMover = true;

    var drawnFunc = undefined;
    $scope.hideDrawer = true;
    $scope.drawCard = function() {
        $scope.card = $scope.deck.draw();
        if ($scope.specificCard)
            $scope.card = pocketciv.EventDeck.specific($scope.specificCard);
        $scope.specificCard = undefined;
        $scope.hideDrawer = true;
        gameLog.deck.push($scope.card.id)
        drawnFunc && drawnFunc.call(pocketciv.Engine, $scope.card);
    }

    pocketciv.Engine.mover = function(situation, move) {
        console.log("Show mover")
        $scope.movement = getMovement(situation);
        $scope.hideMover = false;
        moveFunc = move;
    }

    var reduceFunc = undefined;
    $scope.hideReducer = true;
    pocketciv.Engine.reducer = function(reducer, done) {
        console.log("Show reducer")
        $scope.hideReducer = false;
        $scope.reducer = reducer;
        if (reducer.mode == 'Overall')
        {
            $scope.reduceArray = {};
            var areas = $scope.reducer.areas();
            _.each(areas, function(area) {
                $scope.reduceArray[area.id] = { 'tribes': 0 }
            });
            $scope.reduceAreas = areas;
        }
        else
            $scope.reduceArray = [];
        reduceFunc = done;
        checkReducer();
    }
    var checkReducer = function() {
        console.log('reduce array change')
        console.log($scope.reduceArray)
        if ($scope.hideReducer)
            return;
        var ok = $scope.reducer.ok($scope.reduceArray);
        if ($scope.reducer.mode == 'AreaWalker')
        {
            $scope.reduceAreas = ok.areas;
            if (! $scope.reduceAreas)
            {
                $scope.hideReducer = true;
                reduceFunc(ok);
                gameLog.reduce.push($scope.reduceArray)
            }
        } else {
            $scope.reducer.amount = ok.amount;
        }
    };
    $scope.reduceReady = function() {
        var arr = _.filter(_.keys($scope.reduceArray), function(k) {
            return $scope.reduceArray[k]['tribes'] != "0";
        })
        var ok = $scope.reducer.ok(_.pick($scope.reduceArray, arr));
        if (ok.ok != false)
        {
            $scope.hideReducer = true;
            reduceFunc(ok);
            gameLog.reduce.push($scope.reduceArray)
        }
    }
    $scope.$watchCollection('reduceArray', checkReducer);
    $scope.$watch('reduceArray', checkReducer, true);

    pocketciv.Engine.drawer = function(deck, drawn) {
        console.log("Show drawer")
        $scope.deck = deck;
        $scope.hideDrawer = false;
        drawnFunc = drawn;
    }

    $scope.areaChangeOk = function() {
        $scope.areaChange = undefined;
        areaChangeDone.call($scope.engine);
        areaChangeDone = undefined;
        $(".highlight").removeClass('highlight');
    }

    var areaChangeDone = undefined;
    pocketciv.Engine.areaChanger = function(changes, done) {
        $scope.areaChange = changes;
        areaChangeDone = done;
        if (_.isEmpty(changes))
            $scope.areaChangeOk();
        else {
            _.each(_.keys(changes), function(k) {
                $("[id$='"+k+"']:not([id$='-1'])").addClass('highlight');
            });
        }
    }

    // TODO: These region functions to map.js ?
    var clearRegions = function() {
        $(".activeCanvas").removeClass('active');
    }

    var selectRegion = function(region) {
        $(".activeCanvas:not(#activeCanvas"+region+")").removeClass('active');
        $("#activeCanvas"+region).addClass('active');
    }

    // End region functions

    $scope.possibleAreas = []
    $scope.selectedArea = undefined;
    var areaSelect = undefined;
    $scope.selectArea = function() {
        $scope.possibleAreas = []
        mapClicked = oldClicked;
        $scope.mapInfo = undefined;
        if ($scope.selectedArea)
        {
            areaSelect(pocketciv.Engine.map.areas[$scope.selectedArea]);
            gameLog.areas.push($scope.selectedArea)
        }
        clearRegions();
        $scope.selectedArea = undefined;
    }

    var oldClicked = undefined;
    pocketciv.Engine.areaSelector = function(possibleAreas, select)
    {
        console.log('Area select');
        $scope.possibleAreas = _.keys(possibleAreas);
        $scope.mapInfo = "Select an area from areas "+$scope.possibleAreas;
        oldClicked = mapClicked;
        mapClicked = function(region) {
            if ($scope.possibleAreas.indexOf(region.toString()) > -1)
            {
                $scope.selectedArea = region.toString();
                selectRegion(region);
            }
        }
        $scope.mapDone = function() {
            $scope.selectArea();
        }
        console.log($scope.possibleAreas);
        areaSelect = select;
    }

    pocketciv.Engine.selector = pocketciv.Engine.areaSelector;

    pocketciv.Engine.queryUser = function(type, message)
    {
        return confirm(message);
    }

    var doAcquire = undefined;
    pocketciv.Engine.advanceAcquirer = function(engine, done) {
        $scope.acquirer = new pocketciv.AdvanceAcquirer(engine);
        $scope.possibleAdvances = $scope.acquirer.possibleAdvances();
        doAcquire = done;
    }

    $scope.acquireGo = function() {
        $scope.acquirer.acquire($scope.acquire_name, $scope.acquire_area);
        $scope.possibleAdvances = $scope.acquirer.possibleAdvances();
        $scope.acquired = _.map($scope.acquirer.acquired, function(v) {
            return v.title;
        });
    }

    $scope.acquireOk = function() {
        doAcquire.call($scope.engine, $scope.acquirer.acquired)
        $scope.possibleAdvances = undefined;
    }

    $scope.doEvent = function() {
        try {
        var ev = JSON.parse($scope.startEvent)
        } catch(e) {
            var ev = { name: $scope.startEvent };
        }
        $scope.engine.doEvent(ev)
    }

    $scope.changePhase = undefined;
    $scope.goPhase = function() {
        $scope.engine.phase = $scope.changePhase;
        $scope.changePhase = undefined;
    }

    $scope.engine = pocketciv.Engine;
    $scope.engine.phase = "";
    $scope.godMode = false;

    var map = new Map(pocketciv.Map);
    $scope.mapArea = map

    map.getCanvas = function(i) {
        return [$('#mapCanvas'+i)[0],
                $('#focusCanvas'+i).get(0),
                $('#activeCanvas'+i).get(0)];
    }
    map.getImage = function(i) {
        return $('#mapImage'+i)[0];
    }

    function getMousePos(canvas, evt) {
        var rect = canvas.getBoundingClientRect();
        return {
          X: evt.clientX - rect.left,
          Y: evt.clientY - rect.top
        };
    }

    var mouseCanvas = document.getElementById("clickCanvas");
    var focusCnvs = $.makeArray($(".focusCanvas"));
    $scope.mapClick = function(ev) {
        var pnt = getMousePos(mouseCanvas, ev);
        var hex = map.getRegionAt(pnt.X, pnt.Y);
        mapClicked(hex);
    }

    var mapClicked = function(region) {
        console.log("Map clicked on region "+region);
        $("#activeCanvas"+region).toggleClass('active');
    }

    $scope.mapFocus= function(ev) {
        var pnt = getMousePos(mouseCanvas, ev);
        var hex = map.getRegionAt(pnt.X, pnt.Y);
        for (var i = 1; i <= 8; i++)
        {
            if (i == hex)
                $(focusCnvs[i-1]).addClass('focus');
            else
                $(focusCnvs[i-1]).removeClass('focus');
        }
    }

    angular.element(document).ready(function() {
        map.paint();
        for (var reg in map.symbols)
        {
            $('#area'+reg).css({top: map.symbols[reg]['area'].Y, left: map.symbols[reg]['area'].X }).show()
        }
    })

    $scope.advance = function(name) {
        $scope.engine.runPhase('advance', name);
        _.last(gameLog.advance).push(name);
    }

    $scope.$watch(function(){ return pocketciv.Engine.phase; }, function(name) {
        if (loading || !name) return;
        if (name == 'advance')
        {
            console.log("gameLog advance")
            gameLog.advance.push([]);
        }
        pocketciv.Engine.runPhase(name);
    })

    $scope.saveGamePlay = function() {
        console.log("Saving game "+$scope.gameName)
        $scope.$storage[$scope.gameName] = JSON.stringify(gameLog);
    }

    var loading = false;
    $scope.loadGamePlay = function(name, game) {
        $scope.gameName = name;
        console.log("run: "+game)
        gameLog = JSON.parse(game);
        loading = true;
        pocketciv.Engine.phase = "populate";
        runplay.run(pocketciv.Engine, JSON.parse(game), function() { loading = false; })
    }

    $scope.$watch('map', function() {
        console.log("Hey! Map changed!")
        pocketciv.Map.areas = $scope.map.areas
        for (var reg in $scope.map.areas)
        {
            if (!(reg in map.symbols))
                continue

            for (var prop in $scope.map.areas[reg])
            {
                if (!(prop in map.symbols[reg]))
                    continue;

                var $elem = $('#'+prop+reg);
                var val = $scope.map.areas[reg][prop];

                if ($elem.length == 0 && val)
                {
                    $elem = $('#'+prop).clone().attr('id', prop+reg).appendTo("#canvases")
                    $elem.css({ top: map.symbols[reg][prop].Y, left: map.symbols[reg][prop].X})
                }
                if ($elem.length > 0 && !val)
                    $elem.remove()
                else
                    $elem.html($scope.map.areas[reg][prop]).show()
            }
        }
    })
});

pocketciv.Engine.init(scenarios["1"]);

pocketcivApp.directive('jsonText', function() {
  return {
    restrict: 'A', // only activate on element attribute
    require: 'ngModel', // get a hold of NgModelController
    link: function(scope, element, attrs, ngModelCtrl) {

      var lastValid;

      // push() if faster than unshift(), and avail. in IE8 and earlier (unshift isn't)
      ngModelCtrl.$parsers.push(fromUser);
      ngModelCtrl.$formatters.push(toUser);

      // clear any invalid changes on blur
      element.bind('blur', function () {
        element.val(toUser(scope.$eval(attrs.ngModel)));
      });

      // $watch(attrs.ngModel) wouldn't work if this directive created a new scope;
      // see http://stackoverflow.com/questions/14693052/watch-ngmodel-from-inside-directive-using-isolate-scope how to do it then
      scope.$watch(attrs.ngModel, function(newValue, oldValue) {
        lastValid = lastValid || newValue;

        if (newValue != oldValue) {
          ngModelCtrl.$setViewValue(toUser(newValue));

          // TODO avoid this causing the focus of the input to be lost..
          ngModelCtrl.$render();
        }
      }, true); // MUST use objectEquality (true) here, for some reason..

      function fromUser(text) {
        // Beware: trim() is not available in old browsers
        if (!text || text.trim() === '') {
          return {};
        } else {
          try {
            lastValid = angular.fromJson(text);
            ngModelCtrl.$setValidity('invalidJson', true);
          } catch(e) {
            ngModelCtrl.$setValidity('invalidJson', false);
          }
          return lastValid
        }
      }

      function toUser(object) {
        // better than JSON.stringify(), because it formats + filters $$hashKey etc.
        return angular.toJson(object, true);
      }
    }
  };
});
<commit_msg>UI tribe mover implemented<commit_after>var pocketciv = require("../../core/pocketciv");
var pocketcivApp = angular.module('pocketcivApp', ['ngStorage']);
var runplay = require("../../core/runplay")

pp = pocketciv

function getMovement(areas) {
    return _.object(_.map(pocketciv.Map.areas, function (area, id) {
        return [id, area.tribes ? area.tribes : 0 ];
    }));
}

gameLog = {
    "move": [],
    "deck": [],
    "reduce": [],
    "areas": [],
    "advance": []
};

var scenarios = {
    "1": require("../scenarios/scenario1")
}

pocketcivApp.controller('MainGame', function ($scope, $localStorage) {
    $scope.$storage = $localStorage;
    $scope.map = pocketciv.Map;
    $scope.deck = pocketciv.EventDeck;

    var moveFunc = undefined;
    $scope.moveTribes = function() {
        var mover = new pocketciv.TribeMover(pocketciv.Map.areas);
        mover.init(getMovement(pocketciv.Map.areas));
        if (mover.ok($scope.movement))
        {
            console.log("OK MOVE!");
            moveFunc.call(pocketciv.Engine, $scope.movement);
            $scope.hideMover = true;
            $scope.mapInfo = undefined;
            mapClicked = oldClicked;
            gameLog.move.push($scope.movement)
        } else {
            console.log("FAILED MOVE")
        }
    }
    $scope.hideMover = true;

    var moveFrom = 0;
    pocketciv.Engine.mover = function(situation, move) {
        console.log("Show mover")
        // Plain mover
        $scope.movement = getMovement(situation);
        $scope.hideMover = false;
        moveFunc = move;
        var mover = new pocketciv.TribeMover(pocketciv.Map.areas);

        // UI
        $scope.mapInfo = "Move tribes by clicking start region and then target region";
        oldClicked = mapClicked;
        mapClicked = function(region) {
            if (region < 1 || region > 8)
                return;
            if (moveFrom == 0)
            {
                if ($scope.movement[region] > 0)
                {
                    moveFrom = region;
                    selectRegion(region);
                }
            } else {
                mover.init(getMovement(pocketciv.Map.areas));
                $scope.movement[moveFrom]--;
                $scope.movement[region]++;
                if (mover.ok($scope.movement))
                {
                    drawElem("tribes", region, $scope.movement[region]);
                    drawElem("tribes", moveFrom, $scope.movement[moveFrom]);
                    moveFrom = 0;
                    clearRegions();
                } else {
                    $scope.movement[moveFrom]++;
                    $scope.movement[region]--;
                }
            }
        }
        $scope.mapDone = function() {
            $scope.moveTribes();
        }

    }

    var drawnFunc = undefined;
    $scope.hideDrawer = true;
    $scope.drawCard = function() {
        $scope.card = $scope.deck.draw();
        if ($scope.specificCard)
            $scope.card = pocketciv.EventDeck.specific($scope.specificCard);
        $scope.specificCard = undefined;
        $scope.hideDrawer = true;
        gameLog.deck.push($scope.card.id)
        drawnFunc && drawnFunc.call(pocketciv.Engine, $scope.card);
    }

    var reduceFunc = undefined;
    $scope.hideReducer = true;
    pocketciv.Engine.reducer = function(reducer, done) {
        console.log("Show reducer")
        $scope.hideReducer = false;
        $scope.reducer = reducer;
        if (reducer.mode == 'Overall')
        {
            $scope.reduceArray = {};
            var areas = $scope.reducer.areas();
            _.each(areas, function(area) {
                $scope.reduceArray[area.id] = { 'tribes': 0 }
            });
            $scope.reduceAreas = areas;
        }
        else
            $scope.reduceArray = [];
        reduceFunc = done;
        checkReducer();
    }
    var checkReducer = function() {
        console.log('reduce array change')
        console.log($scope.reduceArray)
        if ($scope.hideReducer)
            return;
        var ok = $scope.reducer.ok($scope.reduceArray);
        if ($scope.reducer.mode == 'AreaWalker')
        {
            $scope.reduceAreas = ok.areas;
            if (! $scope.reduceAreas)
            {
                $scope.hideReducer = true;
                reduceFunc(ok);
                gameLog.reduce.push($scope.reduceArray)
            }
        } else {
            $scope.reducer.amount = ok.amount;
        }
    };
    $scope.reduceReady = function() {
        var arr = _.filter(_.keys($scope.reduceArray), function(k) {
            return $scope.reduceArray[k]['tribes'] != "0";
        })
        var ok = $scope.reducer.ok(_.pick($scope.reduceArray, arr));
        if (ok.ok != false)
        {
            $scope.hideReducer = true;
            reduceFunc(ok);
            gameLog.reduce.push($scope.reduceArray)
        }
    }
    $scope.$watchCollection('reduceArray', checkReducer);
    $scope.$watch('reduceArray', checkReducer, true);

    pocketciv.Engine.drawer = function(deck, drawn) {
        console.log("Show drawer")
        $scope.deck = deck;
        $scope.hideDrawer = false;
        drawnFunc = drawn;
    }

    $scope.areaChangeOk = function() {
        $scope.areaChange = undefined;
        areaChangeDone.call($scope.engine);
        areaChangeDone = undefined;
        $(".highlight").removeClass('highlight');
    }

    var areaChangeDone = undefined;
    pocketciv.Engine.areaChanger = function(changes, done) {
        $scope.areaChange = changes;
        areaChangeDone = done;
        if (_.isEmpty(changes))
            $scope.areaChangeOk();
        else {
            _.each(_.keys(changes), function(k) {
                $("[id$='"+k+"']:not([id$='-1'])").addClass('highlight');
            });
        }
    }

    // TODO: These region functions to map.js ?
    var clearRegions = function() {
        $(".activeCanvas").removeClass('active');
    }

    var selectRegion = function(region) {
        $(".activeCanvas:not(#activeCanvas"+region+")").removeClass('active');
        $("#activeCanvas"+region).addClass('active');
    }

    // End region functions

    $scope.possibleAreas = []
    $scope.selectedArea = undefined;
    var areaSelect = undefined;
    $scope.selectArea = function() {
        $scope.possibleAreas = []
        mapClicked = oldClicked;
        $scope.mapInfo = undefined;
        if ($scope.selectedArea)
        {
            areaSelect(pocketciv.Engine.map.areas[$scope.selectedArea]);
            gameLog.areas.push($scope.selectedArea)
        }
        clearRegions();
        $scope.selectedArea = undefined;
    }

    var oldClicked = undefined;
    pocketciv.Engine.areaSelector = function(possibleAreas, select)
    {
        console.log('Area select');
        $scope.possibleAreas = _.keys(possibleAreas);
        $scope.mapInfo = "Select an area from areas "+$scope.possibleAreas;
        oldClicked = mapClicked;
        mapClicked = function(region) {
            if ($scope.possibleAreas.indexOf(region.toString()) > -1)
            {
                $scope.selectedArea = region.toString();
                selectRegion(region);
            }
        }
        $scope.mapDone = function() {
            $scope.selectArea();
        }
        console.log($scope.possibleAreas);
        areaSelect = select;
    }

    pocketciv.Engine.selector = pocketciv.Engine.areaSelector;

    pocketciv.Engine.queryUser = function(type, message)
    {
        return confirm(message);
    }

    var doAcquire = undefined;
    pocketciv.Engine.advanceAcquirer = function(engine, done) {
        $scope.acquirer = new pocketciv.AdvanceAcquirer(engine);
        $scope.possibleAdvances = $scope.acquirer.possibleAdvances();
        doAcquire = done;
    }

    $scope.acquireGo = function() {
        $scope.acquirer.acquire($scope.acquire_name, $scope.acquire_area);
        $scope.possibleAdvances = $scope.acquirer.possibleAdvances();
        $scope.acquired = _.map($scope.acquirer.acquired, function(v) {
            return v.title;
        });
    }

    $scope.acquireOk = function() {
        doAcquire.call($scope.engine, $scope.acquirer.acquired)
        $scope.possibleAdvances = undefined;
    }

    $scope.doEvent = function() {
        try {
        var ev = JSON.parse($scope.startEvent)
        } catch(e) {
            var ev = { name: $scope.startEvent };
        }
        $scope.engine.doEvent(ev)
    }

    $scope.changePhase = undefined;
    $scope.goPhase = function() {
        $scope.engine.phase = $scope.changePhase;
        $scope.changePhase = undefined;
    }

    $scope.engine = pocketciv.Engine;
    $scope.engine.phase = "";
    $scope.godMode = false;

    var map = new Map(pocketciv.Map);
    $scope.mapArea = map

    map.getCanvas = function(i) {
        return [$('#mapCanvas'+i)[0],
                $('#focusCanvas'+i).get(0),
                $('#activeCanvas'+i).get(0)];
    }
    map.getImage = function(i) {
        return $('#mapImage'+i)[0];
    }

    function getMousePos(canvas, evt) {
        var rect = canvas.getBoundingClientRect();
        return {
          X: evt.clientX - rect.left,
          Y: evt.clientY - rect.top
        };
    }

    var mouseCanvas = document.getElementById("clickCanvas");
    var focusCnvs = $.makeArray($(".focusCanvas"));
    $scope.mapClick = function(ev) {
        var pnt = getMousePos(mouseCanvas, ev);
        var hex = map.getRegionAt(pnt.X, pnt.Y);
        mapClicked(hex);
    }

    var mapClicked = function(region) {
        console.log("Map clicked on region "+region);
        $("#activeCanvas"+region).toggleClass('active');
    }

    $scope.mapFocus= function(ev) {
        var pnt = getMousePos(mouseCanvas, ev);
        var hex = map.getRegionAt(pnt.X, pnt.Y);
        for (var i = 1; i <= 8; i++)
        {
            if (i == hex)
                $(focusCnvs[i-1]).addClass('focus');
            else
                $(focusCnvs[i-1]).removeClass('focus');
        }
    }

    angular.element(document).ready(function() {
        map.paint();
        for (var reg in map.symbols)
        {
            $('#area'+reg).css({top: map.symbols[reg]['area'].Y, left: map.symbols[reg]['area'].X }).show()
        }
    })

    $scope.advance = function(name) {
        $scope.engine.runPhase('advance', name);
        _.last(gameLog.advance).push(name);
    }

    $scope.$watch(function(){ return pocketciv.Engine.phase; }, function(name) {
        if (loading || !name) return;
        if (name == 'advance')
        {
            console.log("gameLog advance")
            gameLog.advance.push([]);
        }
        pocketciv.Engine.runPhase(name);
    })

    $scope.saveGamePlay = function() {
        console.log("Saving game "+$scope.gameName)
        $scope.$storage[$scope.gameName] = JSON.stringify(gameLog);
    }

    var loading = false;
    $scope.loadGamePlay = function(name, game) {
        $scope.gameName = name;
        console.log("run: "+game)
        gameLog = JSON.parse(game);
        loading = true;
        pocketciv.Engine.phase = "populate";
        runplay.run(pocketciv.Engine, JSON.parse(game), function() { loading = false; })
    }

    var drawElem = function(prop, reg, val) {
        var $elem = $('#' + prop + reg);

        if ($elem.length == 0 && val) {
            $elem = $('#' + prop).clone().attr('id', prop + reg).appendTo("#canvases")
            $elem.css({
                top: map.symbols[reg][prop].Y,
                left: map.symbols[reg][prop].X
            })
        }
        if ($elem.length > 0 && !val) $elem.remove()
        else $elem.html(val).show()
    }

    $scope.$watch('map', function() {
        console.log("Hey! Map changed!")
        pocketciv.Map.areas = $scope.map.areas
        for (var reg in $scope.map.areas)
        {
            if (!(reg in map.symbols))
                continue

            for (var prop in $scope.map.areas[reg])
            {
                if (!(prop in map.symbols[reg]))
                    continue;

                var val = $scope.map.areas[reg][prop];
                drawElem(prop, reg, val);
            }
        }
    })
});

pocketciv.Engine.init(scenarios["1"]);

pocketcivApp.directive('jsonText', function() {
  return {
    restrict: 'A', // only activate on element attribute
    require: 'ngModel', // get a hold of NgModelController
    link: function(scope, element, attrs, ngModelCtrl) {

      var lastValid;

      // push() if faster than unshift(), and avail. in IE8 and earlier (unshift isn't)
      ngModelCtrl.$parsers.push(fromUser);
      ngModelCtrl.$formatters.push(toUser);

      // clear any invalid changes on blur
      element.bind('blur', function () {
        element.val(toUser(scope.$eval(attrs.ngModel)));
      });

      // $watch(attrs.ngModel) wouldn't work if this directive created a new scope;
      // see http://stackoverflow.com/questions/14693052/watch-ngmodel-from-inside-directive-using-isolate-scope how to do it then
      scope.$watch(attrs.ngModel, function(newValue, oldValue) {
        lastValid = lastValid || newValue;

        if (newValue != oldValue) {
          ngModelCtrl.$setViewValue(toUser(newValue));

          // TODO avoid this causing the focus of the input to be lost..
          ngModelCtrl.$render();
        }
      }, true); // MUST use objectEquality (true) here, for some reason..

      function fromUser(text) {
        // Beware: trim() is not available in old browsers
        if (!text || text.trim() === '') {
          return {};
        } else {
          try {
            lastValid = angular.fromJson(text);
            ngModelCtrl.$setValidity('invalidJson', true);
          } catch(e) {
            ngModelCtrl.$setValidity('invalidJson', false);
          }
          return lastValid
        }
      }

      function toUser(object) {
        // better than JSON.stringify(), because it formats + filters $$hashKey etc.
        return angular.toJson(object, true);
      }
    }
  };
});
<|endoftext|>


<commit_before>'use strict';

function AuthorsController($scope, $location, $anchorScroll) {
  'ngInject';

  let self = this;

  let name = (p) => `${p.first_name||''} ${p.last_name}`.trim();

  this.icon = () => {
    if ($scope.icon) {
      return $scope.icon;
    }
    return 'people';
  };

  this._show = { author: true, contributor: false, affiliations: false };

  this.flip = (role='contributor') => {
    self._show[role] = !self._show[role];
  };

  this.show = (role) => self._show[role];

  // Inject contributors (other than authors) from outside scope
  this.contributors = ($scope.people||[]).filter(
    p => (false === p.roles.includes('author'))
  ).map(c => {
    if (c && !c.name && c.last_name) {
      c.name = name(c);
    }
    return c;
  });

  // Inject authors from outside scope
  this.authors = ($scope.authors||[]).map(a => {
    if (a && !a.name && a.last_name) {
      a.name = name(a);
    }
    return a;
  });

  $scope.document = { people: self.authors.concat(self.contributors||[]) };

  this.isNpolar = (o) => {
    return ((/npolar\.no|NPI|Norsk Polarinstitutt|Norwegian Polar Institute/i).test(o));
  };

  this.tinyLogo = (id) => {
    return "http://www.npolar.no/system/modules/no.npolar.site.npweb/resources/style/np-logo.svg?fingerprint=1386594068655";
  };

  $scope.hasRole = (person, role) => {
    if (!person || !person.roles.length || !role) { return; }
    return person.roles.includes(role);
  };

  $scope.gotoPerson = (person) => {
    if (!person) { return; }
    let anchor = `${person.first_name}+${person.last_name}`.toLowerCase();
    console.log('gotoPerson', person, anchor);
    $location.hash(anchor);
    $anchorScroll();
  };

  $scope.isContact = (person) => {
    if (!person || !person.roles.length || person.roles.length < 1) { return; }
    if (person.roles.findIndex(r => ['correspondent', 'pointOfContact'].includes(r)) > 0) {
      return true;
    }
  };

}
module.exports = AuthorsController;<commit_msg>Bugfix: contacts may be the first role<commit_after>'use strict';

function AuthorsController($scope, $location, $anchorScroll) {
  'ngInject';

  let self = this;

  let name = (p) => `${p.first_name||''} ${p.last_name}`.trim();

  this.icon = () => {
    if ($scope.icon) {
      return $scope.icon;
    }
    return 'people';
  };

  this._show = { author: true, contributor: false, affiliations: false };

  this.flip = (role='contributor') => {
    self._show[role] = !self._show[role];
  };

  this.show = (role) => self._show[role];

  // Inject contributors (other than authors) from outside scope
  this.contributors = ($scope.people||[]).filter(
    p => (false === p.roles.includes('author'))
  ).map(c => {
    if (c && !c.name && c.last_name) {
      c.name = name(c);
    }
    return c;
  });

  // Inject authors from outside scope
  this.authors = ($scope.authors||[]).map(a => {
    if (a && !a.name && a.last_name) {
      a.name = name(a);
    }
    return a;
  });

  $scope.document = { people: self.authors.concat(self.contributors||[]) };

  this.isNpolar = (o) => {
    return ((/npolar\.no|NPI|Norsk Polarinstitutt|Norwegian Polar Institute/i).test(o));
  };

  this.tinyLogo = (id) => {
    return "http://www.npolar.no/system/modules/no.npolar.site.npweb/resources/style/np-logo.svg?fingerprint=1386594068655";
  };

  $scope.hasRole = (person, role) => {
    if (!person || !person.roles.length || !role) { return; }
    return person.roles.includes(role);
  };

  $scope.gotoPerson = (person) => {
    if (!person) { return; }
    let anchor = `${person.first_name}+${person.last_name}`.toLowerCase();
    console.log('gotoPerson', person, anchor);
    $location.hash(anchor);
    $anchorScroll();
  };

  $scope.isContact = (person) => {
    if (!person || !person.roles.length || person.roles.length < 1) { return; }
    if (person.roles.findIndex(r => ['correspondent', 'pointOfContact'].includes(r)) >= 0) {
      return true;
    }
  };

}
module.exports = AuthorsController;<|endoftext|>


<commit_before>'use strict';

var util = require( '../../../util' );
var math = require( '../../../math' );

var CRp = {};

CRp.eleTextBiggerThanMin = function( ele, scale ){
  if( !scale ){
    var zoom = ele.cy().zoom();
    var pxRatio = this.getPixelRatio();
    var lvl = Math.ceil( math.log2( zoom * pxRatio ) ); // the effective texture level

    scale = Math.pow( 2, lvl );
  }

  var computedSize = ele.pstyle( 'font-size' ).pfValue * scale;
  var minSize = ele.pstyle( 'min-zoomed-font-size' ).pfValue;

  if( computedSize < minSize ){
    return false;
  }

  return true;
};

CRp.drawElementText = function( context, ele, force ){
  var r = this;

  if( force === undefined ){
    if( !r.eleTextBiggerThanMin( ele ) ){ return; }
  } else {
    if( !force ){ return; }
  }

  if( ele.isNode() ){
    var label = ele.pstyle( 'label' );

    if( !label || !label.value ){ return; }

    var textHalign = ele.pstyle( 'text-halign' ).strValue;
    var textValign = ele.pstyle( 'text-valign' ).strValue;

    switch( textHalign ){
      case 'left':
        context.textAlign = 'right';
        break;

      case 'right':
        context.textAlign = 'left';
        break;

      default: // e.g. center
        context.textAlign = 'center';
    }

    context.textBaseline = 'bottom';
  } else {
    var label = ele.pstyle( 'label' );
    var srcLabel = ele.pstyle( 'source-label' );
    var tgtLabel = ele.pstyle( 'target-label' );

    if(
      ( !label || !label.value )
      && ( !srcLabel || !srcLabel.value )
      && ( !tgtLabel || !tgtLabel.value )
    ){
      return;
    }

    context.textAlign = 'center';
    context.textBaseline = 'bottom';
  }

  r.drawText( context, ele );

  if( ele.isEdge() ){
    r.drawText( context, ele, 'source' );

    r.drawText( context, ele, 'target' );
  }
};

CRp.drawNodeText = CRp.drawEdgeText = CRp.drawElementText;

CRp.getFontCache = function( context ){
  var cache;

  this.fontCaches = this.fontCaches || [];

  for( var i = 0; i < this.fontCaches.length; i++ ){
    cache = this.fontCaches[ i ];

    if( cache.context === context ){
      return cache;
    }
  }

  cache = {
    context: context
  };
  this.fontCaches.push( cache );

  return cache;
};

// set up canvas context with font
// returns transformed text string
CRp.setupTextStyle = function( context, ele ){
  // Font style
  var parentOpacity = ele.effectiveOpacity();
  var labelStyle = ele.pstyle( 'font-style' ).strValue;
  var labelSize = ele.pstyle( 'font-size' ).pfValue + 'px';
  var labelFamily = ele.pstyle( 'font-family' ).strValue;
  var labelWeight = ele.pstyle( 'font-weight' ).strValue;
  var opacity = ele.pstyle( 'text-opacity' ).value * ele.pstyle( 'opacity' ).value * parentOpacity;
  var outlineOpacity = ele.pstyle( 'text-outline-opacity' ).value * opacity;
  var color = ele.pstyle( 'color' ).value;
  var outlineColor = ele.pstyle( 'text-outline-color' ).value;
  var shadowBlur = ele.pstyle( 'text-shadow-blur' ).pfValue;
  var shadowOpacity = ele.pstyle( 'text-shadow-opacity' ).value;
  var shadowColor = ele.pstyle( 'text-shadow-color' ).value;
  var shadowOffsetX = ele.pstyle( 'text-shadow-offset-x' ).pfValue;
  var shadowOffsetY = ele.pstyle( 'text-shadow-offset-y' ).pfValue;

  var fontCacheKey = ele._private.fontKey;
  var cache = this.getFontCache( context );

  if( cache.key !== fontCacheKey ){
    context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;

    cache.key = fontCacheKey;
  }

  // Calculate text draw position based on text alignment

  // so text outlines aren't jagged
  context.lineJoin = 'round';

  this.fillStyle( context, color[ 0 ], color[ 1 ], color[ 2 ], opacity );

  this.strokeStyle( context, outlineColor[ 0 ], outlineColor[ 1 ], outlineColor[ 2 ], outlineOpacity );

  this.shadowStyle( context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY );
};

function roundRect( ctx, x, y, width, height, radius ){
  var radius = radius || 5;
  ctx.beginPath();
  ctx.moveTo( x + radius, y );
  ctx.lineTo( x + width - radius, y );
  ctx.quadraticCurveTo( x + width, y, x + width, y + radius );
  ctx.lineTo( x + width, y + height - radius );
  ctx.quadraticCurveTo( x + width, y + height, x + width - radius, y + height );
  ctx.lineTo( x + radius, y + height );
  ctx.quadraticCurveTo( x, y + height, x, y + height - radius );
  ctx.lineTo( x, y + radius );
  ctx.quadraticCurveTo( x, y, x + radius, y );
  ctx.closePath();
  ctx.fill();
}

// Draw text
CRp.drawText = function( context, ele, prefix ){
  var _p = ele._private;
  var rscratch = _p.rscratch;
  var parentOpacity = ele.effectiveOpacity();
  if( parentOpacity === 0 || ele.pstyle( 'text-opacity' ).value === 0 ){
    return;
  }

  var textX = util.getPrefixedProperty( rscratch, 'labelX', prefix );
  var textY = util.getPrefixedProperty( rscratch, 'labelY', prefix );
  var text = this.getLabelText( ele, prefix );

  if( text != null && text !== '' && !isNaN( textX ) && !isNaN( textY ) ){
    this.setupTextStyle( context, ele );

    var pdash = prefix ? prefix + '-' : '';
    var textW = util.getPrefixedProperty( rscratch, 'labelWidth', prefix );
    var textH = util.getPrefixedProperty( rscratch, 'labelHeight', prefix );
    var textAngle = util.getPrefixedProperty( rscratch, 'labelAngle', prefix );
    var marginX = ele.pstyle( pdash + 'text-margin-x' ).pfValue;
    var marginY = ele.pstyle( pdash + 'text-margin-y' ).pfValue;

    var isEdge = ele.isEdge();
    var isNode = ele.isNode();

    var halign = ele.pstyle( 'text-halign' ).value;
    var valign = ele.pstyle( 'text-valign' ).value;

    if( isEdge ){
      halign = 'center';
      valign = 'center';
    }

    textX += marginX;
    textY += marginY;

    var rotation = ele.pstyle( 'text-rotation' );
    var theta;

    if( rotation.strValue === 'autorotate' ){
      theta = isEdge ? textAngle : 0;
    } else if( rotation.strValue === 'none' ){
      theta = 0;
    } else {
      theta = rotation.pfValue;
    }

    if( theta !== 0 ){
      var orgTextX = textX;
      var orgTextY = textY;

      context.translate( orgTextX, orgTextY );
      context.rotate( theta );

      textX = 0;
      textY = 0;
    }

    if( isNode ){
      var pLeft = ele.pstyle( 'padding-left' ).pfValue;
      var pRight = ele.pstyle( 'padding-right' ).pfValue;
      var pTop = ele.pstyle( 'padding-top' ).pfValue;
      var pBottom = ele.pstyle( 'padding-bottom' ).pfValue;

      textX += pLeft / 2;
      textX -= pRight / 2;

      textY += pTop / 2;
      textY -= pBottom / 2;
    }

    switch( valign ){
      case 'top':
        break;
      case 'center':
        textY += textH / 2;
        break;
      case 'bottom':
        textY += textH;
        break;
    }

    var backgroundOpacity = ele.pstyle( 'text-background-opacity' ).value;
    var borderOpacity = ele.pstyle( 'text-border-opacity' ).value;
    var textBorderWidth = ele.pstyle( 'text-border-width' ).pfValue;

    if( backgroundOpacity > 0 || ( textBorderWidth > 0 && borderOpacity > 0 ) ){
      var bgX = textX;

      switch( halign ){
        case 'left':
          bgX -= textW;
          break;
        case 'center':
          bgX -= textW / 2;
          break;
        case 'right':
          break;
      }

      var bgY = textY;

      switch( valign ){
        case 'top':
          bgY -= textH;
          break;
        case 'center':
          bgY -= textH / 2;
          break;
        case 'bottom':
          break;
      }

      if( backgroundOpacity > 0 ){
        var textFill = context.fillStyle;
        var textBackgroundColor = ele.pstyle( 'text-background-color' ).value;

        context.fillStyle = 'rgba(' + textBackgroundColor[ 0 ] + ',' + textBackgroundColor[ 1 ] + ',' + textBackgroundColor[ 2 ] + ',' + backgroundOpacity * parentOpacity + ')';
        var styleShape = ele.pstyle( 'text-background-shape' ).strValue;
        if( styleShape == 'roundrectangle' ){
          roundRect( context, bgX, bgY, textW, textH, 2 );
        } else {
          context.fillRect( bgX, bgY, textW, textH );
        }
        context.fillStyle = textFill;
      }

      if( textBorderWidth > 0 && borderOpacity > 0 ){
        var textStroke = context.strokeStyle;
        var textLineWidth = context.lineWidth;
        var textBorderColor = ele.pstyle( 'text-border-color' ).value;
        var textBorderStyle = ele.pstyle( 'text-border-style' ).value;

        context.strokeStyle = 'rgba(' + textBorderColor[ 0 ] + ',' + textBorderColor[ 1 ] + ',' + textBorderColor[ 2 ] + ',' + borderOpacity * parentOpacity + ')';
        context.lineWidth = textBorderWidth;

        if( context.setLineDash ){ // for very outofdate browsers
          switch( textBorderStyle ){
            case 'dotted':
              context.setLineDash( [ 1, 1 ] );
              break;
            case 'dashed':
              context.setLineDash( [ 4, 2 ] );
              break;
            case 'double':
              context.lineWidth = textBorderWidth / 4; // 50% reserved for white between the two borders
              context.setLineDash( [] );
              break;
            case 'solid':
              context.setLineDash( [] );
              break;
          }
        }

        context.strokeRect( bgX, bgY, textW, textH );

        if( textBorderStyle === 'double' ){
          var whiteWidth = textBorderWidth / 2;

          context.strokeRect( bgX + whiteWidth, bgY + whiteWidth, textW - whiteWidth * 2, textH - whiteWidth * 2 );
        }

        if( context.setLineDash ){ // for very outofdate browsers
          context.setLineDash( [] );
        }
        context.lineWidth = textLineWidth;
        context.strokeStyle = textStroke;
      }

    }

    var lineWidth = 2 * ele.pstyle( 'text-outline-width' ).pfValue; // *2 b/c the stroke is drawn centred on the middle

    if( lineWidth > 0 ){
      context.lineWidth = lineWidth;
    }

    if( ele.pstyle( 'text-wrap' ).value === 'wrap' ){
      var lines = rscratch.labelWrapCachedLines;
      var lineHeight = textH / lines.length;

      switch( valign ){
        case 'top':
          textY -= ( lines.length - 1 ) * lineHeight;
          break;
        case 'center':
        case 'bottom':
          textY -= ( lines.length - 1 ) * lineHeight;
          break;
      }

      for( var l = 0; l < lines.length; l++ ){
        if( lineWidth > 0 ){
          context.strokeText( lines[ l ], textX, textY );
        }

        context.fillText( lines[ l ], textX, textY );

        textY += lineHeight;
      }

    } else {
      if( lineWidth > 0 ){
        context.strokeText( text, textX, textY );
      }

      context.fillText( text, textX, textY );
    }

    if( theta !== 0 ){
      context.rotate( -theta );
      context.translate( -orgTextX, -orgTextY );
    }

    this.shadowStyle( context, 'transparent', 0 ); // reset for next guy
  }
};

module.exports = CRp;
<commit_msg>Label background misaligned on y axis #1513<commit_after>'use strict';

var util = require( '../../../util' );
var math = require( '../../../math' );

var CRp = {};

CRp.eleTextBiggerThanMin = function( ele, scale ){
  if( !scale ){
    var zoom = ele.cy().zoom();
    var pxRatio = this.getPixelRatio();
    var lvl = Math.ceil( math.log2( zoom * pxRatio ) ); // the effective texture level

    scale = Math.pow( 2, lvl );
  }

  var computedSize = ele.pstyle( 'font-size' ).pfValue * scale;
  var minSize = ele.pstyle( 'min-zoomed-font-size' ).pfValue;

  if( computedSize < minSize ){
    return false;
  }

  return true;
};

CRp.drawElementText = function( context, ele, force ){
  var r = this;

  if( force === undefined ){
    if( !r.eleTextBiggerThanMin( ele ) ){ return; }
  } else {
    if( !force ){ return; }
  }

  if( ele.isNode() ){
    var label = ele.pstyle( 'label' );

    if( !label || !label.value ){ return; }

    var textHalign = ele.pstyle( 'text-halign' ).strValue;
    var textValign = ele.pstyle( 'text-valign' ).strValue;

    switch( textHalign ){
      case 'left':
        context.textAlign = 'right';
        break;

      case 'right':
        context.textAlign = 'left';
        break;

      default: // e.g. center
        context.textAlign = 'center';
    }

    context.textBaseline = 'bottom';
  } else {
    var label = ele.pstyle( 'label' );
    var srcLabel = ele.pstyle( 'source-label' );
    var tgtLabel = ele.pstyle( 'target-label' );

    if(
      ( !label || !label.value )
      && ( !srcLabel || !srcLabel.value )
      && ( !tgtLabel || !tgtLabel.value )
    ){
      return;
    }

    context.textAlign = 'center';
    context.textBaseline = 'bottom';
  }

  r.drawText( context, ele );

  if( ele.isEdge() ){
    r.drawText( context, ele, 'source' );

    r.drawText( context, ele, 'target' );
  }
};

CRp.drawNodeText = CRp.drawEdgeText = CRp.drawElementText;

CRp.getFontCache = function( context ){
  var cache;

  this.fontCaches = this.fontCaches || [];

  for( var i = 0; i < this.fontCaches.length; i++ ){
    cache = this.fontCaches[ i ];

    if( cache.context === context ){
      return cache;
    }
  }

  cache = {
    context: context
  };
  this.fontCaches.push( cache );

  return cache;
};

// set up canvas context with font
// returns transformed text string
CRp.setupTextStyle = function( context, ele ){
  // Font style
  var parentOpacity = ele.effectiveOpacity();
  var labelStyle = ele.pstyle( 'font-style' ).strValue;
  var labelSize = ele.pstyle( 'font-size' ).pfValue + 'px';
  var labelFamily = ele.pstyle( 'font-family' ).strValue;
  var labelWeight = ele.pstyle( 'font-weight' ).strValue;
  var opacity = ele.pstyle( 'text-opacity' ).value * ele.pstyle( 'opacity' ).value * parentOpacity;
  var outlineOpacity = ele.pstyle( 'text-outline-opacity' ).value * opacity;
  var color = ele.pstyle( 'color' ).value;
  var outlineColor = ele.pstyle( 'text-outline-color' ).value;
  var shadowBlur = ele.pstyle( 'text-shadow-blur' ).pfValue;
  var shadowOpacity = ele.pstyle( 'text-shadow-opacity' ).value;
  var shadowColor = ele.pstyle( 'text-shadow-color' ).value;
  var shadowOffsetX = ele.pstyle( 'text-shadow-offset-x' ).pfValue;
  var shadowOffsetY = ele.pstyle( 'text-shadow-offset-y' ).pfValue;

  var fontCacheKey = ele._private.fontKey;
  var cache = this.getFontCache( context );

  if( cache.key !== fontCacheKey ){
    context.font = labelStyle + ' ' + labelWeight + ' ' + labelSize + ' ' + labelFamily;

    cache.key = fontCacheKey;
  }

  // Calculate text draw position based on text alignment

  // so text outlines aren't jagged
  context.lineJoin = 'round';

  this.fillStyle( context, color[ 0 ], color[ 1 ], color[ 2 ], opacity );

  this.strokeStyle( context, outlineColor[ 0 ], outlineColor[ 1 ], outlineColor[ 2 ], outlineOpacity );

  this.shadowStyle( context, shadowColor, shadowOpacity, shadowBlur, shadowOffsetX, shadowOffsetY );
};

function roundRect( ctx, x, y, width, height, radius ){
  var radius = radius || 5;
  ctx.beginPath();
  ctx.moveTo( x + radius, y );
  ctx.lineTo( x + width - radius, y );
  ctx.quadraticCurveTo( x + width, y, x + width, y + radius );
  ctx.lineTo( x + width, y + height - radius );
  ctx.quadraticCurveTo( x + width, y + height, x + width - radius, y + height );
  ctx.lineTo( x + radius, y + height );
  ctx.quadraticCurveTo( x, y + height, x, y + height - radius );
  ctx.lineTo( x, y + radius );
  ctx.quadraticCurveTo( x, y, x + radius, y );
  ctx.closePath();
  ctx.fill();
}

// Draw text
CRp.drawText = function( context, ele, prefix ){
  var _p = ele._private;
  var rscratch = _p.rscratch;
  var parentOpacity = ele.effectiveOpacity();
  if( parentOpacity === 0 || ele.pstyle( 'text-opacity' ).value === 0 ){
    return;
  }

  var textX = util.getPrefixedProperty( rscratch, 'labelX', prefix );
  var textY = util.getPrefixedProperty( rscratch, 'labelY', prefix );
  var text = this.getLabelText( ele, prefix );

  if( text != null && text !== '' && !isNaN( textX ) && !isNaN( textY ) ){
    this.setupTextStyle( context, ele );

    var pdash = prefix ? prefix + '-' : '';
    var textW = util.getPrefixedProperty( rscratch, 'labelWidth', prefix );
    var textH = util.getPrefixedProperty( rscratch, 'labelHeight', prefix );
    var textAngle = util.getPrefixedProperty( rscratch, 'labelAngle', prefix );
    var marginX = ele.pstyle( pdash + 'text-margin-x' ).pfValue;
    var marginY = ele.pstyle( pdash + 'text-margin-y' ).pfValue;

    var isEdge = ele.isEdge();
    var isNode = ele.isNode();

    var halign = ele.pstyle( 'text-halign' ).value;
    var valign = ele.pstyle( 'text-valign' ).value;

    if( isEdge ){
      halign = 'center';
      valign = 'center';
    }

    textX += marginX;
    textY += marginY;

    var rotation = ele.pstyle( 'text-rotation' );
    var theta;

    if( rotation.strValue === 'autorotate' ){
      theta = isEdge ? textAngle : 0;
    } else if( rotation.strValue === 'none' ){
      theta = 0;
    } else {
      theta = rotation.pfValue;
    }

    if( theta !== 0 ){
      var orgTextX = textX;
      var orgTextY = textY;

      context.translate( orgTextX, orgTextY );
      context.rotate( theta );

      textX = 0;
      textY = 0;
    }

    if( isNode ){
      var pLeft = ele.pstyle( 'padding-left' ).pfValue;
      var pRight = ele.pstyle( 'padding-right' ).pfValue;
      var pTop = ele.pstyle( 'padding-top' ).pfValue;
      var pBottom = ele.pstyle( 'padding-bottom' ).pfValue;

      textX += pLeft / 2;
      textX -= pRight / 2;

      textY += pTop / 2;
      textY -= pBottom / 2;
    }

    switch( valign ){
      case 'top':
        break;
      case 'center':
        textY += textH / 2;
        break;
      case 'bottom':
        textY += textH;
        break;
    }

    var backgroundOpacity = ele.pstyle( 'text-background-opacity' ).value;
    var borderOpacity = ele.pstyle( 'text-border-opacity' ).value;
    var textBorderWidth = ele.pstyle( 'text-border-width' ).pfValue;

    if( backgroundOpacity > 0 || ( textBorderWidth > 0 && borderOpacity > 0 ) ){
      var bgX = textX;

      switch( halign ){
        case 'left':
          bgX -= textW;
          break;
        case 'center':
          bgX -= textW / 2;
          break;
        case 'right':
          break;
      }

      var bgY = textY - textH;

      if( backgroundOpacity > 0 ){
        var textFill = context.fillStyle;
        var textBackgroundColor = ele.pstyle( 'text-background-color' ).value;

        context.fillStyle = 'rgba(' + textBackgroundColor[ 0 ] + ',' + textBackgroundColor[ 1 ] + ',' + textBackgroundColor[ 2 ] + ',' + backgroundOpacity * parentOpacity + ')';
        var styleShape = ele.pstyle( 'text-background-shape' ).strValue;
        if( styleShape == 'roundrectangle' ){
          roundRect( context, bgX, bgY, textW, textH, 2 );
        } else {
          context.fillRect( bgX, bgY, textW, textH );
        }
        context.fillStyle = textFill;
      }

      if( textBorderWidth > 0 && borderOpacity > 0 ){
        var textStroke = context.strokeStyle;
        var textLineWidth = context.lineWidth;
        var textBorderColor = ele.pstyle( 'text-border-color' ).value;
        var textBorderStyle = ele.pstyle( 'text-border-style' ).value;

        context.strokeStyle = 'rgba(' + textBorderColor[ 0 ] + ',' + textBorderColor[ 1 ] + ',' + textBorderColor[ 2 ] + ',' + borderOpacity * parentOpacity + ')';
        context.lineWidth = textBorderWidth;

        if( context.setLineDash ){ // for very outofdate browsers
          switch( textBorderStyle ){
            case 'dotted':
              context.setLineDash( [ 1, 1 ] );
              break;
            case 'dashed':
              context.setLineDash( [ 4, 2 ] );
              break;
            case 'double':
              context.lineWidth = textBorderWidth / 4; // 50% reserved for white between the two borders
              context.setLineDash( [] );
              break;
            case 'solid':
              context.setLineDash( [] );
              break;
          }
        }

        context.strokeRect( bgX, bgY, textW, textH );

        if( textBorderStyle === 'double' ){
          var whiteWidth = textBorderWidth / 2;

          context.strokeRect( bgX + whiteWidth, bgY + whiteWidth, textW - whiteWidth * 2, textH - whiteWidth * 2 );
        }

        if( context.setLineDash ){ // for very outofdate browsers
          context.setLineDash( [] );
        }
        context.lineWidth = textLineWidth;
        context.strokeStyle = textStroke;
      }

    }

    var lineWidth = 2 * ele.pstyle( 'text-outline-width' ).pfValue; // *2 b/c the stroke is drawn centred on the middle

    if( lineWidth > 0 ){
      context.lineWidth = lineWidth;
    }

    if( ele.pstyle( 'text-wrap' ).value === 'wrap' ){
      var lines = rscratch.labelWrapCachedLines;
      var lineHeight = textH / lines.length;

      switch( valign ){
        case 'top':
          textY -= ( lines.length - 1 ) * lineHeight;
          break;
        case 'center':
        case 'bottom':
          textY -= ( lines.length - 1 ) * lineHeight;
          break;
      }

      for( var l = 0; l < lines.length; l++ ){
        if( lineWidth > 0 ){
          context.strokeText( lines[ l ], textX, textY );
        }

        context.fillText( lines[ l ], textX, textY );

        textY += lineHeight;
      }

    } else {
      if( lineWidth > 0 ){
        context.strokeText( text, textX, textY );
      }

      context.fillText( text, textX, textY );
    }

    if( theta !== 0 ){
      context.rotate( -theta );
      context.translate( -orgTextX, -orgTextY );
    }

    this.shadowStyle( context, 'transparent', 0 ); // reset for next guy
  }
};

module.exports = CRp;
<|endoftext|>


<commit_before>var http = require('http');
var server = http.createServer().listen(8005);
var io = require('socket.io')(server);
var cookie = require('cookie');
var querystring = require('querystring');

io.use(function (socket, next) {
  if (socket.request.headers.cookie) {
    socket.request.cookie = cookie.parse(socket.request.headers.cookie);
    return next();
  }
  return next(new Error('not authorized'));
});

io.on('connection', function (socket) {
  var id = socket.request.cookie.sessionid.slice(-8);

  console.log('client connected', id);

  socket.on('client', function (data) {
    console.log('received from', id, ':', data);
    io.emit('server', data);
  });

  socket.on('disconnect', function (data) {
    console.log('client disconnected');
  });
});
<commit_msg>Broadcast message to all connected sockets except the sender<commit_after>var http = require('http');
var server = http.createServer().listen(8005);
var io = require('socket.io')(server);
var cookie = require('cookie');
var querystring = require('querystring');

io.use(function (socket, next) {
  if (socket.request.headers.cookie) {
    socket.request.cookie = cookie.parse(socket.request.headers.cookie);
    return next();
  }
  return next(new Error('not authorized'));
});

io.on('connection', function (socket) {
  var id = socket.request.cookie.sessionid.slice(-8);

  console.log('client connected', id);

  socket.on('client', function (data) {
    console.log('received from', id, ':', data);
    socket.broadcast.emit('server', data);
  });

  socket.on('disconnect', function (data) {
    console.log('client disconnected');
  });
});
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';

import Form from '../../../src/Form/Form.js';

class FormExample extends React.Component {

  getDefinition() {
    return [
      [
        {
          fieldType: 'text',
          name: 'description',
          placeholder: 'First name',
          showError: 'Setting "showError" will make a field display an error',
          writeType: 'input'
        },
        {
          fieldType: 'text',
          focused: true,
          name: 'uid',
          placeholder: 'Last name',
          required: true,
          value: 'Last name',
          writeType: 'input'
        }
      ],
      {
        fieldType: 'password',
        name: 'Password',
        required: true,
        showLabel: true,
        validation: function (value) {
          return value && value.length > 8;
        },
        validationErrorText: 'Password needs to be greater than 8 characters',
        writeType: 'input'
      },
      {
        fieldType: 'number',
        name: 'Number',
        required: false,
        showLabel: true,
        max: '10',
        min: '0',
        step: '1',
        validation: function (value) {
          return value >= 0 && value <= 10;
        },
        validationErrorText: 'Must be a positive integer between 0 and 10 representing its priority',
        writeType: 'input'
      },
      {
        fieldType: 'checkbox',
        name: 'single-checkbox',
        checked: true,
        disabled: true,
        showLabel: 'Accept terms of service',
        required: true,
        label: 'Single checkbox',
        value: true,
        validation: function (value) {
          return value;
        },
        validationErrorText: 'Must check checkbox!',
        writeType: 'input'
      },
      {
        fieldType: 'select',
        label: 'Level',
        showLabel: true,
        options: [
          {
            html: 'Senior',
            id: 'senior'
          },
          {
            html: 'Junior',
            id: 'junior'
          }
        ],
        value: 'junior',
        name: 'level',
        validation: function (value) {
          return !!value;
        },
        validationErrorText: 'One option has to be selected'
      },
      {
        fieldType: 'checkbox',
        value: [
          {
            name: 'isManager',
            label: 'Manager',
            checked: false
          },
          {
            name: 'isDeveloper',
            label: 'Developer',
            checked: false
          },
          {
            name: 'isSRE',
            label: 'SRE',
            checked: true
          }
        ],
        showLabel: 'What is your role?',
        name: 'role',
        validation: function (value) {;
          return value.some(function (item) {
            return item.checked;
          });
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'radioButton',
        value: [
          {
            disabled: true,
            name: 'bananas',
            label: 'Bananas (disabled)',
            checked: false
          },
          {
            name: 'apple',
            label: 'Apple',
            checked: false
          },
          {
            name: 'pineapple',
            label: 'Pineapple',
            checked: true
          },
          {
            name: 'other',
            label: 'Something else',
            checked: false
          }
        ],
        showLabel: 'What is your favorite fruit?',
        name: 'fruit',
        validation: function (value) {
          return value.some(function (item) {
            return item.checked;
          });
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'textarea',
        name: 'message',
        required: true,
        showLabel: 'Message',
        validation: function (value) {
          return value && value.length < 140;
        },
        validationErrorText: 'Message needs to be less than 140 characters',
        writeType: 'input'
      },
      {
        fieldType: 'submit',
        buttonText: 'Submit',
        buttonClass: 'button button-primary button-wide'
      }
    ];
  }

  render() {

    return (

                  Forms

                  Create forms with custom elements.

                  View full source

                    here
                  .

Properties API

{`Form.propTypes = {
  // Classes.
  className: PropTypes.string,
  formGroupClass: PropTypes.string,
  formRowClass: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.func
  ]),
  helpBlockClass: PropTypes.string,
  inlineIconClass: PropTypes.string,
  inlineTextClass: PropTypes.string,
  inputClass: PropTypes.string,
  readClass: PropTypes.string,
  sharedClass: PropTypes.string,

  // Form definition to build the form from. Contains either:
  // 1. Array of field definitions will be created on same row
  // 2. Field definition (object) will create a single field in that row
  definition: PropTypes.arrayOf(
    React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array
    ])
  ),

  // Optional number of columns in the grid
  maxColumnWidth: PropTypes.number,
  // Optional function to call on error
  onError: PropTypes.func,
  // Optional function to call on change
  onChange: PropTypes.func,
  // Optional function to call on submit
  onSubmit: PropTypes.func,
  // Optional function. Will receive a trigger function.
  // Call the trigger function, when a submit needs to be triggered externally
  triggerSubmit: PropTypes.func
};`}

                        <Form definition={this.getDefinition()} />

{`import {Form} from 'reactjs-components';
import React from 'react';

class FormExample extends React.Component {

  getDefinition() {
    return [
      [
        {
          fieldType: 'text',
          name: 'description',
          placeholder: 'First name',
          showError: 'Setting "showError" will make a field display an error',
          writeType: 'input'
        },
        {
          fieldType: 'text',
          focused: true,
          name: 'uid',
          placeholder: 'Last name',
          required: true,
          value: 'Last name',
          writeType: 'input'
        }
      ],
      {
        fieldType: 'password',
        name: 'Password',
        required: true,
        showLabel: true,
        validation: function (value) {
          return value && value.length > 8;
        },
        validationErrorText: 'Password needs to be greater than 8 characters',
        writeType: 'input'
      },
      {
        fieldType: 'number',
        name: 'Number',
        required: false,
        showLabel: true,
        max: '10',
        min: '0',
        step: '1',
        validation: function (value) {
          return value >= 0 && value <= 10;
        },
        validationErrorText: 'Must be a positive integer between 0 and 10 representing its priority',
        writeType: 'input'
      },
      {
        fieldType: 'checkbox',
        name: 'single-checkbox',
        checked: true,
        disabled: true,
        showLabel: 'Accept terms of service',
        required: true,
        label: 'Single checkbox',
        value: true,
        validation: function (value) {
          return value;
        },
        validationErrorText: 'Must check checkbox!',
        writeType: 'input'
      },
      {
        fieldType: 'checkbox',
        value: [
          {
            name: 'isManager',
            label: 'Manager',
            checked: false
          },
          {
            name: 'isDeveloper',
            label: 'Developer',
            checked: false
          },
          {
            name: 'isSRE',
            label: 'SRE',
            checked: true
          }
        ],
        showLabel: 'What is your role?',
        name: 'role',
        validation: function (value) {
          let result = false;
          value.forEach(function (item) {
            return item.checked;
          });

          return result;
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'radioButton',
        value: [
          {
            disabled: true,
            name: 'bananas',
            label: 'Bananas (disabled)',
            checked: false
          },
          {
            name: 'apple',
            label: 'Apple',
            checked: false
          },
          {
            name: 'pineapple',
            label: 'Pineapple',
            checked: true
          },
          {
            name: 'other',
            label: 'Something else',
            checked: false
          }
        ],
        showLabel: 'What is your favorite fruit?',
        name: 'fruit',
        validation: function (value) {
          let result = false;
          value.forEach(function (item) {
            return item.checked;
          });

          return result;
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'select',
        label: 'Level',
        showLabel: true,
        options: [
          {
            html: 'Senior',
            id: 'Senior'
          },
          {
            html: 'Junior',
            id: 'junior'
          }
        ],
        value: 'junior',
        name: 'level',
        validation: function (value) {
          return !!value;
        },
        validationErrorText: 'One option has to be selected'
      },
      {
        fieldType: 'textarea',
        name: 'message',
        required: true,
        showLabel: 'Message',
        validation: function (value) {
          return value && value.length < 140;
        },
        validationErrorText: 'Message needs to be less than 140 characters',
        writeType: 'input'
      },
      {
        fieldType: 'submit',
        buttonText: 'Submit',
        buttonClass: 'button button-primary button-wide'
      }
    ];
  }

  render() {
    return (
      <Form definition={this.getDefinition()} />
    );
  }
}`}

    );
  }
}

ReactDOM.render(<FormExample />, document.getElementById('form'));
<commit_msg>Remove auto focus of filed in docs as it was causing page to jolt<commit_after>import React from 'react';
import ReactDOM from 'react-dom';

import Form from '../../../src/Form/Form.js';

class FormExample extends React.Component {

  getDefinition() {
    return [
      [
        {
          fieldType: 'text',
          name: 'description',
          placeholder: 'First name',
          showError: 'Setting "showError" will make a field display an error',
          writeType: 'input'
        },
        {
          fieldType: 'text',
          name: 'uid',
          placeholder: 'Last name',
          required: true,
          value: 'Last name',
          writeType: 'input'
        }
      ],
      {
        fieldType: 'password',
        name: 'Password',
        required: true,
        showLabel: true,
        validation: function (value) {
          return value && value.length > 8;
        },
        validationErrorText: 'Password needs to be greater than 8 characters',
        writeType: 'input'
      },
      {
        fieldType: 'number',
        name: 'Number',
        required: false,
        showLabel: true,
        max: '10',
        min: '0',
        step: '1',
        validation: function (value) {
          return value >= 0 && value <= 10;
        },
        validationErrorText: 'Must be a positive integer between 0 and 10 representing its priority',
        writeType: 'input'
      },
      {
        fieldType: 'checkbox',
        name: 'single-checkbox',
        checked: true,
        disabled: true,
        showLabel: 'Accept terms of service',
        required: true,
        label: 'Single checkbox',
        value: true,
        validation: function (value) {
          return value;
        },
        validationErrorText: 'Must check checkbox!',
        writeType: 'input'
      },
      {
        fieldType: 'select',
        label: 'Level',
        showLabel: true,
        options: [
          {
            html: 'Senior',
            id: 'senior'
          },
          {
            html: 'Junior',
            id: 'junior'
          }
        ],
        value: 'junior',
        name: 'level',
        validation: function (value) {
          return !!value;
        },
        validationErrorText: 'One option has to be selected'
      },
      {
        fieldType: 'checkbox',
        value: [
          {
            name: 'isManager',
            label: 'Manager',
            checked: false
          },
          {
            name: 'isDeveloper',
            label: 'Developer',
            checked: false
          },
          {
            name: 'isSRE',
            label: 'SRE',
            checked: true
          }
        ],
        showLabel: 'What is your role?',
        name: 'role',
        validation: function (value) {;
          return value.some(function (item) {
            return item.checked;
          });
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'radioButton',
        value: [
          {
            disabled: true,
            name: 'bananas',
            label: 'Bananas (disabled)',
            checked: false
          },
          {
            name: 'apple',
            label: 'Apple',
            checked: false
          },
          {
            name: 'pineapple',
            label: 'Pineapple',
            checked: true
          },
          {
            name: 'other',
            label: 'Something else',
            checked: false
          }
        ],
        showLabel: 'What is your favorite fruit?',
        name: 'fruit',
        validation: function (value) {
          return value.some(function (item) {
            return item.checked;
          });
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'textarea',
        name: 'message',
        required: true,
        showLabel: 'Message',
        validation: function (value) {
          return value && value.length < 140;
        },
        validationErrorText: 'Message needs to be less than 140 characters',
        writeType: 'input'
      },
      {
        fieldType: 'submit',
        buttonText: 'Submit',
        buttonClass: 'button button-primary button-wide'
      }
    ];
  }

  render() {

    return (

                  Forms

                  Create forms with custom elements.

                  View full source

                    here
                  .

Properties API

{`Form.propTypes = {
  // Classes.
  className: PropTypes.string,
  formGroupClass: PropTypes.string,
  formRowClass: React.PropTypes.oneOfType([
    React.PropTypes.string,
    React.PropTypes.func
  ]),
  helpBlockClass: PropTypes.string,
  inlineIconClass: PropTypes.string,
  inlineTextClass: PropTypes.string,
  inputClass: PropTypes.string,
  readClass: PropTypes.string,
  sharedClass: PropTypes.string,

  // Form definition to build the form from. Contains either:
  // 1. Array of field definitions will be created on same row
  // 2. Field definition (object) will create a single field in that row
  definition: PropTypes.arrayOf(
    React.PropTypes.oneOfType([
      React.PropTypes.object,
      React.PropTypes.array
    ])
  ),

  // Optional number of columns in the grid
  maxColumnWidth: PropTypes.number,
  // Optional function to call on error
  onError: PropTypes.func,
  // Optional function to call on change
  onChange: PropTypes.func,
  // Optional function to call on submit
  onSubmit: PropTypes.func,
  // Optional function. Will receive a trigger function.
  // Call the trigger function, when a submit needs to be triggered externally
  triggerSubmit: PropTypes.func
};`}

                        <Form definition={this.getDefinition()} />

{`import {Form} from 'reactjs-components';
import React from 'react';

class FormExample extends React.Component {

  getDefinition() {
    return [
      [
        {
          fieldType: 'text',
          name: 'description',
          placeholder: 'First name',
          showError: 'Setting "showError" will make a field display an error',
          writeType: 'input'
        },
        {
          fieldType: 'text',
          name: 'uid',
          placeholder: 'Last name',
          required: true,
          value: 'Last name',
          writeType: 'input'
        }
      ],
      {
        fieldType: 'password',
        name: 'Password',
        required: true,
        showLabel: true,
        validation: function (value) {
          return value && value.length > 8;
        },
        validationErrorText: 'Password needs to be greater than 8 characters',
        writeType: 'input'
      },
      {
        fieldType: 'number',
        name: 'Number',
        required: false,
        showLabel: true,
        max: '10',
        min: '0',
        step: '1',
        validation: function (value) {
          return value >= 0 && value <= 10;
        },
        validationErrorText: 'Must be a positive integer between 0 and 10 representing its priority',
        writeType: 'input'
      },
      {
        fieldType: 'checkbox',
        name: 'single-checkbox',
        checked: true,
        disabled: true,
        showLabel: 'Accept terms of service',
        required: true,
        label: 'Single checkbox',
        value: true,
        validation: function (value) {
          return value;
        },
        validationErrorText: 'Must check checkbox!',
        writeType: 'input'
      },
      {
        fieldType: 'checkbox',
        value: [
          {
            name: 'isManager',
            label: 'Manager',
            checked: false
          },
          {
            name: 'isDeveloper',
            label: 'Developer',
            checked: false
          },
          {
            name: 'isSRE',
            label: 'SRE',
            checked: true
          }
        ],
        showLabel: 'What is your role?',
        name: 'role',
        validation: function (value) {
          let result = false;
          value.forEach(function (item) {
            return item.checked;
          });

          return result;
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'radioButton',
        value: [
          {
            disabled: true,
            name: 'bananas',
            label: 'Bananas (disabled)',
            checked: false
          },
          {
            name: 'apple',
            label: 'Apple',
            checked: false
          },
          {
            name: 'pineapple',
            label: 'Pineapple',
            checked: true
          },
          {
            name: 'other',
            label: 'Something else',
            checked: false
          }
        ],
        showLabel: 'What is your favorite fruit?',
        name: 'fruit',
        validation: function (value) {
          let result = false;
          value.forEach(function (item) {
            return item.checked;
          });

          return result;
        },
        validationErrorText: 'Please select at least one option.',
        writeType: 'input'
      },
      {
        fieldType: 'select',
        label: 'Level',
        showLabel: true,
        options: [
          {
            html: 'Senior',
            id: 'Senior'
          },
          {
            html: 'Junior',
            id: 'junior'
          }
        ],
        value: 'junior',
        name: 'level',
        validation: function (value) {
          return !!value;
        },
        validationErrorText: 'One option has to be selected'
      },
      {
        fieldType: 'textarea',
        name: 'message',
        required: true,
        showLabel: 'Message',
        validation: function (value) {
          return value && value.length < 140;
        },
        validationErrorText: 'Message needs to be less than 140 characters',
        writeType: 'input'
      },
      {
        fieldType: 'submit',
        buttonText: 'Submit',
        buttonClass: 'button button-primary button-wide'
      }
    ];
  }

  render() {
    return (
      <Form definition={this.getDefinition()} />
    );
  }
}`}

    );
  }
}

ReactDOM.render(<FormExample />, document.getElementById('form'));
<|endoftext|>


<commit_before>'use strict';

let TimeseriesShowController = function($scope, $controller, $timeout,
  NpolarApiSecurity, NpolarTranslate,
  npdcAppConfig,
  Timeseries, TimeseriesModel, TimeseriesCitation, Parameter, google, Sparkline) {

  'ngInject';

  let ctrl = this;

  ctrl.authors = (t) => {
    return t.authors.map(a => {
      return { name: a['@id']};
    });
  };

  ctrl.collection_link = (links,hreflang='en') => {
    return links.find(l => l.rel === 'collection' && l.hreflang === hreflang);
  };

  $controller("NpolarBaseController", {$scope: $scope});
  $scope.resource = Timeseries;

  let chartElement = Sparkline.getElement();
  if (chartElement) {
    chartElement.innerHTML = '';
  }

  $scope.show().$promise.then(timeseries => {
    $scope.data = timeseries.data;

    $scope.data_not_null = timeseries.data.filter(t => t.value !== undefined);

    // Create facet-style links to timeseries with same keywords...
    if (!$scope.keywords && timeseries.keywords && timeseries.keywords.length > 0) {
      $scope.keywords = {};
      let keywords = TimeseriesModel.keywords(timeseries);
      ['en', 'no'].forEach(l => {
        let k = keywords[l];
        let href = $scope.resource.uiBase+`?filter-keywords.@value=${ k.join(',') }`;
        let link = { keywords: keywords[l], count: 0, href };
        Timeseries.feed({"filter-keywords.@value": k.join(','), facets: 'keywords,species', limit: 0}).$promise.then((r) => {

          link.count = r.feed.opensearch.totalResults; // Has all keywords

          if (timeseries.species) {
            let f = r.feed.facets.find(f => f.hasOwnProperty('species'));

            if (f && f.species) {
              let c = f.species.find(f => f.term === timeseries.species);
              link.count_keywords_and_species = c.count;
            }
          }

          $scope.keywords[l] = link;
        }, (e) => {
          $scope.keywords[l] = link;
        });
      });
    }

    $scope.metadata = TimeseriesModel.metadata(timeseries, $scope.resource);

    $scope.citation = (t) => {
      if (!t) { return; }
      return TimeseriesCitation.citation(timeseries);
    };

    // Create graph
    if ($scope.data && $scope.data.length > 0) {
      $timeout(function(){
        $scope.sparkline = true;
        let sparkline = timeseries.data.map(d => [d.value]);
        google.setOnLoadCallback(Sparkline.draw(sparkline));
      });
    }

    // Count keyword-siblings
    //if ($scope.keywords && $scope.keywords.en) {
    //
    //  let k1 = $scope.keywords.en.join(',');
    //  let k2 = $scope.keywords.no.join(',');
    //
    //  Timeseries.array({"filter-keywords.@value": k1, limit: "all"}).$promise.then(t => {
    //    $scope.siblings_en = t.length;
    //  });
    //
    //  Timeseries.array({"filter-keywords.@value": k2, limit: "all"}).$promise.then(t => {
    //    $scope.siblings_no = t.length;
    //  });
    //}

    // Count number of timeseries belonging to the same collection
    if (timeseries.links && timeseries.links.length > 0) {
      ['en', 'nb'].forEach(l => {
        if (!$scope.collection || !$scope.collection[l]) {
          let link = ctrl.collection_link(timeseries.links, l);
          let query = {"filter-links.href": link.href, limit: 0 };
          Timeseries.feed(query).$promise.then(r => {
            if (!$scope.collection) {
              $scope.collection = {};
            }
            $scope.collection[l] = { href: $scope.resource.uiBase+`?filter-links.href=${link.href}`, title: link.title, count: r.feed.opensearch.totalResults }
          });
        }
      });
    }

  });
};
module.exports = TimeseriesShowController;
<commit_msg>Improved quasi-facet counts<commit_after>'use strict';

let TimeseriesShowController = function($scope, $controller, $timeout,
  NpolarApiSecurity, NpolarTranslate,
  npdcAppConfig,
  Timeseries, TimeseriesModel, TimeseriesCitation, google, Sparkline) {

  'ngInject';

  let ctrl = this;

  ctrl.authors = (t) => {
    return t.authors.map(a => {
      return { name: a['@id']};
    });
  };

  ctrl.collection_link = (links,hreflang='en') => {
    return links.find(l => l.rel === 'collection' && l.hreflang === hreflang);
  };

  $controller("NpolarBaseController", {$scope: $scope});
  $scope.resource = Timeseries;

  let chartElement = Sparkline.getElement();
  if (chartElement) {
    chartElement.innerHTML = '';
  }

  $scope.show().$promise.then(timeseries => {
    $scope.data = timeseries.data;

    $scope.data_not_null = timeseries.data.filter(t => t.value !== undefined);

    // Create facet-style links with counts to timeseries with all of the same keywords...
    if (!$scope.keywords && timeseries.keywords && timeseries.keywords.length > 0) {
      $scope.keywords = {};
      let keywords = TimeseriesModel.keywords(timeseries);
      ['en', 'no'].forEach(l => {
        let k = keywords[l];
        let href = $scope.resource.uiBase+`?filter-keywords.@value=${ k.join(',') }`;
        let link = { keywords: keywords[l], count: 0, href };
        Timeseries.feed({"filter-keywords.@value": k.join(','), facets: 'keywords,species,locations.placename', limit: 0}).$promise.then((r) => {

          link.count = r.feed.opensearch.totalResults; // All keywords

          // Count for all keywords + species
          if (timeseries.species) {
            let f = r.feed.facets.find(f => f.hasOwnProperty('species'));

            if (f && f.species) {
              let c = f.species.find(f => f.term === timeseries.species);
              link.count_keywords_and_species = c.count;
            }
          }

          // Count for first all keywords + placename[0]
          if (timeseries.locations && timeseries.locations.length > 0) {
            let f = r.feed.facets.find(f => f.hasOwnProperty('locations.placename'));

            if (f && f['locations.placename']) {
              let c = f['locations.placename'].find(f => f.term === timeseries.locations[0].placename);
              link.count_keywords_and_placename = c.count;
            }
          }

          $scope.keywords[l] = link;
        }, (e) => {
          $scope.keywords[l] = link;
        });
      });
    }

    $scope.metadata = TimeseriesModel.metadata(timeseries, $scope.resource);

    $scope.citation = (t) => {
      if (!t) { return; }
      return TimeseriesCitation.citation(timeseries);
    };

    // Create graph
    if ($scope.data && $scope.data.length > 0) {
      $timeout(function(){
        $scope.sparkline = true;
        let sparkline = timeseries.data.map(d => [d.value]);
        google.setOnLoadCallback(Sparkline.draw(sparkline));
      });
    }

    // Count number of timeseries belonging to the same collection
    if (timeseries.links && timeseries.links.length > 0) {
      ['en', 'nb'].forEach(l => {
        if (!$scope.collection || !$scope.collection[l]) {
          let link = ctrl.collection_link(timeseries.links, l);
          if (link && link.href) {
            let query = {"filter-links.href": link.href, limit: 0 };
            Timeseries.feed(query).$promise.then(r => {
              if (!$scope.collection) {
                $scope.collection = {};
              }
              $scope.collection[l] = { href: $scope.resource.uiBase+`?filter-links.href=${link.href}`,
                title: link.title,
                count: r.feed.opensearch.totalResults
              };

            });

          }
        }
      });
    }

  });
};
module.exports = TimeseriesShowController;
<|endoftext|>


<commit_before>const NEIGHBOUR_DISTANCE = 1;
var selectedGem = null;

function swapClassNames(leftElement, rightElement) {
    var thisClassName = $(leftElement).attr("class");
    $(leftElement).attr("class", $(rightElement).attr("class"));
    $(rightElement).attr("class", thisClassName);
}

function deselectGem(gem) {
    $(gem).removeClass("selected");
    selectedGem = null;
}

function isSelected(gem) {
    return selectedGem === gem;
}

function someGemIsSelected() {
    return selectedGem !== null;
}

function swapGemWithSelected(gem) {
    swapClassNames(gem, selectedGem);
    deselectGem(gem);
}

function selectGem(gem) {
    $(gem).addClass("selected");
    selectedGem = gem;
}

function getGemCoordinates(gem) {
    return {
        col: ($(gem).offset().left - 11) / 34,
        row: ($(gem).offset().top - 11) / 34
    };
}

function columnDistance(coordinates, otherCoordinates) {
    return Math.abs(coordinates.col - otherCoordinates.col);
}

function rowDistance(coordinates, otherCoordinates) {
    return Math.abs(coordinates.row - otherCoordinates.row);
}

function getDistance(gem, otherGem) {
    var coordinates = getGemCoordinates(gem);
    var otherCoordinates = getGemCoordinates(otherGem);
    return columnDistance(coordinates, otherCoordinates) + rowDistance(coordinates, otherCoordinates);
}

function areNeighbours(gem, otherGem) {
    return getDistance(gem, otherGem) === NEIGHBOUR_DISTANCE;
}

function putGemIntoTableByCoordinates(table, row, col, gem) {
    table[row] = table[row] || [];
    table[row][col] = gem;
}

function putGemIntoTable(table, gem) {
    var coordinates = getGemCoordinates(gem);

    $(gem).attr("coordinates", JSON.stringify(coordinates));
    putGemIntoTableByCoordinates(table, coordinates.row, coordinates.col, gem);
}
function getGemsCoordinateLookupTable() {
    var table = [];

    $(".gem").each(function () {
        putGemIntoTable(table, $(this));
    });
    return table;
}

function getGem(lookupTable, row, col) {
    var lookupRow = lookupTable[row];

    if (!lookupRow) {
        return $(null);
    }

    return $(lookupRow[col]);
}

function getGemsWithPattern(lookupTable, row, col, rowOffsets, colOffsets) {
    var gems = [];

    for (var index = 0; index < rowOffsets.length; index++) {
        gems.push(getGem(lookupTable, row + rowOffsets[index], col + colOffsets[index]));
    }

    return gems;
}

function thereIsNoGem(gem) {
    return !gem.attr("class");
}

function isDestroyedGem(gem) {
    return gem.hasClass("gem-destroyed");
}

function allGemsHaveSameClass(gems, name) {
    var firstGem = gems[0];

    if (thereIsNoGem(firstGem) || isDestroyedGem(firstGem)) {
        return false;
    }

    for (var index = 1; index < gems.length; index++) {
        if (firstGem.attr("class") !== gems[index].attr("class")) {
            return false;
        }
    }

    return true;
}

function destroyGem(gem) {
    gem.addClass("gem-destroyed");
}

function destroyGems(gems) {
    for (var index = 0; index < gems.length; index++) {
        destroyGem(gems[index]);
    }
}

function getGemsToBeDestroyedWithPattern(lookupTable, rowOffsets, colOffsets, name) {
    var gemsToBeDestroyed = [];

    for (var row = 0; row < lookupTable.length; row++) {
        for (var col = 0; col < lookupTable[row].length; col++) {
            var gems = getGemsWithPattern(lookupTable, row, col, rowOffsets, colOffsets);

            if (allGemsHaveSameClass(gems, name)) {
                gemsToBeDestroyed.push(gems);
            }
        }
    }

    return gemsToBeDestroyed;
}

function generateRandomColor() {
    var randomValue = Math.random();

    if (randomValue < 0.25) return "red";
    if (randomValue < 0.50) return "green";
    if (randomValue < 0.75) return "yellow";
    return "blue";
}

var $gems = $(".gem");

function enableGravity() {
    var lookupTable = getGemsCoordinateLookupTable();

    setInterval(function () {
        $gems.each(function () {
            var $gem = $(this);
            var coordinates = getGemCoordinates($gem);
            var $downGem = getGem(lookupTable, coordinates.row + 1, coordinates.col);

            if (isDestroyedGem($downGem)) {
                swapClassNames($gem, $downGem);
            }
        });
    }, 50);
}

$gems.click(function () {
    var clickedGem = this;

    if (isSelected(clickedGem)) {
        deselectGem(clickedGem);
    } else {
        if (someGemIsSelected()) {
            if (areNeighbours(clickedGem, selectedGem)) {
                var selectedGemBeforeSwap = selectedGem;

                swapGemWithSelected(clickedGem);

                var lookupTable = getGemsCoordinateLookupTable();

                var gemsToBeDestroyedByCol = getGemsToBeDestroyedWithPattern(lookupTable, [0, 1, 2], [0, 0, 0], "3 in column");
                var gemsToBeDestroyedByRow = getGemsToBeDestroyedWithPattern(lookupTable, [0, 0, 0], [0, 1, 2], "3 in row");

                if (gemsToBeDestroyedByCol.length === 0 && gemsToBeDestroyedByRow.length === 0) {
                    swapClassNames(clickedGem, selectedGemBeforeSwap);
                }

                var index;

                for (index = 0; index < gemsToBeDestroyedByCol.length; index++) {
                    destroyGems(gemsToBeDestroyedByCol[index]);
                }

                for (index = 0; index < gemsToBeDestroyedByRow.length; index++) {
                    destroyGems(gemsToBeDestroyedByRow[index]);
                }

            } else {
                deselectGem(selectedGem);
            }

        } else {
            selectGem(clickedGem);
        }
    }
});
<commit_msg>Make Gravity not to swap destroyed gems<commit_after>const NEIGHBOUR_DISTANCE = 1;
var selectedGem = null;

function swapClassNames(leftElement, rightElement) {
    var thisClassName = $(leftElement).attr("class");
    $(leftElement).attr("class", $(rightElement).attr("class"));
    $(rightElement).attr("class", thisClassName);
}

function deselectGem(gem) {
    $(gem).removeClass("selected");
    selectedGem = null;
}

function isSelected(gem) {
    return selectedGem === gem;
}

function someGemIsSelected() {
    return selectedGem !== null;
}

function swapGemWithSelected(gem) {
    swapClassNames(gem, selectedGem);
    deselectGem(gem);
}

function selectGem(gem) {
    $(gem).addClass("selected");
    selectedGem = gem;
}

function getGemCoordinates(gem) {
    return {
        col: ($(gem).offset().left - 11) / 34,
        row: ($(gem).offset().top - 11) / 34
    };
}

function columnDistance(coordinates, otherCoordinates) {
    return Math.abs(coordinates.col - otherCoordinates.col);
}

function rowDistance(coordinates, otherCoordinates) {
    return Math.abs(coordinates.row - otherCoordinates.row);
}

function getDistance(gem, otherGem) {
    var coordinates = getGemCoordinates(gem);
    var otherCoordinates = getGemCoordinates(otherGem);
    return columnDistance(coordinates, otherCoordinates) + rowDistance(coordinates, otherCoordinates);
}

function areNeighbours(gem, otherGem) {
    return getDistance(gem, otherGem) === NEIGHBOUR_DISTANCE;
}

function putGemIntoTableByCoordinates(table, row, col, gem) {
    table[row] = table[row] || [];
    table[row][col] = gem;
}

function putGemIntoTable(table, gem) {
    var coordinates = getGemCoordinates(gem);

    $(gem).attr("coordinates", JSON.stringify(coordinates));
    putGemIntoTableByCoordinates(table, coordinates.row, coordinates.col, gem);
}
function getGemsCoordinateLookupTable() {
    var table = [];

    $(".gem").each(function () {
        putGemIntoTable(table, $(this));
    });
    return table;
}

function getGem(lookupTable, row, col) {
    var lookupRow = lookupTable[row];

    if (!lookupRow) {
        return $(null);
    }

    return $(lookupRow[col]);
}

function getGemsWithPattern(lookupTable, row, col, rowOffsets, colOffsets) {
    var gems = [];

    for (var index = 0; index < rowOffsets.length; index++) {
        gems.push(getGem(lookupTable, row + rowOffsets[index], col + colOffsets[index]));
    }

    return gems;
}

function thereIsNoGem(gem) {
    return !gem.attr("class");
}

function isDestroyedGem(gem) {
    return gem.hasClass("gem-destroyed");
}

function allGemsHaveSameClass(gems, name) {
    var firstGem = gems[0];

    if (thereIsNoGem(firstGem) || isDestroyedGem(firstGem)) {
        return false;
    }

    for (var index = 1; index < gems.length; index++) {
        if (firstGem.attr("class") !== gems[index].attr("class")) {
            return false;
        }
    }

    return true;
}

function destroyGem(gem) {
    gem.addClass("gem-destroyed");
}

function destroyGems(gems) {
    for (var index = 0; index < gems.length; index++) {
        destroyGem(gems[index]);
    }
}

function getGemsToBeDestroyedWithPattern(lookupTable, rowOffsets, colOffsets, name) {
    var gemsToBeDestroyed = [];

    for (var row = 0; row < lookupTable.length; row++) {
        for (var col = 0; col < lookupTable[row].length; col++) {
            var gems = getGemsWithPattern(lookupTable, row, col, rowOffsets, colOffsets);

            if (allGemsHaveSameClass(gems, name)) {
                gemsToBeDestroyed.push(gems);
            }
        }
    }

    return gemsToBeDestroyed;
}

function generateRandomColor() {
    var randomValue = Math.random();

    if (randomValue < 0.25) return "red";
    if (randomValue < 0.50) return "green";
    if (randomValue < 0.75) return "yellow";
    return "blue";
}

var $gems = $(".gem");

function enableGravity() {
    var lookupTable = getGemsCoordinateLookupTable();

    setInterval(function () {
        $gems.each(function () {
            var $gem = $(this);
            var coordinates = getGemCoordinates($gem);
            var $downGem = getGem(lookupTable, coordinates.row + 1, coordinates.col);

            if (isDestroyedGem($downGem) && !isDestroyedGem($gem)) {
                swapClassNames($gem, $downGem);
            }
        });
    }, 50);
}

$gems.click(function () {
    var clickedGem = this;

    if (isSelected(clickedGem)) {
        deselectGem(clickedGem);
    } else {
        if (someGemIsSelected()) {
            if (areNeighbours(clickedGem, selectedGem)) {
                var selectedGemBeforeSwap = selectedGem;

                swapGemWithSelected(clickedGem);

                var lookupTable = getGemsCoordinateLookupTable();

                var gemsToBeDestroyedByCol = getGemsToBeDestroyedWithPattern(lookupTable, [0, 1, 2], [0, 0, 0], "3 in column");
                var gemsToBeDestroyedByRow = getGemsToBeDestroyedWithPattern(lookupTable, [0, 0, 0], [0, 1, 2], "3 in row");

                if (gemsToBeDestroyedByCol.length === 0 && gemsToBeDestroyedByRow.length === 0) {
                    swapClassNames(clickedGem, selectedGemBeforeSwap);
                }

                var index;

                for (index = 0; index < gemsToBeDestroyedByCol.length; index++) {
                    destroyGems(gemsToBeDestroyedByCol[index]);
                }

                for (index = 0; index < gemsToBeDestroyedByRow.length; index++) {
                    destroyGems(gemsToBeDestroyedByRow[index]);
                }

            } else {
                deselectGem(selectedGem);
            }

        } else {
            selectGem(clickedGem);
        }
    }
});
<|endoftext|>