<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';

logViewerApp.controller('LogviewerCtrl', [
    '$anchorScroll', '$http', '$location', '$q', '$rootScope', '$scope',
    '$timeout', 'ThJobArtifactModel', 'ThLog', 'ThLogSliceModel', 'ThJobModel',
    'dateFilter', 'thJobSearchStr', 'ThResultSetModel', 'thDateFormat', 'thReftestStatus',
    function Logviewer(
        $anchorScroll, $http, $location, $q, $rootScope, $scope,
        $timeout, ThJobArtifactModel, ThLog, ThLogSliceModel, ThJobModel,
        dateFilter, thJobSearchStr, ThResultSetModel, thDateFormat, thReftestStatus) {

        var $log = new ThLog('LogviewerCtrl');

        // changes the size of chunks pulled from server
        var LINE_BUFFER_SIZE = 100;
        var LogSlice;

        $rootScope.urlBasePath = $location.absUrl().split('logviewer')[0];

        var query_string = $location.search();
        if (query_string.repo !== "") {
            $rootScope.repoName = query_string.repo;
        }
        if (query_string.job_id !== "") {
            $scope.job_id= query_string.job_id;
            LogSlice = new ThLogSliceModel($scope.job_id, LINE_BUFFER_SIZE);
        }

        $scope.displayedLogLines = [];
        $scope.loading = false;
        $scope.logError = false;
        $scope.currentLineNumber = 0;
        $scope.highestLine = 0;
        $scope.showSuccessful = true;

        $scope.$watch('artifact', function () {
            if (!$scope.artifact) {
                return;
            }
            $scope.showSuccessful = !$scope.hasFailedSteps();
        });

        $scope.hasFailedSteps = function () {
            var steps = $scope.artifact.step_data.steps;
            for (var i = 0; i < steps.length; i++) {
                // We only recently generated step results as part of ingestion,
                // so we have to check the results property is present.
                // TODO: Remove this when the old data has expired, so long as
                // other data submitters also provide a step result.
                if ('result' in steps[i] && steps[i].result !== "success") {
                    return true;
                }
            }
            return false;
        };

        // get the css class for the result color
        // used for the whole job, as well as for each step
        $scope.getShadingClass = function(result) {
            return "result-status-shading-" + result;
        };

        $scope.loadMore = function(bounds, element) {
            var deferred = $q.defer(), range, req, above, below;

            if (!$scope.loading) {
                // move the line number either up or down depending which boundary was hit
                $scope.currentLineNumber = moveLineNumber(bounds);

                range = {
                    start: $scope.currentLineNumber,
                    end: $scope.currentLineNumber
                };

                if (bounds.top) {
                    above = getChunkAbove(range);
                } else if (bounds.bottom) {
                    below = getChunkBelow(range);
                } else {
                    range = getChunksSurrounding($scope.currentLineNumber);
                }

                // dont do the call if we already have all the lines
                if (range.start === range.end) {
                    return deferred.promise;
                }

                $scope.loading = true;
                var lineRangeParams = {
                    job_id: $scope.job_id,
                    start_line: range.start,
                    end_line: range.end
                };
                if ($scope.artifact.logname) {
                    lineRangeParams.name = $scope.artifact.logname;
                }
                LogSlice.get_line_range(lineRangeParams, {
                    buffer_size: LINE_BUFFER_SIZE
                }).then(function(data) {
                    var slicedData, length;

                    drawErrorLines(data);

                    if (bounds.top) {
                        for (var i = data.length - 1; i >= 0; i--) {
                            // make sure we are inserting at the right place
                            if ($scope.displayedLogLines[0].index !== data[i].index + 1) {
                                continue;
                            }
                            $scope.displayedLogLines.unshift(data[i]);
                        }

                        $timeout(function () {
                            if (above) {
                                removeChunkBelow();
                            }
                        }, 100);
                    } else if (bounds.bottom) {
                        var sh = element.scrollHeight;
                        var lines = $scope.displayedLogLines;

                        for (var j = 0; j < data.length; j++) {
                            // make sure we are inserting at the right place
                            if (lines[lines.length - 1].index !== data[j].index - 1) {
                                continue;
                            }
                            $scope.displayedLogLines.push(data[j]);
                        }

                        $timeout(function () {
                            if (below) {
                                removeChunkAbove();
                                element.scrollTop -= element.scrollHeight - sh;
                            }
                        }, 100);
                    } else {
                        $scope.displayedLogLines = data;
                    }

                    $scope.loading = false;
                    deferred.resolve();
                }, function (error) {
                    $scope.loading = false;
                    $scope.logError = true;
                    deferred.reject();
                });
            } else {
                deferred.reject();
            }

            return deferred.promise;
        };

        // @@@ it may be possible to do this with the angular date filter?
        $scope.formatTime = function(sec) {
            var h = Math.floor(sec/3600);
            var m = Math.floor(sec%3600/60);
            var s = Math.floor(sec%3600 % 60);
            var secStng = sec.toString();
            var ms = secStng.substr(secStng.indexOf(".")+1, 2);
            return ((h > 0 ? h + "h " : "") + (m > 0 ? m + "m " : "") +
                   (s > 0 ? s + "s " : "") + (ms > 0 ? ms + "ms " : "00ms"));
        };

        $scope.displayTime = function(started, finished) {
            var start = started.substr(started.indexOf(" ")+1, 8);
            var end = finished.substr(finished.indexOf(" ")+1, 8);
            return start + "-" + end;
        };

        $scope.init = function() {

            $scope.logProperties = [];
            ThJobModel.get($scope.repoName, $scope.job_id).then(function(job) {
                var jobStr = thJobSearchStr(job);

                // set the title of the browser window/tab
                $scope.logViewerTitle = "Log for " + jobStr;

                // set the result value and shading color class
                $scope.result = {label: "Result", value: job.result};
                $scope.resultStatusShading = $scope.getShadingClass(job.result);

                // other properties, in order of appearance
                $scope.logProperties = [
                    {label: "Job", value: jobStr},
                    {label: "Machine", value: job.machine_name},
                    {label: "Start", value: dateFilter(job.start_timestamp*1000, thDateFormat)},
                    {label: "End", value: dateFilter(job.end_timestamp*1000, thDateFormat)}
                ];

                // Test to expose the reftest button in the logviewer actionbar
                $scope.isReftest = function() {
                    if (job.job_group_name) {
                        return thReftestStatus(job);
                    }
                };

                // get the revision and linkify it
                ThResultSetModel.getResultSet($scope.repoName, job.result_set_id).then(function(data){
                    var revision = data.data.revision;
                    $scope.logProperties.push({label: "Revision", value: revision});
                    $scope.logRevisionFilterUrl = $scope.urlBasePath +
                        "#/jobs?repo=" + $scope.repoName + "&revision=" +
                        revision;
                });
            });

            ThJobArtifactModel.get_list({job_id: $scope.job_id, name__in: 'text_log_summary,Job Info'})
            .then(function(artifactList) {
                artifactList.forEach(function(artifact) {
                    if (artifact.name === 'text_log_summary') {
                        $scope.artifact = artifact.blob;
                    } else if (artifact.name === 'Job Info') {
                        $scope.job_details = artifact.blob.job_details;
                    }
                });
            });
        };

        /** utility functions **/

        function logFileLineCount () {
            var steps = $scope.artifact.step_data.steps;
            return steps[ steps.length - 1 ].finished_linenumber;
        }

        function moveLineNumber (bounds) {
            var lines = $scope.displayedLogLines, newLine;

            if (bounds.top) {
                return lines[0].index;
            } else if (bounds.bottom) {
                newLine = lines[lines.length - 1].index + 1;
                return (newLine > logFileLineCount()) ? logFileLineCount(): newLine;
            }

            return $scope.currentLineNumber;
        }

        function drawErrorLines (data) {
            if (data.length === 0) {
                return;
            }

            var min = data[0].index;
            var max = data[ data.length - 1 ].index;

            $scope.artifact.step_data.steps.forEach(function(step) {
                step.errors.forEach(function(err) {
                    var line = err.linenumber;

                    if (line < min || line > max) {
                        return;
                    }

                    var index = line - min;
                    data[index].hasError = true;
                });
            });
        }

        function getChunksSurrounding(line) {
            var request = {start: null, end: null};

            getChunkContaining(line, request);
            getChunkAbove(request);
            getChunkBelow(request);

            return request;
        }

        function getChunkContaining (line, request) {
            var index = Math.floor(line/LINE_BUFFER_SIZE);

            request.start = index * LINE_BUFFER_SIZE;
            request.end = (index + 1) * LINE_BUFFER_SIZE;
        }

        function getChunkAbove (request) {
            request.start -= LINE_BUFFER_SIZE;
            request.start = Math.floor(request.start/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.start >= 0) {
                return true;
            } else {
                request.start = 0;
                return false;
            }
        }

        function getChunkBelow (request) {
            var lastLine = logFileLineCount();

            request.end += LINE_BUFFER_SIZE;
            request.end = Math.ceil(request.end/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.end <= lastLine) {
                return true;
            } else {
                request.end = lastLine;
                return false;
            }
        }

        function removeChunkAbove (request) {
            $scope.displayedLogLines = $scope.displayedLogLines.slice(LINE_BUFFER_SIZE);
        }

        function removeChunkBelow (request) {
            var endSlice = $scope.displayedLogLines.length - LINE_BUFFER_SIZE;
            $scope.displayedLogLines = $scope.displayedLogLines.slice(0, endSlice);
        }
    }
]);
<commit_msg>Bug 1192198 - Evaluate a skipped step as a non-failure<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, you can obtain one at http://mozilla.org/MPL/2.0/. */

'use strict';

logViewerApp.controller('LogviewerCtrl', [
    '$anchorScroll', '$http', '$location', '$q', '$rootScope', '$scope',
    '$timeout', 'ThJobArtifactModel', 'ThLog', 'ThLogSliceModel', 'ThJobModel',
    'dateFilter', 'thJobSearchStr', 'ThResultSetModel', 'thDateFormat', 'thReftestStatus',
    function Logviewer(
        $anchorScroll, $http, $location, $q, $rootScope, $scope,
        $timeout, ThJobArtifactModel, ThLog, ThLogSliceModel, ThJobModel,
        dateFilter, thJobSearchStr, ThResultSetModel, thDateFormat, thReftestStatus) {

        var $log = new ThLog('LogviewerCtrl');

        // changes the size of chunks pulled from server
        var LINE_BUFFER_SIZE = 100;
        var LogSlice;

        $rootScope.urlBasePath = $location.absUrl().split('logviewer')[0];

        var query_string = $location.search();
        if (query_string.repo !== "") {
            $rootScope.repoName = query_string.repo;
        }
        if (query_string.job_id !== "") {
            $scope.job_id= query_string.job_id;
            LogSlice = new ThLogSliceModel($scope.job_id, LINE_BUFFER_SIZE);
        }

        $scope.displayedLogLines = [];
        $scope.loading = false;
        $scope.logError = false;
        $scope.currentLineNumber = 0;
        $scope.highestLine = 0;
        $scope.showSuccessful = true;

        $scope.$watch('artifact', function () {
            if (!$scope.artifact) {
                return;
            }
            $scope.showSuccessful = !$scope.hasFailedSteps();
        });

        $scope.hasFailedSteps = function () {
            var steps = $scope.artifact.step_data.steps;
            for (var i = 0; i < steps.length; i++) {
                // We only recently generated step results as part of ingestion,
                // so we have to check the results property is present.
                // TODO: Remove this when the old data has expired, so long as
                // other data submitters also provide a step result.
                if ('result' in steps[i] && steps[i].result !== 'success' &&
                    steps[i].result !== 'skipped') {

                    return true;
                }
            }
            return false;
        };

        // get the css class for the result color
        // used for the whole job, as well as for each step
        $scope.getShadingClass = function(result) {
            return "result-status-shading-" + result;
        };

        $scope.loadMore = function(bounds, element) {
            var deferred = $q.defer(), range, req, above, below;

            if (!$scope.loading) {
                // move the line number either up or down depending which boundary was hit
                $scope.currentLineNumber = moveLineNumber(bounds);

                range = {
                    start: $scope.currentLineNumber,
                    end: $scope.currentLineNumber
                };

                if (bounds.top) {
                    above = getChunkAbove(range);
                } else if (bounds.bottom) {
                    below = getChunkBelow(range);
                } else {
                    range = getChunksSurrounding($scope.currentLineNumber);
                }

                // dont do the call if we already have all the lines
                if (range.start === range.end) {
                    return deferred.promise;
                }

                $scope.loading = true;
                var lineRangeParams = {
                    job_id: $scope.job_id,
                    start_line: range.start,
                    end_line: range.end
                };
                if ($scope.artifact.logname) {
                    lineRangeParams.name = $scope.artifact.logname;
                }
                LogSlice.get_line_range(lineRangeParams, {
                    buffer_size: LINE_BUFFER_SIZE
                }).then(function(data) {
                    var slicedData, length;

                    drawErrorLines(data);

                    if (bounds.top) {
                        for (var i = data.length - 1; i >= 0; i--) {
                            // make sure we are inserting at the right place
                            if ($scope.displayedLogLines[0].index !== data[i].index + 1) {
                                continue;
                            }
                            $scope.displayedLogLines.unshift(data[i]);
                        }

                        $timeout(function () {
                            if (above) {
                                removeChunkBelow();
                            }
                        }, 100);
                    } else if (bounds.bottom) {
                        var sh = element.scrollHeight;
                        var lines = $scope.displayedLogLines;

                        for (var j = 0; j < data.length; j++) {
                            // make sure we are inserting at the right place
                            if (lines[lines.length - 1].index !== data[j].index - 1) {
                                continue;
                            }
                            $scope.displayedLogLines.push(data[j]);
                        }

                        $timeout(function () {
                            if (below) {
                                removeChunkAbove();
                                element.scrollTop -= element.scrollHeight - sh;
                            }
                        }, 100);
                    } else {
                        $scope.displayedLogLines = data;
                    }

                    $scope.loading = false;
                    deferred.resolve();
                }, function (error) {
                    $scope.loading = false;
                    $scope.logError = true;
                    deferred.reject();
                });
            } else {
                deferred.reject();
            }

            return deferred.promise;
        };

        // @@@ it may be possible to do this with the angular date filter?
        $scope.formatTime = function(sec) {
            var h = Math.floor(sec/3600);
            var m = Math.floor(sec%3600/60);
            var s = Math.floor(sec%3600 % 60);
            var secStng = sec.toString();
            var ms = secStng.substr(secStng.indexOf(".")+1, 2);
            return ((h > 0 ? h + "h " : "") + (m > 0 ? m + "m " : "") +
                   (s > 0 ? s + "s " : "") + (ms > 0 ? ms + "ms " : "00ms"));
        };

        $scope.displayTime = function(started, finished) {
            var start = started.substr(started.indexOf(" ")+1, 8);
            var end = finished.substr(finished.indexOf(" ")+1, 8);
            return start + "-" + end;
        };

        $scope.init = function() {

            $scope.logProperties = [];
            ThJobModel.get($scope.repoName, $scope.job_id).then(function(job) {
                var jobStr = thJobSearchStr(job);

                // set the title of the browser window/tab
                $scope.logViewerTitle = "Log for " + jobStr;

                // set the result value and shading color class
                $scope.result = {label: "Result", value: job.result};
                $scope.resultStatusShading = $scope.getShadingClass(job.result);

                // other properties, in order of appearance
                $scope.logProperties = [
                    {label: "Job", value: jobStr},
                    {label: "Machine", value: job.machine_name},
                    {label: "Start", value: dateFilter(job.start_timestamp*1000, thDateFormat)},
                    {label: "End", value: dateFilter(job.end_timestamp*1000, thDateFormat)}
                ];

                // Test to expose the reftest button in the logviewer actionbar
                $scope.isReftest = function() {
                    if (job.job_group_name) {
                        return thReftestStatus(job);
                    }
                };

                // get the revision and linkify it
                ThResultSetModel.getResultSet($scope.repoName, job.result_set_id).then(function(data){
                    var revision = data.data.revision;
                    $scope.logProperties.push({label: "Revision", value: revision});
                    $scope.logRevisionFilterUrl = $scope.urlBasePath +
                        "#/jobs?repo=" + $scope.repoName + "&revision=" +
                        revision;
                });
            });

            ThJobArtifactModel.get_list({job_id: $scope.job_id, name__in: 'text_log_summary,Job Info'})
            .then(function(artifactList) {
                artifactList.forEach(function(artifact) {
                    if (artifact.name === 'text_log_summary') {
                        $scope.artifact = artifact.blob;
                    } else if (artifact.name === 'Job Info') {
                        $scope.job_details = artifact.blob.job_details;
                    }
                });
            });
        };

        /** utility functions **/

        function logFileLineCount () {
            var steps = $scope.artifact.step_data.steps;
            return steps[ steps.length - 1 ].finished_linenumber;
        }

        function moveLineNumber (bounds) {
            var lines = $scope.displayedLogLines, newLine;

            if (bounds.top) {
                return lines[0].index;
            } else if (bounds.bottom) {
                newLine = lines[lines.length - 1].index + 1;
                return (newLine > logFileLineCount()) ? logFileLineCount(): newLine;
            }

            return $scope.currentLineNumber;
        }

        function drawErrorLines (data) {
            if (data.length === 0) {
                return;
            }

            var min = data[0].index;
            var max = data[ data.length - 1 ].index;

            $scope.artifact.step_data.steps.forEach(function(step) {
                step.errors.forEach(function(err) {
                    var line = err.linenumber;

                    if (line < min || line > max) {
                        return;
                    }

                    var index = line - min;
                    data[index].hasError = true;
                });
            });
        }

        function getChunksSurrounding(line) {
            var request = {start: null, end: null};

            getChunkContaining(line, request);
            getChunkAbove(request);
            getChunkBelow(request);

            return request;
        }

        function getChunkContaining (line, request) {
            var index = Math.floor(line/LINE_BUFFER_SIZE);

            request.start = index * LINE_BUFFER_SIZE;
            request.end = (index + 1) * LINE_BUFFER_SIZE;
        }

        function getChunkAbove (request) {
            request.start -= LINE_BUFFER_SIZE;
            request.start = Math.floor(request.start/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.start >= 0) {
                return true;
            } else {
                request.start = 0;
                return false;
            }
        }

        function getChunkBelow (request) {
            var lastLine = logFileLineCount();

            request.end += LINE_BUFFER_SIZE;
            request.end = Math.ceil(request.end/LINE_BUFFER_SIZE)*LINE_BUFFER_SIZE;

            if (request.end <= lastLine) {
                return true;
            } else {
                request.end = lastLine;
                return false;
            }
        }

        function removeChunkAbove (request) {
            $scope.displayedLogLines = $scope.displayedLogLines.slice(LINE_BUFFER_SIZE);
        }

        function removeChunkBelow (request) {
            var endSlice = $scope.displayedLogLines.length - LINE_BUFFER_SIZE;
            $scope.displayedLogLines = $scope.displayedLogLines.slice(0, endSlice);
        }
    }
]);
<|endoftext|>


<commit_before>/**
 * @module /ui/text-area.reel
 */
var AbstractTextArea = require("montage/ui/base/abstract-text-area").AbstractTextArea;

/**
 * @class TextArea
 * @extends Component
 */
exports.TextArea = AbstractTextArea.specialize(/** @lends TextArea# */ {

    hasTemplate: {value: false},

    constructor: {
        value: function TextArea() {
            this.super();
        }
    },

    rows: {value: null},

    enterDocument: {
        value: function(firstTime) {
            this.super(firstTime);

            if (firstTime){
                this.defineBindings({
                    "element.rows": { "<-": "rows" }
                });
            }
        }
    }
});
<commit_msg>add class .form-control to textarea<commit_after>/**
 * @module /ui/text-area.reel
 */
var AbstractTextArea = require("montage/ui/base/abstract-text-area").AbstractTextArea;

/**
 * @class TextArea
 * @extends Component
 */
exports.TextArea = AbstractTextArea.specialize( /** @lends TextArea# */ {

    hasTemplate: {
        value: false
    },

    constructor: {
        value: function TextArea() {
            this.super();

            this.defineBindings({
                "element.rows": {
                    "<-": "rows"
                }
            });
            this.classList.add('form-control');
        }
    },

    rows: {
        value: null
    }
});
<|endoftext|>


<commit_before>/*globals define, _, $*/
/*jshint browser: true, camelcase: false*/

/**
 * @author brollb / https://github.com/brollb
 */

define([
    'js/Constants',
    'js/NodePropertyNames',
    'widgets/EasyDAG/EasyDAGWidget.DecoratorBase',
    'css!./EllipseDecorator.EasyDAGWidget.css',
    'd3'
], function (
    CONSTANTS,
    nodePropertyNames,
    DecoratorBase
) {

    'use strict';

    var EllipseDecorator,
        DECORATOR_ID = 'EllipseDecorator',
        NAME_MARGIN = 15;

    EllipseDecorator = function (options) {
        var opts = _.extend({}, options);

        this._node = options.node;
        this._attrToDisplayName = {};
        this.attributeFields = {};
        this.nameWidth = null;
        this.setAttributes();

        this.color = opts.color || this.color || '#2196f3';
        // Set width, height values
        if (!this.size) {
            this.size = {
                width: 100,
                height: 50
            };
        }

        if (!this.dense) {  // condensed size
            this.dense = {};
            this.dense.width = this.size.width;  // Not initialized
            this.dense.height = this.size.height;
        }

        this.width = this.dense.width;
        this.height = this.dense.height;

        DecoratorBase.call(this, options);
        this.initialize();
        this.condense();
        this.logger.debug('EllipseDecorator ctor');
    };

    _.extend(EllipseDecorator.prototype, DecoratorBase.prototype);

    EllipseDecorator.prototype.initialize = function() {
        this.width = this.dense.width;
        this.height = this.dense.height;

        this.$body = this.$el
            .append('path')
            .attr('class', 'layer-decorator');

        this.$name = this.$el.append('text')
            .attr('class', 'name')
            .style('font-size', '16px')  // FIXME: Move this to css
            .attr('fill', 'black');

        this.$attributes = this.$el.append('g')
            .attr('fill', '#222222');
    };

    EllipseDecorator.prototype.expand = function() {
        var height,
            width,
            rx,
            attrNames = Object.keys(this._attributes),
            displayName,
            path,
            textHeight = 15,

            // Attributes
            initialY = 20,
            attributeMargin = 10,
            leftCol,
            rightCol,
            y = 5;

        // Only expand if the node has attributes to show
        if (attrNames.length > 0) {

            // Get the height from the number of attributes
            height = y + this.dense.height + textHeight*attrNames.length;
            width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.size.width);
            rx = width/2;

            path = [
                `M${-rx},0`,
                `l ${width} 0`,
                `l 0 ${height}`,
                `l -${width} 0`,
                `l 0 -${height}`
            ].join(' ');

            this.$body
                .attr('d', path);

            // Shift name down
            this.$name.attr('y', '20');

            // Add the attribute fields
            y += initialY;
            leftCol = -rx + attributeMargin;
            rightCol = rx - attributeMargin;
            this.$attributes.remove();
            this.$attributes = this.$el.append('g')
                .attr('fill', '#222222');
            for (var i = attrNames.length; i--;) {
                // Create two text boxes (2nd is editable)
                y += textHeight;
                displayName = this._attrToDisplayName[attrNames[i]];
                // Attribute name
                this.$attributes.append('text')
                    .attr('y', y)
                    .attr('x', leftCol)
                    .attr('font-style', 'italic')  // FIXME: move this to css
                    .attr('class', 'attr-title')
                    .attr('text-anchor', 'start')
                    .text(`${displayName}: `);

                // Attribute value
                this.attributeFields[attrNames[i]] = this.$attributes.append('text')
                    .attr('y', y)
                    .attr('x', rightCol)
                    .attr('text-anchor', 'end')  // FIXME: move this to css
                    .text(`${this._attributes[attrNames[i]]}`)
                    .on('click', this.editAttribute.bind(this, attrNames[i], rightCol, y));
            }

            // Update width, height
            this.height = height;
            this.width = width;
            this.expanded = true;
            this.$el
                .attr('transform', `translate(${this.width/2}, 0)`);
        }

        this.onResize();
    };

    EllipseDecorator.prototype.condense = function() {
        var path,
            width,
            rx,
            ry;

        width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.dense.width);
        rx = width/2;
        ry = this.dense.height/2;

        path = [
            `M${-rx},0`,
            `a${rx},${ry} 0 1,0 ${width},0`,
            `a${rx},${ry} 0 1,0 -${width},0`
        ].join(' ');

        this.$body
            .attr('d', path);

        // Clear the attributes
        this.$attributes.remove();
        this.$attributes = this.$el.append('g')
            .attr('fill', '#222222');

        this.height = this.dense.height;
        this.width = width;

        this.$name.attr('y', '0');

        this.$el
            .attr('transform', `translate(${this.width/2}, ${this.height/2})`);
        this.expanded = false;
        this.onResize();
    };

    EllipseDecorator.prototype.onSelect = function() {
        this.expand();
    };

    EllipseDecorator.prototype.onDeselect = function() {
        this.condense();
    };

    EllipseDecorator.prototype.getDisplayName = function() {
        return this._node.baseName;  // Using the base node name for title
    };

    EllipseDecorator.prototype.setAttributes = function() {
        var attrNames = Object.keys(this._node.attributes),
            name;

        if (this.name !== this.getDisplayName()) {
            this.name = this.getDisplayName();
            this.nameWidth = null;
        }

        this._attributes = {};
        for (var i = attrNames.length; i--;) {
            name = this.getAttributeDisplayName(attrNames[i]);
            if (name !== null) {
                this._attrToDisplayName[attrNames[i]] = name;
                this._attributes[attrNames[i]] = this._node.attributes[attrNames[i]];
            }
        }
    };

    EllipseDecorator.prototype.getAttributeDisplayName = function(name) {
        if (name === 'name') {
            return null;
        }
        return name.replace(/_/g, ' ');
    };

    EllipseDecorator.prototype.editAttribute = function(attr) {
        // Edit the node's attribute
        var html = this.attributeFields[attr][0][0],
            position = html.getBoundingClientRect(),

            width = Math.max(position.right-position.left, 15),
            container = $('<div>'),
            parentHtml = $('body'),
            values = this.getEnumValues(attr);

        // foreignObject was not working so we are using a tmp container
        // instead
        container.css('top', position.top);
        container.css('left', position.left);
        container.css('position', 'absolute');
        container.css('width', width);
        container.attr('id', 'CONTAINER-TMP');

        $(parentHtml).append(container);

        // Get the attribute schema
        if (values) {
            var dropdown = document.createElement('select'),
                option,
                self = this,
                arrowMargin = 30;

            for (var i = values.length; i--;) {
                option = document.createElement('option');
                option.setAttribute('value', values[i]);
                option.innerHTML = values[i];
                // set the default
                if (this._attributes[attr] === values[i]) {
                    option.setAttribute('selected', 'selected');
                }
                dropdown.appendChild(option);
            }
            dropdown.style.width = (width + arrowMargin)+ 'px';
            container.append(dropdown);
            dropdown.focus();
            // on select
            dropdown.onblur = function() {
                if (this.value !== self._attributes[attr]) {
                    self.saveAttribute(attr, this.value);
                }
                container.remove();
            };

        } else {  // Check if it is a boolean type TODO
            container.editInPlace({
                enableEmpty: true,
                value: this._attributes[attr],
                css: {
                    'z-index': 10000,
                    'id': 'asdf',
                    'width': width,
                    'xmlns': 'http://www.w3.org/1999/xhtml'
                },
                onChange: (oldValue, newValue) => {
                    this.saveAttribute(attr, newValue);
                },
                onFinish: function () {
                    $(this).remove();
                }
            });
        }
    };

    // Reads the name width if it is currently unknown
    EllipseDecorator.prototype.updateDenseWidth = function() {
        if (!this.nameWidth) {
            this.nameWidth = this.$name.node().getBoundingClientRect().width;

            // Update the condensed width
            if (this.nameWidth > this.dense.width && !this.expanded) {
                // Fix the condensed size
                this.condense();
            }
        }
    };

    EllipseDecorator.prototype.render = function() {
        this.$body
            .transition()
            .attr('stroke', this.color)
            .attr('fill', this.color);

        this.$name
            .attr('text-anchor', 'middle')
            .text(this.name);

        this.updateDenseWidth();
    };

    EllipseDecorator.prototype.update = function(node) {
        this._node = node;
        // Update the attributes
        this.setAttributes();
        if (this.expanded) {
            this.expand();
        } else {
            this.condense();
        }
    };

    EllipseDecorator.prototype.DECORATORID = DECORATOR_ID;

    return EllipseDecorator;
});
<commit_msg>Set dominant-baseline on name. Fixes #43<commit_after>/*globals define, _, $*/
/*jshint browser: true, camelcase: false*/

/**
 * @author brollb / https://github.com/brollb
 */

define([
    'js/Constants',
    'js/NodePropertyNames',
    'widgets/EasyDAG/EasyDAGWidget.DecoratorBase',
    'css!./EllipseDecorator.EasyDAGWidget.css',
    'd3'
], function (
    CONSTANTS,
    nodePropertyNames,
    DecoratorBase
) {

    'use strict';

    var EllipseDecorator,
        DECORATOR_ID = 'EllipseDecorator',
        NAME_MARGIN = 15;

    EllipseDecorator = function (options) {
        var opts = _.extend({}, options);

        this._node = options.node;
        this._attrToDisplayName = {};
        this.attributeFields = {};
        this.nameWidth = null;
        this.setAttributes();

        this.color = opts.color || this.color || '#2196f3';
        // Set width, height values
        if (!this.size) {
            this.size = {
                width: 100,
                height: 50
            };
        }

        if (!this.dense) {  // condensed size
            this.dense = {};
            this.dense.width = this.size.width;  // Not initialized
            this.dense.height = this.size.height;
        }

        this.width = this.dense.width;
        this.height = this.dense.height;

        DecoratorBase.call(this, options);
        this.initialize();
        this.condense();
        this.logger.debug('EllipseDecorator ctor');
    };

    _.extend(EllipseDecorator.prototype, DecoratorBase.prototype);

    EllipseDecorator.prototype.initialize = function() {
        this.width = this.dense.width;
        this.height = this.dense.height;

        this.$body = this.$el
            .append('path')
            .attr('class', 'layer-decorator');

        this.$name = this.$el.append('text')
            .attr('class', 'name')
            .style('font-size', '16px')  // FIXME: Move this to css
            .attr('text-anchor', 'middle')
            .attr('dominant-baseline', 'middle')
            .attr('fill', 'black');

        this.$attributes = this.$el.append('g')
            .attr('fill', '#222222');
    };

    EllipseDecorator.prototype.expand = function() {
        var height,
            width,
            rx,
            attrNames = Object.keys(this._attributes),
            displayName,
            path,
            textHeight = 15,

            // Attributes
            initialY = 20,
            attributeMargin = 10,
            leftCol,
            rightCol,
            y = 5;

        // Only expand if the node has attributes to show
        if (attrNames.length > 0) {

            // Get the height from the number of attributes
            height = y + this.dense.height + textHeight*attrNames.length;
            width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.size.width);
            rx = width/2;

            path = [
                `M${-rx},0`,
                `l ${width} 0`,
                `l 0 ${height}`,
                `l -${width} 0`,
                `l 0 -${height}`
            ].join(' ');

            this.$body
                .attr('d', path);

            // Shift name down
            this.$name.attr('y', '20');

            // Add the attribute fields
            y += initialY;
            leftCol = -rx + attributeMargin;
            rightCol = rx - attributeMargin;
            this.$attributes.remove();
            this.$attributes = this.$el.append('g')
                .attr('fill', '#222222');
            for (var i = attrNames.length; i--;) {
                // Create two text boxes (2nd is editable)
                y += textHeight;
                displayName = this._attrToDisplayName[attrNames[i]];
                // Attribute name
                this.$attributes.append('text')
                    .attr('y', y)
                    .attr('x', leftCol)
                    .attr('font-style', 'italic')  // FIXME: move this to css
                    .attr('class', 'attr-title')
                    .attr('text-anchor', 'start')
                    .text(`${displayName}: `);

                // Attribute value
                this.attributeFields[attrNames[i]] = this.$attributes.append('text')
                    .attr('y', y)
                    .attr('x', rightCol)
                    .attr('text-anchor', 'end')  // FIXME: move this to css
                    .text(`${this._attributes[attrNames[i]]}`)
                    .on('click', this.editAttribute.bind(this, attrNames[i], rightCol, y));
            }

            // Update width, height
            this.height = height;
            this.width = width;
            this.expanded = true;
            this.$el
                .attr('transform', `translate(${this.width/2}, 0)`);
        }

        this.onResize();
    };

    EllipseDecorator.prototype.condense = function() {
        var path,
            width,
            rx,
            ry;

        width = Math.max(this.nameWidth + 2 * NAME_MARGIN, this.dense.width);
        rx = width/2;
        ry = this.dense.height/2;

        path = [
            `M${-rx},0`,
            `a${rx},${ry} 0 1,0 ${width},0`,
            `a${rx},${ry} 0 1,0 -${width},0`
        ].join(' ');

        this.$body
            .attr('d', path);

        // Clear the attributes
        this.$attributes.remove();
        this.$attributes = this.$el.append('g')
            .attr('fill', '#222222');

        this.height = this.dense.height;
        this.width = width;

        this.$name.attr('y', '0');

        this.$el
            .attr('transform', `translate(${this.width/2}, ${this.height/2})`);
        this.expanded = false;
        this.onResize();
    };

    EllipseDecorator.prototype.onSelect = function() {
        this.expand();
    };

    EllipseDecorator.prototype.onDeselect = function() {
        this.condense();
    };

    EllipseDecorator.prototype.getDisplayName = function() {
        return this._node.baseName;  // Using the base node name for title
    };

    EllipseDecorator.prototype.setAttributes = function() {
        var attrNames = Object.keys(this._node.attributes),
            name;

        if (this.name !== this.getDisplayName()) {
            this.name = this.getDisplayName();
            this.nameWidth = null;
        }

        this._attributes = {};
        for (var i = attrNames.length; i--;) {
            name = this.getAttributeDisplayName(attrNames[i]);
            if (name !== null) {
                this._attrToDisplayName[attrNames[i]] = name;
                this._attributes[attrNames[i]] = this._node.attributes[attrNames[i]];
            }
        }
    };

    EllipseDecorator.prototype.getAttributeDisplayName = function(name) {
        if (name === 'name') {
            return null;
        }
        return name.replace(/_/g, ' ');
    };

    EllipseDecorator.prototype.editAttribute = function(attr) {
        // Edit the node's attribute
        var html = this.attributeFields[attr][0][0],
            position = html.getBoundingClientRect(),

            width = Math.max(position.right-position.left, 15),
            container = $('<div>'),
            parentHtml = $('body'),
            values = this.getEnumValues(attr);

        // foreignObject was not working so we are using a tmp container
        // instead
        container.css('top', position.top);
        container.css('left', position.left);
        container.css('position', 'absolute');
        container.css('width', width);
        container.attr('id', 'CONTAINER-TMP');

        $(parentHtml).append(container);

        // Get the attribute schema
        if (values) {
            var dropdown = document.createElement('select'),
                option,
                self = this,
                arrowMargin = 30;

            for (var i = values.length; i--;) {
                option = document.createElement('option');
                option.setAttribute('value', values[i]);
                option.innerHTML = values[i];
                // set the default
                if (this._attributes[attr] === values[i]) {
                    option.setAttribute('selected', 'selected');
                }
                dropdown.appendChild(option);
            }
            dropdown.style.width = (width + arrowMargin)+ 'px';
            container.append(dropdown);
            dropdown.focus();
            // on select
            dropdown.onblur = function() {
                if (this.value !== self._attributes[attr]) {
                    self.saveAttribute(attr, this.value);
                }
                container.remove();
            };

        } else {  // Check if it is a boolean type TODO
            container.editInPlace({
                enableEmpty: true,
                value: this._attributes[attr],
                css: {
                    'z-index': 10000,
                    'id': 'asdf',
                    'width': width,
                    'xmlns': 'http://www.w3.org/1999/xhtml'
                },
                onChange: (oldValue, newValue) => {
                    this.saveAttribute(attr, newValue);
                },
                onFinish: function () {
                    $(this).remove();
                }
            });
        }
    };

    // Reads the name width if it is currently unknown
    EllipseDecorator.prototype.updateDenseWidth = function() {
        if (!this.nameWidth) {
            this.nameWidth = this.$name.node().getBoundingClientRect().width;

            // Update the condensed width
            if (this.nameWidth > this.dense.width && !this.expanded) {
                // Fix the condensed size
                this.condense();
            }
        }
    };

    EllipseDecorator.prototype.render = function() {
        this.$body
            .transition()
            .attr('stroke', this.color)
            .attr('fill', this.color);

        this.$name
            .text(this.name);

        this.updateDenseWidth();
    };

    EllipseDecorator.prototype.update = function(node) {
        this._node = node;
        // Update the attributes
        this.setAttributes();
        if (this.expanded) {
            this.expand();
        } else {
            this.condense();
        }
    };

    EllipseDecorator.prototype.DECORATORID = DECORATOR_ID;

    return EllipseDecorator;
});
<|endoftext|>


<commit_before>import { h } from '@cycle/dom';
import Rx from 'rx';

export default function(state$) {
  const vtree$ = state$.map(({ issues }) => {
    return h('div', [
      h('button', ['fetch']),
      h('ul', issues.map(({ url, title, number }) => {
        return h('li', [
          h('a', { href: url }, [`#${number} ${title}`])
        ]);
      }))
    ])
  });
  const request$ = state$.request$;
  const requests = {
    DOM: vtree$,
    HTTP: request$
  };
  return requests;
}
<commit_msg>change format<commit_after>import { h } from '@cycle/dom';
import Rx from 'rx';

export default function(state$) {
  const vtree$ = state$.map(({ issues }) => {
    return h('div', [
      h('button', ['fetch']),
      h('ul', issues.map(({ url, title, number }) => {
        return h('li', [
          h('a', { href: url }, [`#${number}`]),
          ' ',
          title
        ]);
      }))
    ])
  });
  const request$ = state$.request$;
  const requests = {
    DOM: vtree$,
    HTTP: request$
  };
  return requests;
}
<|endoftext|>


<commit_before>var util = require('./util');
var board = require('./board');
var drag = require('./drag');
var anim = require('./anim');

function pieceClass(p) {
  return ['cg-piece', p.role, p.color].join(' ');
}

function renderPiece(ctrl, key, p) {
  var attrs = {
    class: pieceClass(p)
  };
  if (ctrl.board.draggable.current.orig === key) {
    attrs.style = {
      webkitTransform: util.translate(ctrl.board.draggable.current.pos)
    };
    attrs.class = attrs.class + ' dragging';
  } else if (ctrl.board.animation.current.anims) {
    var animation = ctrl.board.animation.current.anims[key];
    if (animation) {
      attrs.style = {
        webkitTransform: util.translate(animation[1])
      };
    }
  }
  return {
    tag: 'div',
    attrs: attrs
  };
}

function renderGhost(p) {
  return {
    tag: 'div',
    attrs: {
      class: pieceClass(p) + ' ghost'
    }
  };
}

function renderSquare(ctrl, pos) {
  var styleX = (pos[0] - 1) * 12.5 + '%';
  var styleY = (pos[1] - 1) * 12.5 + '%';
  var file = util.files[pos[0] - 1];
  var rank = pos[1];
  var key = file + rank;
  var piece = ctrl.board.pieces.get(key);
  var attrs = {
    class: util.classSet({
      'cg-square': true,
      'selected': ctrl.board.selected === key,
      'check': ctrl.board.check === key,
      'last-move': util.contains2(ctrl.board.lastMove, key),
      'move-dest': util.containsX(ctrl.board.movable.dests[ctrl.board.selected], key),
      'premove-dest': util.containsX(ctrl.board.premovable.dests, key),
      'current-premove': util.contains2(ctrl.board.premovable.current, key),
      'drag-over': ctrl.board.draggable.current.over === key
    }),
    style: ctrl.board.orientation === 'white' ? {
      left: styleX,
      bottom: styleY
    } : {
      right: styleX,
      top: styleY
    }
  };
  if (pos[1] === (ctrl.board.orientation === 'white' ? 1 : 8)) attrs['data-coord-x'] = file;
  if (pos[0] === (ctrl.board.orientation === 'white' ? 8 : 1)) attrs['data-coord-y'] = rank;
  var children = [];
  if (piece) {
    children.push(renderPiece(ctrl, key, piece));
    if (ctrl.board.draggable.current.orig === key) {
      children.push(renderGhost(piece));
    }
  }
  return {
    tag: 'div',
    attrs: attrs,
    children: children
  };
}

function renderBoard(ctrl) {
  var attrs = {
    class: 'cg-board',
    config: function(el, isUpdate, context) {

      if (!isUpdate) {
        // ontouchstart in attrs doesn't work so we do it like that
        if (util.isTouchDevice()) {
          el.addEventListener('touchstart', function(e) {
            var touch = e.touches[0];
            drag.call(ctrl.board, e);
            ctrl.selectSquare(board.getKeyAtDomPos.call(ctrl.board, touch.clientX, touch.clientY));
          });
        } else {
          el.addEventListener('click', function(e) {
            ctrl.selectSquare(board.getKeyAtDomPos.call(ctrl.board, e.clientX, e.clientY));
          });
          el.addEventListener('mousedown', drag.bind(ctrl.board));
        }
      }

      // stay async to prevent a layout force redraw
      if (!isUpdate) requestAnimationFrame(function() {
        ctrl.board.render = function() {
          m.render(el.parentNode, renderBoard(ctrl));
        };
        ctrl.board.bounds = el.getBoundingClientRect();
      });
    }
  };

  return {
    tag: 'div',
    attrs: attrs,
    children: util.allPos.map(function(pos) {
      return renderSquare(ctrl, pos);
    })
  };
}

module.exports = renderBoard;
<commit_msg>fix auto redraw on event listeners<commit_after>var util = require('./util');
var board = require('./board');
var drag = require('./drag');
var anim = require('./anim');

function pieceClass(p) {
  return ['cg-piece', p.role, p.color].join(' ');
}

function renderPiece(ctrl, key, p) {
  var attrs = {
    class: pieceClass(p)
  };
  if (ctrl.board.draggable.current.orig === key) {
    attrs.style = {
      webkitTransform: util.translate(ctrl.board.draggable.current.pos)
    };
    attrs.class = attrs.class + ' dragging';
  } else if (ctrl.board.animation.current.anims) {
    var animation = ctrl.board.animation.current.anims[key];
    if (animation) {
      attrs.style = {
        webkitTransform: util.translate(animation[1])
      };
    }
  }
  return {
    tag: 'div',
    attrs: attrs
  };
}

function renderGhost(p) {
  return {
    tag: 'div',
    attrs: {
      class: pieceClass(p) + ' ghost'
    }
  };
}

function renderSquare(ctrl, pos) {
  var styleX = (pos[0] - 1) * 12.5 + '%';
  var styleY = (pos[1] - 1) * 12.5 + '%';
  var file = util.files[pos[0] - 1];
  var rank = pos[1];
  var key = file + rank;
  var piece = ctrl.board.pieces.get(key);
  var attrs = {
    class: util.classSet({
      'cg-square': true,
      'selected': ctrl.board.selected === key,
      'check': ctrl.board.check === key,
      'last-move': util.contains2(ctrl.board.lastMove, key),
      'move-dest': util.containsX(ctrl.board.movable.dests[ctrl.board.selected], key),
      'premove-dest': util.containsX(ctrl.board.premovable.dests, key),
      'current-premove': util.contains2(ctrl.board.premovable.current, key),
      'drag-over': ctrl.board.draggable.current.over === key
    }),
    style: ctrl.board.orientation === 'white' ? {
      left: styleX,
      bottom: styleY
    } : {
      right: styleX,
      top: styleY
    }
  };
  if (pos[1] === (ctrl.board.orientation === 'white' ? 1 : 8)) attrs['data-coord-x'] = file;
  if (pos[0] === (ctrl.board.orientation === 'white' ? 8 : 1)) attrs['data-coord-y'] = rank;
  var children = [];
  if (piece) {
    children.push(renderPiece(ctrl, key, piece));
    if (ctrl.board.draggable.current.orig === key) {
      children.push(renderGhost(piece));
    }
  }
  return {
    tag: 'div',
    attrs: attrs,
    children: children
  };
}

// from mithril source, more or less
function autoredraw(callback, object) {
  return function(e) {
    m.redraw.strategy("diff");
    m.startComputation();
    try {
      return callback.call(object, e);
    } finally {
      m.endComputation();
    }
  }
}

function boardEventListeners(ctrl, el) {
  // ontouchstart in attrs doesn't work so we do it like that
  if (util.isTouchDevice()) {
    el.addEventListener('touchstart', autoredraw(function(e) {
      var touch = e.touches[0];
      drag.call(ctrl.board, e);
      ctrl.selectSquare(board.getKeyAtDomPos.call(ctrl.board, touch.clientX, touch.clientY));
    }, el));
  } else {
    el.addEventListener('click', autoredraw(function(e) {
      ctrl.selectSquare(board.getKeyAtDomPos.call(ctrl.board, e.clientX, e.clientY));
    }, el));
    el.addEventListener('mousedown', autoredraw(drag.bind(ctrl.board), el));
  }
}

function renderBoard(ctrl) {
  return {
    tag: 'div',
    attrs: {
      class: 'cg-board',
      config: function(el, isUpdate, context) {
        if (!isUpdate) {
          ctrl.board.element = el;
          boardEventListeners(ctrl, el);
        }
      }
    },
    children: util.allPos.map(function(pos) {
      return renderSquare(ctrl, pos);
    })
  };
}

module.exports = renderBoard;
<|endoftext|>


<commit_before>/**
 * https://github.com/chrisweb
 *
 * Copyright 2014 weber chris
 * Released under the MIT license
 * https://chris.lu
 */

/**
 *
 * base view
 *
 * @param {type} Backbone
 * @param {type} _
 * @param {type} $
 * @param {type} Container
 *
 * @returns {unresolved}
 */
define([
    'backbone',
    'underscore',
    'jquery',
    'ribs.container'

], function(Backbone, _, $, Container) {

    'use strict';

    var View = Backbone.View.extend({

        initialize: function(options) {

			var defaultOptions = {
				removeModelOnClose: true, // Boolean: If true, remove model from its collection on view close.
				listSelector: '.list',
				templateVariables: {},
				ModelView: null,
				ModelViewOptions: {}
			};

            this.options = $.extend(defaultOptions, options || {}) ;

            // if oninitialize exists
            if (this.onInitializeStart) {

                // execute it now
                this.onInitializeStart();

            }

            // collection children views, usefull when collection view gets
            // destroyed and we want to take some action on sub views
            this.collectionModelViews = {};

            // list of reference view by model. Usefull to delete all view
            // reference when a model is remove from the collection
            this.referenceModelView = {};

            // check if a template has been defined
            /*if (typeof this.template === 'undefined') {

                throw 'missing template, you need to define a template in your view';

            }*/

            var renderedTemplate;

            if (this.model !== undefined) {

                var templateKeyValues;

                // are there also templateVariables
                if (_.keys(this.options.templateVariables).length > 0) {

                    templateKeyValues = $.extend(this.options.templateVariables, this.getModelAsJson());

                } else {

                    templateKeyValues = this.getModelAsJson();

                }

                renderedTemplate = this.template(templateKeyValues);

            } else if (_.keys(this.options.templateVariables).length > 0) {

                renderedTemplate = this.template(this.options.templateVariables);

            } else {

                renderedTemplate = this.template();

            }

            // sizzle of jquery will throw an error if the view content is
            // not encaplsulated in an html element, for example if the
            // content is just a text
            try {

                var $renderedTemplate = $(renderedTemplate);

            } catch(error) {

                throw 'The view template should have at least one root element and not more then one';

            }

            if ($renderedTemplate.length === 1) {

                var rootElement = $renderedTemplate.first().html('');

                this.setElement(rootElement);

            } else {

                // unfortunatly we have to ensure that the view template has
                // a root html element and that it only has one ... this is
                // because backbone views by design have an $el attribute
                // containing an element in which the template will be rendered
                throw 'The view template should have at least one root element and not more then one';

            }

            if (this.collection !== undefined) {

                this.listenTo(this.collection, 'add', this.addModel);
                this.listenTo(this.collection, 'remove', this.removeModel);
                this.listenTo(this.collection, 'reset', this.reset);

            }

            if (this.model !== undefined) {

                this.listenTo(this.model, 'destroy', this.close);

            }

            // if oninitialize exists
            if (this.onInitialize) {

                // execute it now
                this.onInitialize();

            }

        },
        render: function() {

            // if onRender exists
            if (this.onRenderStart) {

                // execute it now
                this.onRenderStart();

            }

            this.htmlize();

            // if onRender exists
            if (this.onRender) {

                // execute it now
                this.onRender();

            }

            return this;

        },
        htmlize: function() {

            var renderedTemplate;

             // is there a collection?
            if (this.collection !== undefined) {

                // and also a model or templateVariables or nothing?
                if (this.model !== undefined) {

                    var templateKeyValues;

                    // are there also templateVariables
                    if (_.keys(this.options.templateVariables).length > 0) {

                        templateKeyValues = $.extend(this.options.templateVariables, this.getModelAsJson());

                    } else {

                        templateKeyValues = this.getModelAsJson();

                    }

                    renderedTemplate = this.template(templateKeyValues);

                } else if (_.keys(this.options.templateVariables).length > 0) {

                    renderedTemplate = this.template(this.options.templateVariables);

                } else {

                    renderedTemplate = this.template();

                }

                // for each model of the collection append a modelView to
                // collection dom
                var that = this;

                if (this.collection.models.length > 0) {

                    if (that.options.ModelView !== null) {

                        var ModelView = that.options.ModelView;

                    } else {

                        throw 'a collection view needs a ModelView passed on instantiation through the options';

                    }

                    var modelViewsAsHtml = [];

                    _.each(this.collection.models, function(model) {

                        var mergedModelViewOptions = $.extend(that.options.ModelViewOptions, { model: model, parentView: that });

                        var modelView = new ModelView(mergedModelViewOptions);

                        that.collectionModelViews[model.cid] = modelView;

                        var $html = modelView.create();

                        that.referenceModelView[model.cid] = {$html:$html};

                        modelViewsAsHtml.push($html);

                    });

                    var $renderedTemplateCache = $(renderedTemplate);

                    if ($renderedTemplateCache.is(this.options.listSelector)) {

                        $renderedTemplateCache.append(modelViewsAsHtml);

                    } else {

                        $renderedTemplateCache.find(this.options.listSelector).append(modelViewsAsHtml);

                    }

                    // collection view
                    renderedTemplate = $renderedTemplateCache[0];

                }

            } else if (this.model !== undefined) {

                var templateKeyValues;

                // are there also templateVariables
                if (_.keys(this.options.templateVariables).length > 0) {

                    templateKeyValues = $.extend(this.options.templateVariables, this.getModelAsJson());

                } else {

                    templateKeyValues = this.getModelAsJson();

                }

                // model view
                renderedTemplate = this.template(templateKeyValues);

            } else if (_.keys(this.options.templateVariables).length > 0) {

                // templateVariables view
                renderedTemplate = this.template(this.options.templateVariables);

            } else {

                // basic view
                renderedTemplate = this.template();

            }

            this.setElement($(renderedTemplate));

        },
        getModelAsJson: function() {

            var data;

            if (this.model) {

                data = this.model.toJSON();

            }

            return data;

        },
        getCollectionAsJson: function() {

            var data;

            if (this.collection) {

                data = this.collection.toJSON();

            }

            return data;

        },
        close: function() {

            if (this.onCloseStart) {

                this.onCloseStart();

            }

            if (this.collectionModelViews !== null) {

                _.each(this.collectionModelViews, function closeModelViews(modelView) {

                    modelView.close();

                });

                this.collectionModelViews = {};

            }

            // remove the view from dom and stop listening to events that were
            // added with listenTo or that were added to the events declaration
            this.remove();

            // unbind events triggered from within views using backbone events
            this.unbind();

            if (this.model !== undefined && this.options) {

                if (this.options.removeModelOnClose === true && !!this.model.collection === true) {

                    this.model.collection.remove(this.model);

                }

            }

            if (this.collection !== null) {

                // TODO: ...

            }

            // if there is a onClose function ...
            if (this.onClose) {

                // execute it now
                this.onClose();

            }

        },
        create: function() {

            return this.render().$el;

        },
        clear: function() {

            Container.clear(this.options.listSelector);

            this.referenceModelView = {};

        },
        empty: function() {

            //Container.clear(this.options.listSelector);

            if (this.collectionModelViews !== null) {

                _.each(this.collectionModelViews, function closeModelViews(modelView) {

                    modelView.close();

                });

                this.collectionModelViews = {};

            }

            this.referenceModelView = {};

        },
        reset: function(collection) {

            this.empty();

            _.each(collection.models, (function(newModel) {

                this.addModel(newModel);

            }).bind(this));

        },
        addModel: function(model) {

            if (this.options.ModelView !== null) {

                var ModelView = this.options.ModelView;

            } else {

                throw 'a collection view needs a ModelView passed on instantiation through the options';

            }

            var mergedModelViewOptions = $.extend(this.options.ModelViewOptions, { model: model, parentView: this });

            var modelView = new ModelView(mergedModelViewOptions);

            var $element = modelView.create();

            this.referenceModelView[model.cid] = {$html:$element, container: modelView};

            var $container = this.$el.find(this.options.listSelector);

            if ($container.size() > 0) {

                $container.append($element);

            } else if (($container = this.$el.filter(this.options.listSelector)).size()) {

                $container.append($element);

            }

            // TODO: use the container to manage subviews of a list
            //Container.add(this.options.listSelector, modelView);

            this.collectionModelViews[model.cid] = modelView;

        },
        removeModel: function removeModelFunction(model) {

            var view = this.referenceModelView[model.cid];

            if (view === undefined) {
                return view;
            }

            if (view.container !== undefined) {

                // TODO: use the container to manage subviews of a list
                //Container.remove(this.options.listSelector, view.container);

                view.container.close();

                //TODO: close ?

            }

            if (view.$html !== undefined) {

                view.$html.remove();

            }

            delete this.referenceModelView[model.cid];

            delete this.collectionModelViews[model.cid];

            return view;

        }

    });

    return View;

});
<commit_msg>default options improvement<commit_after>/**
 * https://github.com/chrisweb
 *
 * Copyright 2014 weber chris
 * Released under the MIT license
 * https://chris.lu
 */

/**
 *
 * base view
 *
 * @param {type} Backbone
 * @param {type} _
 * @param {type} $
 * @param {type} Container
 *
 * @returns {unresolved}
 */
define([
    'backbone',
    'underscore',
    'jquery',
    'ribs.container'

], function(Backbone, _, $, Container) {

    'use strict';

    var defaultOptions = {
        removeModelOnClose: true, // Boolean: If true, remove model from its collection on view close.
        listSelector: '.list',
        templateVariables: {},
        ModelView: null,
        ModelViewOptions: {}
    };

    var View = Backbone.View.extend({

        initialize: function(options) {

            this.options = $.extend({}, defaultOptions, options || {}) ;

            // if oninitialize exists
            if (this.onInitializeStart) {

                // execute it now
                this.onInitializeStart();

            }

            // collection children views, usefull when collection view gets
            // destroyed and we want to take some action on sub views
            this.collectionModelViews = {};

            // list of reference view by model. Usefull to delete all view
            // reference when a model is remove from the collection
            this.referenceModelView = {};

            // check if a template has been defined
            /*if (typeof this.template === 'undefined') {

                throw 'missing template, you need to define a template in your view';

            }*/

            var renderedTemplate;

            if (this.model !== undefined) {

                var templateKeyValues;

                // are there also templateVariables
                if (_.keys(this.options.templateVariables).length > 0) {

                    templateKeyValues = $.extend(this.options.templateVariables, this.getModelAsJson());

                } else {

                    templateKeyValues = this.getModelAsJson();

                }

                renderedTemplate = this.template(templateKeyValues);

            } else if (_.keys(this.options.templateVariables).length > 0) {

                renderedTemplate = this.template(this.options.templateVariables);

            } else {

                renderedTemplate = this.template();

            }

            // sizzle of jquery will throw an error if the view content is
            // not encaplsulated in an html element, for example if the
            // content is just a text
            try {

                var $renderedTemplate = $(renderedTemplate);

            } catch(error) {

                throw 'The view template should have at least one root element and not more then one';

            }

            if ($renderedTemplate.length === 1) {

                var rootElement = $renderedTemplate.first().html('');

                this.setElement(rootElement);

            } else {

                // unfortunatly we have to ensure that the view template has
                // a root html element and that it only has one ... this is
                // because backbone views by design have an $el attribute
                // containing an element in which the template will be rendered
                throw 'The view template should have at least one root element and not more then one';

            }

            if (this.collection !== undefined) {

                this.listenTo(this.collection, 'add', this.addModel);
                this.listenTo(this.collection, 'remove', this.removeModel);
                this.listenTo(this.collection, 'reset', this.reset);

            }

            if (this.model !== undefined) {

                this.listenTo(this.model, 'destroy', this.close);

            }

            // if oninitialize exists
            if (this.onInitialize) {

                // execute it now
                this.onInitialize();

            }

        },
        render: function() {

            // if onRender exists
            if (this.onRenderStart) {

                // execute it now
                this.onRenderStart();

            }

            this.htmlize();

            // if onRender exists
            if (this.onRender) {

                // execute it now
                this.onRender();

            }

            return this;

        },
        htmlize: function() {

            var renderedTemplate;

             // is there a collection?
            if (this.collection !== undefined) {

                // and also a model or templateVariables or nothing?
                if (this.model !== undefined) {

                    var templateKeyValues;

                    // are there also templateVariables
                    if (_.keys(this.options.templateVariables).length > 0) {

                        templateKeyValues = $.extend(this.options.templateVariables, this.getModelAsJson());

                    } else {

                        templateKeyValues = this.getModelAsJson();

                    }

                    renderedTemplate = this.template(templateKeyValues);

                } else if (_.keys(this.options.templateVariables).length > 0) {

                    renderedTemplate = this.template(this.options.templateVariables);

                } else {

                    renderedTemplate = this.template();

                }

                // for each model of the collection append a modelView to
                // collection dom
                var that = this;

                if (this.collection.models.length > 0) {

                    if (that.options.ModelView !== null) {

                        var ModelView = that.options.ModelView;

                    } else {

                        throw 'a collection view needs a ModelView passed on instantiation through the options';

                    }

                    var modelViewsAsHtml = [];

                    _.each(this.collection.models, function(model) {

                        var mergedModelViewOptions = $.extend(that.options.ModelViewOptions, { model: model, parentView: that });

                        var modelView = new ModelView(mergedModelViewOptions);

                        that.collectionModelViews[model.cid] = modelView;

                        var $html = modelView.create();

                        that.referenceModelView[model.cid] = {$html:$html};

                        modelViewsAsHtml.push($html);

                    });

                    var $renderedTemplateCache = $(renderedTemplate);

                    if ($renderedTemplateCache.is(this.options.listSelector)) {

                        $renderedTemplateCache.append(modelViewsAsHtml);

                    } else {

                        $renderedTemplateCache.find(this.options.listSelector).append(modelViewsAsHtml);

                    }

                    // collection view
                    renderedTemplate = $renderedTemplateCache[0];

                }

            } else if (this.model !== undefined) {

                var templateKeyValues;

                // are there also templateVariables
                if (_.keys(this.options.templateVariables).length > 0) {

                    templateKeyValues = $.extend(this.options.templateVariables, this.getModelAsJson());

                } else {

                    templateKeyValues = this.getModelAsJson();

                }

                // model view
                renderedTemplate = this.template(templateKeyValues);

            } else if (_.keys(this.options.templateVariables).length > 0) {

                // templateVariables view
                renderedTemplate = this.template(this.options.templateVariables);

            } else {

                // basic view
                renderedTemplate = this.template();

            }

            this.setElement($(renderedTemplate));

        },
        getModelAsJson: function() {

            var data;

            if (this.model) {

                data = this.model.toJSON();

            }

            return data;

        },
        getCollectionAsJson: function() {

            var data;

            if (this.collection) {

                data = this.collection.toJSON();

            }

            return data;

        },
        close: function() {

            if (this.onCloseStart) {

                this.onCloseStart();

            }

            if (this.collectionModelViews !== null) {

                _.each(this.collectionModelViews, function closeModelViews(modelView) {

                    modelView.close();

                });

                this.collectionModelViews = {};

            }

            // remove the view from dom and stop listening to events that were
            // added with listenTo or that were added to the events declaration
            this.remove();

            // unbind events triggered from within views using backbone events
            this.unbind();

            if (this.model !== undefined && this.options) {

                if (this.options.removeModelOnClose === true && !!this.model.collection === true) {

                    this.model.collection.remove(this.model);

                }

            }

            if (this.collection !== null) {

                // TODO: ...

            }

            // if there is a onClose function ...
            if (this.onClose) {

                // execute it now
                this.onClose();

            }

        },
        create: function() {

            return this.render().$el;

        },
        clear: function() {

            Container.clear(this.options.listSelector);

            this.referenceModelView = {};

        },
        empty: function() {

            //Container.clear(this.options.listSelector);

            if (this.collectionModelViews !== null) {

                _.each(this.collectionModelViews, function closeModelViews(modelView) {

                    modelView.close();

                });

                this.collectionModelViews = {};

            }

            this.referenceModelView = {};

        },
        reset: function(collection) {

            this.empty();

            _.each(collection.models, (function(newModel) {

                this.addModel(newModel);

            }).bind(this));

        },
        addModel: function(model) {

            if (this.options.ModelView !== null) {

                var ModelView = this.options.ModelView;

            } else {

                throw 'a collection view needs a ModelView passed on instantiation through the options';

            }

            var mergedModelViewOptions = $.extend(this.options.ModelViewOptions, { model: model, parentView: this });

            var modelView = new ModelView(mergedModelViewOptions);

            var $element = modelView.create();

            this.referenceModelView[model.cid] = {$html:$element, container: modelView};

            var $container = this.$el.find(this.options.listSelector);

            if ($container.size() > 0) {

                $container.append($element);

            } else if (($container = this.$el.filter(this.options.listSelector)).size()) {

                $container.append($element);

            }

            // TODO: use the container to manage subviews of a list
            //Container.add(this.options.listSelector, modelView);

            this.collectionModelViews[model.cid] = modelView;

        },
        removeModel: function removeModelFunction(model) {

            var view = this.referenceModelView[model.cid];

            if (view === undefined) {
                return view;
            }

            if (view.container !== undefined) {

                // TODO: use the container to manage subviews of a list
                //Container.remove(this.options.listSelector, view.container);

                view.container.close();

                //TODO: close ?

            }

            if (view.$html !== undefined) {

                view.$html.remove();

            }

            delete this.referenceModelView[model.cid];

            delete this.collectionModelViews[model.cid];

            return view;

        }

    });

    return View;

});
<|endoftext|>


<commit_before>angular.module('ajoslin.mobile-navigate')
.directive('mobileView', ['$rootScope', '$compile', '$controller', '$route', '$change',
function($rootScope, $compile, $controller, $route, $change) {

  function link(scope, viewElement, attrs) {
    //Insert page into dom
    function insertPage(page) {
      var current = $route.current,
      locals = current && current.locals;

      page.element = angular.element(document.createElement("div"));
      page.element.html(locals.$template);
      page.element.addClass('mb-page'); //always has to have page class
      page.scope = scope.$new();
      if (current.controller) {
        locals.$scope = page.scope;
        page.controller = $controller(current.controller, locals);
        page.element.contents().data('$ngControllerController', page.controller);
      }
      $compile(page.element.contents())(page.scope);
      if (locals && locals.$template) {
        // only append page element if a template exists
        viewElement.append(page.element);
      }
      page.scope.$emit('$viewContentLoaded');
      page.scope.$eval(attrs.onLoad);
    }

    var currentTrans;
    scope.$on('$pageTransitionStart', function ($event, dest, source, reverse) {
      function changePage() {
        var current = $route.current ? $route.current.$$route : {};
        var transition = reverse ? source.transition() : dest.transition();

        insertPage(dest);

        //If the page is marked as reverse, reverse the direction
        if (dest.reverse() || current.reverse) {
          reverse = !reverse;
        }
        var promise = $change(dest.element, (source ? source.element : null),
          transition, reverse);

        promise.then(function() {
          if (source) {
            $rootScope.$broadcast('$pageTransitionSuccess', dest, source);
            source.scope.$destroy();
            source.element.remove();
            source = undefined;
          }
        });

        return promise;
      }
      currentTrans && currentTrans.cancel();
      currentTrans = changePage(dest, source, reverse);
    });
  }
  return {
    restrict: 'EA',
    link: link
  };
}])

.directive('scrollable', function($route) {
  var scrollCache = {};
  return {
    restrict: 'EA',
    link: function(scope, elm, attrs) {
      var route = $route.current ? $route.current.$$route : {};
      var template = route.templateUrl || route.template;
      var rawElm = elm[0];

      //On scope creation, see if we remembered any scroll for this templateUrl
      //If we did, set it
      if (template) {
        //Set oldScroll after a timeout so the page has time to fully load
        setTimeout(function() {
          var oldScroll = scrollCache[template];
          if (oldScroll) {
            rawElm.scrollTop = oldScroll;
          }
        });

        scope.$on('$destroy', function() {
          scrollCache[template] = rawElm.scrollTop;
        });
      }
    }
  };
});
<commit_msg>Fix scrollable to use array injection notation<commit_after>angular.module('ajoslin.mobile-navigate')
.directive('mobileView', ['$rootScope', '$compile', '$controller', '$route', '$change',
function($rootScope, $compile, $controller, $route, $change) {

  function link(scope, viewElement, attrs) {
    //Insert page into dom
    function insertPage(page) {
      var current = $route.current,
      locals = current && current.locals;

      page.element = angular.element(document.createElement("div"));
      page.element.html(locals.$template);
      page.element.addClass('mb-page'); //always has to have page class
      page.scope = scope.$new();
      if (current.controller) {
        locals.$scope = page.scope;
        page.controller = $controller(current.controller, locals);
        page.element.contents().data('$ngControllerController', page.controller);
      }
      $compile(page.element.contents())(page.scope);
      if (locals && locals.$template) {
        // only append page element if a template exists
        viewElement.append(page.element);
      }
      page.scope.$emit('$viewContentLoaded');
      page.scope.$eval(attrs.onLoad);
    }

    var currentTrans;
    scope.$on('$pageTransitionStart', function ($event, dest, source, reverse) {
      function changePage() {
        var current = $route.current ? $route.current.$$route : {};
        var transition = reverse ? source.transition() : dest.transition();

        insertPage(dest);

        //If the page is marked as reverse, reverse the direction
        if (dest.reverse() || current.reverse) {
          reverse = !reverse;
        }
        var promise = $change(dest.element, (source ? source.element : null),
          transition, reverse);

        promise.then(function() {
          if (source) {
            $rootScope.$broadcast('$pageTransitionSuccess', dest, source);
            source.scope.$destroy();
            source.element.remove();
            source = undefined;
          }
        });

        return promise;
      }
      currentTrans && currentTrans.cancel();
      currentTrans = changePage(dest, source, reverse);
    });
  }
  return {
    restrict: 'EA',
    link: link
  };
}])

.directive('scrollable', ['$route', function($route) {
  var scrollCache = {};
  return {
    restrict: 'EA',
    link: function(scope, elm, attrs) {
      var route = $route.current ? $route.current.$$route : {};
      var template = route.templateUrl || route.template;
      var rawElm = elm[0];

      //On scope creation, see if we remembered any scroll for this templateUrl
      //If we did, set it
      if (template) {
        //Set oldScroll after a timeout so the page has time to fully load
        setTimeout(function() {
          var oldScroll = scrollCache[template];
          if (oldScroll) {
            rawElm.scrollTop = oldScroll;
          }
        });

        scope.$on('$destroy', function() {
          scrollCache[template] = rawElm.scrollTop;
        });
      }
    }
  };
}]);
<|endoftext|>


<commit_before>// Returns fragment generator, where each returned fragment emits selected data for specified object

'use strict';

var aFrom           = require('es5-ext/array/from')
  , ensureString    = require('es5-ext/object/validate-stringifiable-value')
  , ensureSet       = require('es6-set/valid-set')
  , deferred        = require('deferred')
  , ensureStorage   = require('dbjs-persistence/ensure-storage')
  , assimilateEvent = require('./lib/assimilate-driver-event');

module.exports = function (storage, keyPaths) {
	var keyPathsArray;

	ensureStorage(storage);
	ensureSet(keyPaths);

	keyPathsArray = aFrom(keyPaths);

	return function (ownerId, fragment) {
		ownerId = ensureString(ownerId);
		fragment.promise = deferred(
			storage.getObject(ownerId, { keyPaths: keyPaths })(function (data) {
				data.forEach(function (data) { fragment.update(data.id, data.data); });
			}),
			deferred.map(keyPathsArray, function (keyPath) {
				var id = ownerId + '/' + keyPath;
				return storage.getComputed(id)(function (data) {
					if (!data) return;
					assimilateEvent(fragment, id, data);
				});
			})
		);
		storage.on('owner:' + ownerId, function (event) {
			if (event.type === 'reduced') return;
			if (keyPaths.has(event.keyPath)) {
				if (event.type === 'direct') fragment.update(event.id, event.data);
				else assimilateEvent(fragment, event.id, event.data);
			}
		});
		return fragment;
	};
};
<commit_msg>Improve validation in getAddRecordsToFragments<commit_after>// Returns fragment generator, where each returned fragment emits selected data for specified object

'use strict';

var aFrom           = require('es5-ext/array/from')
  , ensureIterable  = require('es5-ext/iterable/validate-object')
  , ensureString    = require('es5-ext/object/validate-stringifiable-value')
  , Set             = require('es6-set')
  , deferred        = require('deferred')
  , ensureStorage   = require('dbjs-persistence/ensure-storage')
  , assimilateEvent = require('./lib/assimilate-driver-event');

module.exports = function (storage, keyPaths) {
	var keyPathsArray;

	ensureStorage(storage);
	keyPaths = new Set(aFrom(ensureIterable(keyPaths)));

	keyPathsArray = aFrom(keyPaths);

	return function (ownerId, fragment) {
		ownerId = ensureString(ownerId);
		fragment.promise = deferred(
			storage.getObject(ownerId, { keyPaths: keyPaths })(function (data) {
				data.forEach(function (data) { fragment.update(data.id, data.data); });
			}),
			deferred.map(keyPathsArray, function (keyPath) {
				var id = ownerId + '/' + keyPath;
				return storage.getComputed(id)(function (data) {
					if (!data) return;
					assimilateEvent(fragment, id, data);
				});
			})
		);
		storage.on('owner:' + ownerId, function (event) {
			if (event.type === 'reduced') return;
			if (keyPaths.has(event.keyPath)) {
				if (event.type === 'direct') fragment.update(event.id, event.data);
				else assimilateEvent(fragment, event.id, event.data);
			}
		});
		return fragment;
	};
};
<|endoftext|>


<commit_before>const _ = require('underscore');
const ActionWindow = require('../actionwindow.js');

class DynastyActionWindow extends ActionWindow {
    constructor(game) {
        super(game, 'Play cards from provinces', 'dynasty');
    }

    activePrompt() {
        let buttons = [
            { text: 'Pass', arg: 'pass' }
        ];
        if(this.game.manualMode) {
            buttons.unshift({ text: 'Manual Action', arg: 'manual'});
        }
        return {
            menuTitle: 'Click pass when done',
            buttons: buttons,
            promptTitle: this.title
        };
    }

    pass() {
        this.currentPlayer.passDynasty();
        if(!this.currentPlayer.opponent || !this.currentPlayer.opponent.passedDynasty) {
            this.game.addMessage('{0} is the first to pass, and gains 1 fate.', this.currentPlayer);
            this.game.raiseEvent('onFirstPassDuringDynasty', { player: this.currentPlayer }, () => this.game.addFate(this.currentPlayer, 1));
        } else {
            this.game.addMessage('{0} passes.', this.currentPlayer);
        }

        if(!this.currentPlayer.opponent || this.currentPlayer.opponent.passedDynasty) {
            this.complete();
        } else {
            this.nextPlayer();
        }
    }

    nextPlayer() {
        let otherPlayer = this.game.getOtherPlayer(this.currentPlayer);
        if(otherPlayer && !otherPlayer.passedDynasty) {
            this.currentPlayer = otherPlayer;
        }
    }
}

module.exports = DynastyActionWindow;
<commit_msg>Pass fate bug<commit_after>const _ = require('underscore');
const ActionWindow = require('../actionwindow.js');

class DynastyActionWindow extends ActionWindow {
    constructor(game) {
        super(game, 'Play cards from provinces', 'dynasty');
    }

    activePrompt() {
        let buttons = [
            { text: 'Pass', arg: 'pass' }
        ];
        if(this.game.manualMode) {
            buttons.unshift({ text: 'Manual Action', arg: 'manual'});
        }
        return {
            menuTitle: 'Click pass when done',
            buttons: buttons,
            promptTitle: this.title
        };
    }

    pass() {
        this.currentPlayer.passDynasty();
        if(!this.currentPlayer.opponent || !this.currentPlayer.opponent.passedDynasty) {
            this.game.addMessage('{0} is the first to pass, and gains 1 fate.', this.currentPlayer);
            this.game.raiseEvent('onFirstPassDuringDynasty', { player: this.currentPlayer }, event => this.game.addFate(event.player, 1));
        } else {
            this.game.addMessage('{0} passes.', this.currentPlayer);
        }

        if(!this.currentPlayer.opponent || this.currentPlayer.opponent.passedDynasty) {
            this.complete();
        } else {
            this.nextPlayer();
        }
    }

    nextPlayer() {
        let otherPlayer = this.game.getOtherPlayer(this.currentPlayer);
        if(otherPlayer && !otherPlayer.passedDynasty) {
            this.currentPlayer = otherPlayer;
        }
    }
}

module.exports = DynastyActionWindow;
<|endoftext|>


<commit_before>app.controller('HomeController', ['$http', function($http, $firebaseAuth) {
  console.log('HomeController running');
  var auth = $firebaseAuth();
  var self = this;

  self.logIn = function() {
    auth.$signInWithPopup("google").then(function(firebaseUser) {
      console.log("Firebase Authenticated as: ", firebaseUser.user.displayName);
    }).catch(function(error) {
      console.log("Authentication failed: ", error);
    });
  };

  self.dataArray = [
    {
      src: 'http://www.parasholidays.in/blog/wp-content/uploads/2014/05/holiday-tour-packages-for-usa.jpg'
    },
    {
      src: 'http://clickker.in/wp-content/uploads/2016/03/new-zealand-fy-8-1-Copy.jpg'
    },
    {
      src: 'http://images.kuoni.co.uk/73/indonesia-34834203-1451484722-ImageGalleryLightbox.jpg'
    },
    {
      src: 'http://images.kuoni.co.uk/73/malaysia-21747826-1446726337-ImageGalleryLightbox.jpg'
    },
    {
      src: 'http://www.kimcambodiadriver.com/uploads/images/tours/kim-cambodia-driver-angkor-wat.jpg'
    },
    {
      src: 'https://www.travcoa.com/sites/default/files/styles/flexslider_full/public/tours/images/imperialvietnam-halong-bay-14214576.jpg?itok=O-q1yr5_'
    }
  ];
}]);

//------------------------ SCIENCE PICTURES FROM MARK------------------------ //
// {
//   src: 'http://www.scind.org/content_images/full/1422719896Genome.jpg'
// },
// {
//   src: 'http://www.technology.org/texorgwp/wp-content/uploads/2015/10/18167.jpg'
// },
// {
//   src: 'https://i.ytimg.com/vi/-Wc_7_1PYis/maxresdefault.jpg'
// },
// {
//   src: 'http://cdn3.bigcommerce.com/s-8y8vwv/product_images/theme_images/5590295e7495e.image.jpg?t=1459712154'
// },
// {
//   src: 'https://s3.amazonaws.com/classconnection/580/flashcards/6473580/jpg/carcharodon_carcharias-1493631F70B6169541E.jpg'
// },
// {
//   src: 'https://s-media-cache-ak0.pinimg.com/originals/4c/0b/23/4c0b2337981a1eb4aab3eb3dc0df5465.jpg'
// },
// {
//   src: 'http://www.publicdomainpictures.net/pictures/180000/velka/antelope-canyon-rock-formation.jpg'
// },
// {
//   src: 'http://www.symmetrymagazine.org/sites/default/files/styles/2015_hero/public/images/standard/CMS-s_0.jpg?itok=y0aRfGCC'
// },
// {
//   src: 'http://circuits-central.com/wp-content/uploads/2015/09/home-2-1024x631.jpg'
// },
// {
//   src: 'https://i.ytimg.com/vi/e6dS6grtt_w/maxresdefault.jpg'
// },
// {
//   src: 'http://microbe.net/wp-content/uploads/2016/09/STS132_undocking_iss2.jpg'
// },
// {
//   src: 'https://cdn.pixabay.com/photo/2013/03/17/07/16/industry-94448_960_720.jpg'
// },
// {
//   src: 'http://www.nasa.gov/sites/default/files/synergy_0.jpg'
// }
<commit_msg>Add  to import section of HomeController<commit_after>app.controller('HomeController', ['$http', '$firebaseAuth', function($http, $firebaseAuth) {
  console.log('HomeController running');
  var auth = $firebaseAuth();
  var self = this;

  self.logIn = function() {
    auth.$signInWithPopup("google").then(function(firebaseUser) {
      console.log("Firebase Authenticated as: ", firebaseUser.user.displayName);
    }).catch(function(error) {
      console.log("Authentication failed: ", error);
    });
  };

  self.dataArray = [
    {
      src: 'http://www.parasholidays.in/blog/wp-content/uploads/2014/05/holiday-tour-packages-for-usa.jpg'
    },
    {
      src: 'http://clickker.in/wp-content/uploads/2016/03/new-zealand-fy-8-1-Copy.jpg'
    },
    {
      src: 'http://images.kuoni.co.uk/73/indonesia-34834203-1451484722-ImageGalleryLightbox.jpg'
    },
    {
      src: 'http://images.kuoni.co.uk/73/malaysia-21747826-1446726337-ImageGalleryLightbox.jpg'
    },
    {
      src: 'http://www.kimcambodiadriver.com/uploads/images/tours/kim-cambodia-driver-angkor-wat.jpg'
    },
    {
      src: 'https://www.travcoa.com/sites/default/files/styles/flexslider_full/public/tours/images/imperialvietnam-halong-bay-14214576.jpg?itok=O-q1yr5_'
    }
  ];
}]);

//------------------------ SCIENCE PICTURES FROM MARK------------------------ //
// {
//   src: 'http://www.scind.org/content_images/full/1422719896Genome.jpg'
// },
// {
//   src: 'http://www.technology.org/texorgwp/wp-content/uploads/2015/10/18167.jpg'
// },
// {
//   src: 'https://i.ytimg.com/vi/-Wc_7_1PYis/maxresdefault.jpg'
// },
// {
//   src: 'http://cdn3.bigcommerce.com/s-8y8vwv/product_images/theme_images/5590295e7495e.image.jpg?t=1459712154'
// },
// {
//   src: 'https://s3.amazonaws.com/classconnection/580/flashcards/6473580/jpg/carcharodon_carcharias-1493631F70B6169541E.jpg'
// },
// {
//   src: 'https://s-media-cache-ak0.pinimg.com/originals/4c/0b/23/4c0b2337981a1eb4aab3eb3dc0df5465.jpg'
// },
// {
//   src: 'http://www.publicdomainpictures.net/pictures/180000/velka/antelope-canyon-rock-formation.jpg'
// },
// {
//   src: 'http://www.symmetrymagazine.org/sites/default/files/styles/2015_hero/public/images/standard/CMS-s_0.jpg?itok=y0aRfGCC'
// },
// {
//   src: 'http://circuits-central.com/wp-content/uploads/2015/09/home-2-1024x631.jpg'
// },
// {
//   src: 'https://i.ytimg.com/vi/e6dS6grtt_w/maxresdefault.jpg'
// },
// {
//   src: 'http://microbe.net/wp-content/uploads/2016/09/STS132_undocking_iss2.jpg'
// },
// {
//   src: 'https://cdn.pixabay.com/photo/2013/03/17/07/16/industry-94448_960_720.jpg'
// },
// {
//   src: 'http://www.nasa.gov/sites/default/files/synergy_0.jpg'
// }
<|endoftext|>


<commit_before>
/*
 * Use for Async operations before displaying page
 *
module.exports.prepare = function(opts, done) {
  done({});
};
 */

 /*
  * Compute Vue scope
  *
 module.exports.scope = function(data, opts) {
   return {};
 };
  */

 /*
  * Use as page starting point
  *
module.exports.render = function(data, vm, opts, manifest) {
};
 */
<commit_msg>refactor: Page asset update<commit_after>
/*
 * Use for Async operations before displaying page
 *
module.exports.prepare = function() {
  this.done({});
};
 */

 /*
  * Compute Vue scope
  *
 module.exports.scope = function() {
   return {};
 };
  */

 /*
  * Use as page starting point
  *
module.exports.render = function() {
};
 */
<|endoftext|>