<commit_before>(function () {

'use strict';

// The core module for the OpenSlides projector
angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])

// Can be used to find out if the projector or the side is used
.constant('REALM', 'projector')

.run([
    '$http',
    'autoupdate',
    'DS',
    function ($http, autoupdate, DS) {
        autoupdate.newConnect();

        // If the connection aborts, we try to ping the server with whoami requests. If
        // the server is flushed, we clear the datastore, so the message 'this projector
        // cannot be shown' will be displayed. Otherwise establish the websocket connection.
        autoupdate.registerRetryConnectCallback(function () {
            return $http.get('/users/whoami').then(function (success) {
                if (success.data.user_id === null && !success.data.guest_enabled) {
                    DS.clear();
                } else {
                    autoupdate.newConnect();
                }
            });
        });
    }
])

// Provider to register slides in a .config() statement.
.provider('slides', [
    function() {
        var slidesMap = {};

        this.registerSlide = function(name, config) {
            slidesMap[name] = config;
            return this;
        };

        this.$get = function($templateRequest, $q) {
            var self = this;
            return {
                getElements: function(projector) {
                    var elements = [];
                    var factory = this;
                    _.forEach(projector.elements, function(element) {
                        if (element.name in slidesMap) {
                            element.template = slidesMap[element.name].template;
                            elements.push(element);
                        } else {
                            console.error("Unknown slide: " + element.name);
                        }
                    });
                    return elements;
                }
            };
        };
    }
])

.config([
    'slidesProvider',
    function(slidesProvider) {
        slidesProvider.registerSlide('core/clock', {
            template: 'static/templates/core/slide_clock.html',
        });

        slidesProvider.registerSlide('core/countdown', {
            template: 'static/templates/core/slide_countdown.html',
        });

        slidesProvider.registerSlide('core/projector-message', {
            template: 'static/templates/core/slide_message.html',
        });
    }
])

.controller('LanguageCtrl', [
    '$scope',
    'Languages',
    'Config',
    'ProjectorID',
    function ($scope, Languages, Config, ProjectorID) {
        // for the dynamic title
        $scope.projectorId = ProjectorID();

        $scope.$watch(function () {
            return Config.lastModified('projector_language');
        }, function () {
            var lang = Config.get('projector_language');
            if (!lang || lang.value == 'browser') {
                $scope.selectedLanguage = Languages.getBrowserLanguage();
            } else {
                $scope.selectedLanguage = lang.value;
            }
            Languages.setCurrentLanguage($scope.selectedLanguage);
        });
    }
])

// Projector Container Controller
.controller('ProjectorContainerCtrl', [
    '$scope',
    '$timeout',
    '$location',
    'gettext',
    'Projector',
    function($scope, $timeout, $location, gettext, Projector) {
        $scope.showError = true;

        // watch for changes in Projector
        $scope.$watch(function () {
            return Projector.lastModified($scope.projectorId);
        }, function () {
            var projector = Projector.get($scope.projectorId);
            if (projector) {
                $scope.showError = false;
                $scope.projectorWidth = projector.width;
                $scope.projectorHeight = projector.height;
                $scope.recalculateIframe();
            } else {
                $scope.showError = true;
                // delay displaying the error message, because with a slow internet
                // connection, the autoupdate with the projector may be delayed. We
                // de not want to irritate the user by showing this error to early.
                $timeout(function () {
                    if ($scope.showError) {
                        $scope.error = gettext('Can not open the projector.');
                    }
                }, 3000);
            }
        });

        // recalculate the actual Iframesize and scale
        $scope.recalculateIframe = function () {
            var scale_width = window.innerWidth / $scope.projectorWidth;
            var scale_height = window.innerHeight / $scope.projectorHeight;

            // Iframe has to be scaled down or saceUp is activated
            if (scale_width <= scale_height) {
                // width is the reference
                $scope.iframeWidth = window.innerWidth;
                $scope.scale = scale_width;
                $scope.iframeHeight = $scope.projectorHeight * scale_width;
            } else {
                // height is the reference
                $scope.iframeHeight = window.innerHeight;
                $scope.scale = scale_height;
                $scope.iframeWidth = $scope.projectorWidth * scale_height;
            }
        };

        // watch for changes in the windowsize
        $(window).on("resize.doResize", function () {
            $scope.$apply(function() {
                $scope.recalculateIframe();
            });
        });

        $scope.$on("$destroy",function (){
            $(window).off("resize.doResize");
        });
    }
])

.controller('ProjectorCtrl', [
    '$scope',
    '$location',
    '$timeout',
    'Projector',
    'slides',
    'Config',
    'ProjectorID',
    'Logos',
    function($scope, $location, $timeout, Projector, slides, Config, ProjectorID, Logos) {
        var projectorId = ProjectorID();

        $scope.broadcast = 0;

        var setElements = function (projector) {
            // Get all elements, that should be projected.
            var newElements = [];
            _.forEach(slides.getElements(projector), function (element) {
                if (!element.error) {
                    // Exclude the clock if it should be disabled.
                    if (Config.get('projector_enable_clock').value || element.name !== 'core/clock') {
                        newElements.push(element);
                    }
                } else {
                    console.error("Error for slide " + element.name + ": " + element.error);
                }
            });

            // Now we have to align $scope.elements to newElements:
            // We cannot just assign them, because the ng-repeat would reload every
            // element. This should be prevented (see #3259). To change $scope.elements:
            // 1) remove all elements from scope, that are not in newElements (compared by the uuid)
            // 2) Every new element in newElements, that is not in $scope.elements, get inserted there.
            // 3) If there is the same element in newElements and $scope.elements every changed property
            //    is copied from the new element to the scope element.

            $scope.elements = _.filter($scope.elements, function (element) {
                return _.some(newElements, function (newElement) {
                    return element.uuid === newElement.uuid;
                });
            });

            _.forEach(newElements, function (newElement) {
                var matchingElement = _.find($scope.elements, function (element) {
                    return element.uuid === newElement.uuid;
                });
                if (matchingElement) {
                    // copy all changed properties.
                    _.forEach(newElement, function (value, key) {
                        if (newElement.hasOwnProperty(key) && !key.startsWith('$')) {
                            if (typeof matchingElement[key] === 'undefined' || matchingElement[key] !== value) {
                                matchingElement[key] = value;
                            }
                        }
                    });
                } else {
                    $scope.elements.push(newElement);
                }
            });
        };

        // This function scrolls the projector smoothly. It scrolls is steps calling each
        // step with a little timeout.
        var STEPS = 5;
        $scope.scroll = 0;
        var setScroll = function (scroll) {
            scroll = -250 * scroll;
            if ($scope.scrollTimeout) {
                $timeout.cancel($scope.scrollTimeout);
            }
            var oldScroll = $scope.scroll;
            var diff = scroll - oldScroll;
            var count = 0;
            if (scroll !== oldScroll) {
                var scrollFunction = function () {
                    $scope.scroll += diff/STEPS;
                    count++;
                    if (count < STEPS) {
                        $scope.scrollTimeout = $timeout(scrollFunction, 1);
                    }
                };
                scrollFunction();
            }
        };

        $scope.$watch(function () {
            return Projector.lastModified(projectorId);
        }, function () {
            $scope.projector = Projector.get(projectorId);
            if ($scope.projector) {
                if ($scope.broadcast === 0) {
                    setElements($scope.projector);
                    $scope.blank = $scope.projector.blank;
                }
                setScroll($scope.projector.scroll);
            } else {
                // Blank projector on error
                $scope.elements = [];
                $scope.projector = {
                    scale: 0,
                    blank: true
                };
                setScroll(0);
            }
        });

        $scope.$watch(function () {
            return Config.lastModified('projector_broadcast');
        }, function () {
            var bc = Config.get('projector_broadcast');
            if (bc) {
                if ($scope.broadcast != bc.value) {
                    $scope.broadcast = bc.value;
                    if ($scope.broadcastDeregister) {
                        // revert to original $scope.projector
                        $scope.broadcastDeregister();
                        $scope.broadcastDeregister = null;
                        setElements($scope.projector);
                        $scope.blank = $scope.projector.blank;
                    }
                }
                if ($scope.broadcast > 0) {
                    // get elements and blank from broadcast projector
                    $scope.broadcastDeregister = $scope.$watch(function () {
                        return Projector.lastModified($scope.broadcast);
                    }, function () {
                        if ($scope.broadcast > 0) {
                            var broadcast_projector = Projector.get($scope.broadcast);
                            if (broadcast_projector) {
                                setElements(broadcast_projector);
                                $scope.blank = broadcast_projector.blank;
                            }
                        }
                    });
                }
            }
        });

        $scope.$watch(function () {
            return Config.lastModified('projector_enable_clock');
        }, function () {
            setElements($scope.projector);
        });

        $scope.$on('$destroy', function() {
            if ($scope.broadcastDeregister) {
                $scope.broadcastDeregister();
                $scope.broadcastDeregister = null;
            }
        });
    }
])

.controller('SlideClockCtrl', [
    '$scope',
    '$interval',
    function($scope, $interval) {
        // Attention! Each object that is used here has to be dealt on server side.
        // Add it to the coresponding get_requirements method of the ProjectorElement
        // class.
        $scope.servertime = ( Date.now() / 1000 - $scope.serverOffset ) * 1000;
        var interval = $interval(function () {
            $scope.servertime = ( Date.now() / 1000 - $scope.serverOffset ) * 1000;
        }, 30000); // Update the clock every 30 seconds

        $scope.$on('$destroy', function() {
            if (interval) {
                $interval.cancel(interval);
            }
        });
    }
])

.controller('SlideCountdownCtrl', [
    '$scope',
    '$interval',
    'Countdown',
    function($scope, $interval, Countdown) {
        // Attention! Each object that is used here has to be dealt on server side.
        // Add it to the coresponding get_requirements method of the ProjectorElement
        // class.
        var id = $scope.element.id;
        var interval;
        var calculateCountdownTime = function (countdown) {
            countdown.seconds = Math.floor( $scope.countdown.countdown_time - Date.now() / 1000 + $scope.serverOffset );
        };
        $scope.$watch(function () {
            return Countdown.lastModified(id);
        }, function () {
            $scope.countdown = Countdown.get(id);
            if (interval) {
                $interval.cancel(interval);
            }
            if ($scope.countdown) {
                if ($scope.countdown.running) {
                    calculateCountdownTime($scope.countdown);
                    interval = $interval(function () { calculateCountdownTime($scope.countdown); }, 1000);
                } else {
                    $scope.countdown.seconds = $scope.countdown.countdown_time;
                }
            }
        });
        $scope.$on('$destroy', function() {
            // Cancel the interval if the controller is destroyed
            if (interval) {
                $interval.cancel(interval);
            }
        });
    }
])

.controller('SlideMessageCtrl', [
    '$scope',
    'ProjectorMessage',
    'Projector',
    'ProjectorID',
    'gettextCatalog',
    function($scope, ProjectorMessage, Projector, ProjectorID, gettextCatalog) {
        // Attention! Each object that is used here has to be dealt on server side.
        // Add it to the coresponding get_requirements method of the ProjectorElement
        // class.
        var id = $scope.element.id;

        if ($scope.element.identify) {
            var projector = Projector.get(ProjectorID());
            $scope.identifyMessage = gettextCatalog.getString('Projector') + ' ' + projector.id + ': ' + gettextCatalog.getString(projector.name);
        } else {
            $scope.message = ProjectorMessage.get(id);
            ProjectorMessage.bindOne(id, $scope, 'message');
        }
    }
]);

}());
<commit_msg>Scroll improvement<commit_after>(function () {

'use strict';

// The core module for the OpenSlides projector
angular.module('OpenSlidesApp.core.projector', ['OpenSlidesApp.core'])

// Can be used to find out if the projector or the side is used
.constant('REALM', 'projector')

.run([
    '$http',
    'autoupdate',
    'DS',
    function ($http, autoupdate, DS) {
        autoupdate.newConnect();

        // If the connection aborts, we try to ping the server with whoami requests. If
        // the server is flushed, we clear the datastore, so the message 'this projector
        // cannot be shown' will be displayed. Otherwise establish the websocket connection.
        autoupdate.registerRetryConnectCallback(function () {
            return $http.get('/users/whoami').then(function (success) {
                if (success.data.user_id === null && !success.data.guest_enabled) {
                    DS.clear();
                } else {
                    autoupdate.newConnect();
                }
            });
        });
    }
])

// Provider to register slides in a .config() statement.
.provider('slides', [
    function() {
        var slidesMap = {};

        this.registerSlide = function(name, config) {
            slidesMap[name] = config;
            return this;
        };

        this.$get = function($templateRequest, $q) {
            var self = this;
            return {
                getElements: function(projector) {
                    var elements = [];
                    var factory = this;
                    _.forEach(projector.elements, function(element) {
                        if (element.name in slidesMap) {
                            element.template = slidesMap[element.name].template;
                            elements.push(element);
                        } else {
                            console.error("Unknown slide: " + element.name);
                        }
                    });
                    return elements;
                }
            };
        };
    }
])

.config([
    'slidesProvider',
    function(slidesProvider) {
        slidesProvider.registerSlide('core/clock', {
            template: 'static/templates/core/slide_clock.html',
        });

        slidesProvider.registerSlide('core/countdown', {
            template: 'static/templates/core/slide_countdown.html',
        });

        slidesProvider.registerSlide('core/projector-message', {
            template: 'static/templates/core/slide_message.html',
        });
    }
])

.controller('LanguageCtrl', [
    '$scope',
    'Languages',
    'Config',
    'ProjectorID',
    function ($scope, Languages, Config, ProjectorID) {
        // for the dynamic title
        $scope.projectorId = ProjectorID();

        $scope.$watch(function () {
            return Config.lastModified('projector_language');
        }, function () {
            var lang = Config.get('projector_language');
            if (!lang || lang.value == 'browser') {
                $scope.selectedLanguage = Languages.getBrowserLanguage();
            } else {
                $scope.selectedLanguage = lang.value;
            }
            Languages.setCurrentLanguage($scope.selectedLanguage);
        });
    }
])

// Projector Container Controller
.controller('ProjectorContainerCtrl', [
    '$scope',
    '$timeout',
    '$location',
    'gettext',
    'Projector',
    function($scope, $timeout, $location, gettext, Projector) {
        $scope.showError = true;

        // watch for changes in Projector
        $scope.$watch(function () {
            return Projector.lastModified($scope.projectorId);
        }, function () {
            var projector = Projector.get($scope.projectorId);
            if (projector) {
                $scope.showError = false;
                $scope.projectorWidth = projector.width;
                $scope.projectorHeight = projector.height;
                $scope.recalculateIframe();
            } else {
                $scope.showError = true;
                // delay displaying the error message, because with a slow internet
                // connection, the autoupdate with the projector may be delayed. We
                // de not want to irritate the user by showing this error to early.
                $timeout(function () {
                    if ($scope.showError) {
                        $scope.error = gettext('Can not open the projector.');
                    }
                }, 3000);
            }
        });

        // recalculate the actual Iframesize and scale
        $scope.recalculateIframe = function () {
            var scale_width = window.innerWidth / $scope.projectorWidth;
            var scale_height = window.innerHeight / $scope.projectorHeight;

            // Iframe has to be scaled down or saceUp is activated
            if (scale_width <= scale_height) {
                // width is the reference
                $scope.iframeWidth = window.innerWidth;
                $scope.scale = scale_width;
                $scope.iframeHeight = $scope.projectorHeight * scale_width;
            } else {
                // height is the reference
                $scope.iframeHeight = window.innerHeight;
                $scope.scale = scale_height;
                $scope.iframeWidth = $scope.projectorWidth * scale_height;
            }
        };

        // watch for changes in the windowsize
        $(window).on("resize.doResize", function () {
            $scope.$apply(function() {
                $scope.recalculateIframe();
            });
        });

        $scope.$on("$destroy",function (){
            $(window).off("resize.doResize");
        });
    }
])

.controller('ProjectorCtrl', [
    '$scope',
    '$location',
    '$timeout',
    'Projector',
    'slides',
    'Config',
    'ProjectorID',
    'Logos',
    function($scope, $location, $timeout, Projector, slides, Config, ProjectorID, Logos) {
        var projectorId = ProjectorID();

        $scope.broadcast = 0;

        var setElements = function (projector) {
            // Get all elements, that should be projected.
            var newElements = [];
            _.forEach(slides.getElements(projector), function (element) {
                if (!element.error) {
                    // Exclude the clock if it should be disabled.
                    if (Config.get('projector_enable_clock').value || element.name !== 'core/clock') {
                        newElements.push(element);
                    }
                } else {
                    console.error("Error for slide " + element.name + ": " + element.error);
                }
            });

            // Now we have to align $scope.elements to newElements:
            // We cannot just assign them, because the ng-repeat would reload every
            // element. This should be prevented (see #3259). To change $scope.elements:
            // 1) remove all elements from scope, that are not in newElements (compared by the uuid)
            // 2) Every new element in newElements, that is not in $scope.elements, get inserted there.
            // 3) If there is the same element in newElements and $scope.elements every changed property
            //    is copied from the new element to the scope element.

            $scope.elements = _.filter($scope.elements, function (element) {
                return _.some(newElements, function (newElement) {
                    return element.uuid === newElement.uuid;
                });
            });

            _.forEach(newElements, function (newElement) {
                var matchingElement = _.find($scope.elements, function (element) {
                    return element.uuid === newElement.uuid;
                });
                if (matchingElement) {
                    // copy all changed properties.
                    _.forEach(newElement, function (value, key) {
                        if (newElement.hasOwnProperty(key) && !key.startsWith('$')) {
                            if (typeof matchingElement[key] === 'undefined' || matchingElement[key] !== value) {
                                matchingElement[key] = value;
                            }
                        }
                    });
                } else {
                    $scope.elements.push(newElement);
                }
            });
        };

        $scope.scroll = 0;
        var setScroll = function (scroll) {
            $scope.scroll = -250 * scroll;
        };

        $scope.$watch(function () {
            return Projector.lastModified(projectorId);
        }, function () {
            $scope.projector = Projector.get(projectorId);
            if ($scope.projector) {
                if ($scope.broadcast === 0) {
                    setElements($scope.projector);
                    $scope.blank = $scope.projector.blank;
                }
                setScroll($scope.projector.scroll);
            } else {
                // Blank projector on error
                $scope.elements = [];
                $scope.projector = {
                    scale: 0,
                    blank: true
                };
                setScroll(0);
            }
        });

        $scope.$watch(function () {
            return Config.lastModified('projector_broadcast');
        }, function () {
            var bc = Config.get('projector_broadcast');
            if (bc) {
                if ($scope.broadcast != bc.value) {
                    $scope.broadcast = bc.value;
                    if ($scope.broadcastDeregister) {
                        // revert to original $scope.projector
                        $scope.broadcastDeregister();
                        $scope.broadcastDeregister = null;
                        setElements($scope.projector);
                        $scope.blank = $scope.projector.blank;
                    }
                }
                if ($scope.broadcast > 0) {
                    // get elements and blank from broadcast projector
                    $scope.broadcastDeregister = $scope.$watch(function () {
                        return Projector.lastModified($scope.broadcast);
                    }, function () {
                        if ($scope.broadcast > 0) {
                            var broadcast_projector = Projector.get($scope.broadcast);
                            if (broadcast_projector) {
                                setElements(broadcast_projector);
                                $scope.blank = broadcast_projector.blank;
                            }
                        }
                    });
                }
            }
        });

        $scope.$watch(function () {
            return Config.lastModified('projector_enable_clock');
        }, function () {
            setElements($scope.projector);
        });

        $scope.$on('$destroy', function() {
            if ($scope.broadcastDeregister) {
                $scope.broadcastDeregister();
                $scope.broadcastDeregister = null;
            }
        });
    }
])

.controller('SlideClockCtrl', [
    '$scope',
    '$interval',
    function($scope, $interval) {
        // Attention! Each object that is used here has to be dealt on server side.
        // Add it to the coresponding get_requirements method of the ProjectorElement
        // class.
        $scope.servertime = ( Date.now() / 1000 - $scope.serverOffset ) * 1000;
        var interval = $interval(function () {
            $scope.servertime = ( Date.now() / 1000 - $scope.serverOffset ) * 1000;
        }, 30000); // Update the clock every 30 seconds

        $scope.$on('$destroy', function() {
            if (interval) {
                $interval.cancel(interval);
            }
        });
    }
])

.controller('SlideCountdownCtrl', [
    '$scope',
    '$interval',
    'Countdown',
    function($scope, $interval, Countdown) {
        // Attention! Each object that is used here has to be dealt on server side.
        // Add it to the coresponding get_requirements method of the ProjectorElement
        // class.
        var id = $scope.element.id;
        var interval;
        var calculateCountdownTime = function (countdown) {
            countdown.seconds = Math.floor( $scope.countdown.countdown_time - Date.now() / 1000 + $scope.serverOffset );
        };
        $scope.$watch(function () {
            return Countdown.lastModified(id);
        }, function () {
            $scope.countdown = Countdown.get(id);
            if (interval) {
                $interval.cancel(interval);
            }
            if ($scope.countdown) {
                if ($scope.countdown.running) {
                    calculateCountdownTime($scope.countdown);
                    interval = $interval(function () { calculateCountdownTime($scope.countdown); }, 1000);
                } else {
                    $scope.countdown.seconds = $scope.countdown.countdown_time;
                }
            }
        });
        $scope.$on('$destroy', function() {
            // Cancel the interval if the controller is destroyed
            if (interval) {
                $interval.cancel(interval);
            }
        });
    }
])

.controller('SlideMessageCtrl', [
    '$scope',
    'ProjectorMessage',
    'Projector',
    'ProjectorID',
    'gettextCatalog',
    function($scope, ProjectorMessage, Projector, ProjectorID, gettextCatalog) {
        // Attention! Each object that is used here has to be dealt on server side.
        // Add it to the coresponding get_requirements method of the ProjectorElement
        // class.
        var id = $scope.element.id;

        if ($scope.element.identify) {
            var projector = Projector.get(ProjectorID());
            $scope.identifyMessage = gettextCatalog.getString('Projector') + ' ' + projector.id + ': ' + gettextCatalog.getString(projector.name);
        } else {
            $scope.message = ProjectorMessage.get(id);
            ProjectorMessage.bindOne(id, $scope, 'message');
        }
    }
]);

}());
<|endoftext|>


<commit_before>'use strict';

const _ = require('lodash');

/**
    * @class ORMNeoQuery
 */
class ORMNeoQuery {

    /**
        * Constructs a query object with an label.
        *
        * @constructor
        * @param {string=} label - The query to filter nodes that have to be returned.
    */
    constructor(label) {
        this._queryObject = {
            where: ''
        };
        this.label = label;
    }

    /**
        * Convenience method that creates a query object with an label.
        *
        * @static
        * @param {string=} label - The query to filter nodes that have to be returned.
        * @returns {ORMNeoQuery} Created query with label.
    */
    static query(label) {
        return new ORMNeoQuery(label);
    }

    set label(value) {
        if (value && _.isString(value) && !_.isEmpty(value)) {
            this._label = value;
        }
    }
    /**
     * @type {string}
    */
    get label() {
        return this._label;
    }

    /**
     * @type {object}
     */
    get queryObject() {
        return this._queryObject;
    }

    limit(value) {
        if (_.isInteger(value)) {
            this.queryObject.limit = value;
        }
        return this;
    }

    and(property, filter) {
        let obj = {};
        obj[property] = filter;
        this._appendWhere('AND', obj);
        return this;
    }

    or(property, filter) {
        let obj = {};
        obj[property] = filter;
        this._appendWhere('OR', obj);
        return this;
    }

    where() {
        return (this.queryObject.where === '') ? '' : `WHERE ${this.queryObject.where}`;
    }

    filters() {
        return this.queryObject.where;
    }

    count() {
        let queryLabel = (this.label) ? `:${this.label}` : '';
        let cypher = `MATCH (n${queryLabel}) ${this.where()} RETURN COUNT(n) as count`;
        return cypher;
    }

    match() {
        let queryLabel = (this.label) ? `:${this.label}` : '';
        let limitQuery = (this.queryObject.limit) ? ` LIMIT ${this.queryObject.limit}` : '';
        return `MATCH (n${queryLabel}) WHERE ${this.queryObject.where} RETURN n${limitQuery}`;
    }

    //Convenience methods
    _appendWhere(operator, filter) {
        if (this.queryObject.where === '') {
            this.queryObject.where += this._conditionToQuery(filter);
        } else {
            this.queryObject.where += ` ${operator} ` + this._conditionToQuery(filter);
        }

    }

    _conditionToQuery(filter) {
        if (!_.isEmpty(filter)) {
            let conditionsMap = {
                $eq: '=',
                $lt: '<',
                $lte: '<=',
                $gt: '>',
                $gte: '>=',
                $ne: '!='
            };
            let property = _.first(_.keysIn(filter));
            let conditionKeys = _.keysIn(filter[property]);
            let conditions = filter[property];
            return conditionKeys.reduce((result, key) => {
                let operator = conditionsMap[key];
                if (operator) {
                    return ((result !== '') ? result + ' AND ' : '') +
                        `n.${property} ${operator} ${this._valueOnQuery(conditions[key])}`;
                }
                return result;
            }, '');
        }
        return '';
    }
    _valueOnQuery(value) {
        if (_.isString(value)) {
            return `'${value}'`;
        } else {
            return `${value}`;
        }
    }
}

module.exports = ORMNeoQuery;

<commit_msg>Query docs done<commit_after>'use strict';

const _ = require('lodash');

/**
    * @class ORMNeoQuery
 */
class ORMNeoQuery {

    /**
        * Constructs a query object with an label.
        *
        * @constructor
        * @param {string=} label - The query to filter nodes that have to be returned.
    */
    constructor(label) {
        this._queryObject = {
            where: ''
        };
        this.label = label;
    }

    /**
        * Convenience method that creates a query object with an label.
        *
        * @static
        * @param {string=} label - The query to filter nodes that have to be returned.
        * @returns {ORMNeoQuery} Created query with label.
    */
    static query(label) {
        return new ORMNeoQuery(label);
    }

    set label(value) {
        if (value && _.isString(value) && !_.isEmpty(value)) {
            this._label = value;
        }
    }
    /**
     * @type {string}
    */
    get label() {
        return this._label;
    }

    /**
     * @type {object}
     */
    get queryObject() {
        return this._queryObject;
    }

    /**
        * Add limit constraint to this query object.
        *
        * @param {integer} value - The max number of values that should be returned.
        * @returns {ORMNeoQuery} This instance of query.
    */
    limit(value) {
        if (_.isInteger(value)) {
            this.queryObject.limit = value;
        }
        return this;
    }

    /**
        * Add AND filter constraint to this query object.
        *
        * @param {string} property - Name of the property that the filter will be applied.
        * @param {object} filter - Filter that will be applied. Example: {$eq: 'v'}.
        Possible filters are: $eq(equals), $lt(lessThan),$lte(lessThanOrEqual), $gt(greaterThan), $gte(greaterThanOrEqual), $ne(not equals)
        * @returns {ORMNeoQuery} This instance of query.
    */
    and(property, filter) {
        let obj = {};
        obj[property] = filter;
        this._appendWhere('AND', obj);
        return this;
    }

    /**
        * Add OR filter constraint to this query object.
        *
        * @param {string} property - Name of the property that the filter will be applied.
        * @param {object} filter - Filter that will be applied. Example: {$eq: 'v'}.
        Possible filters are: $eq(equals), $lt(lessThan),$lte(lessThanOrEqual), $gt(greaterThan), $gte(greaterThanOrEqual), $ne(not equals)
        * @returns {ORMNeoQuery} This instance of query.
    */
    or(property, filter) {
        let obj = {};
        obj[property] = filter;
        this._appendWhere('OR', obj);
        return this;
    }

    /**
        * Return cypher WHERE query builded string clause from this query.
        *
        * @returns {string} Cypher WHERE clause builded.
    */
    where() {
        return (this.queryObject.where === '') ? '' : `WHERE ${this.queryObject.where}`;
    }

    /**
        * Return cypher query filter string clause from this query.
        *
        * @returns {string} Cypher filter clause builded.
    */
    filters() {
        return this.queryObject.where;
    }

    /**
        * Return cypher query count string matches from this query.
        *
        * @returns {string} Cypher count match builded.
    */
    count() {
        let queryLabel = (this.label) ? `:${this.label}` : '';
        let cypher = `MATCH (n${queryLabel}) ${this.where()} RETURN COUNT(n) as count`;
        return cypher;
    }

    /**
        * Return cypher nodes match string from this query.
        *
        * @returns {string} Cypher nodes match builded.
    */
    match() {
        let queryLabel = (this.label) ? `:${this.label}` : '';
        let limitQuery = (this.queryObject.limit) ? ` LIMIT ${this.queryObject.limit}` : '';
        return `MATCH (n${queryLabel}) WHERE ${this.queryObject.where} RETURN n${limitQuery}`;
    }

    //Convenience methods
    _appendWhere(operator, filter) {
        if (this.queryObject.where === '') {
            this.queryObject.where += this._conditionToQuery(filter);
        } else {
            this.queryObject.where += ` ${operator} ` + this._conditionToQuery(filter);
        }

    }

    _conditionToQuery(filter) {
        if (!_.isEmpty(filter)) {
            let conditionsMap = {
                $eq: '=',
                $lt: '<',
                $lte: '<=',
                $gt: '>',
                $gte: '>=',
                $ne: '!='
            };
            let property = _.first(_.keysIn(filter));
            let conditionKeys = _.keysIn(filter[property]);
            let conditions = filter[property];
            return conditionKeys.reduce((result, key) => {
                let operator = conditionsMap[key];
                if (operator) {
                    return ((result !== '') ? result + ' AND ' : '') +
                        `n.${property} ${operator} ${this._valueOnQuery(conditions[key])}`;
                }
                return result;
            }, '');
        }
        return '';
    }
    _valueOnQuery(value) {
        if (_.isString(value)) {
            return `'${value}'`;
        } else {
            return `${value}`;
        }
    }
}

module.exports = ORMNeoQuery;

<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Link } from 'react-router'
import InputGroup from '../components/InputGroup'
import Image from '../components/Image'

import SecondaryNavBar from '../components/SecondaryNavBar'
import EditProfileHeader from './components/EditProfileHeader'
import ProfileEditingSidebar from './components/ProfileEditingSidebar'
import { IdentityActions } from './store/identity'
import { signProfileForUpload, findAddressIndex } from '../utils/index'
import { uploadProfile, uploadPhoto } from '../account/utils'

import EditSocialAccountItem from './components/EditSocialAccountItem'
import EditPGPAccountItem from './components/EditPGPAccountItem'

import BasicInfoTab      from './tabs/BasicInfoTab'
import PhotosTab         from './tabs/PhotosTab'
import SocialAccountsTab from './tabs/SocialAccountsTab'
import PublicKeysTab     from './tabs/PublicKeysTab'
import PrivateInfoTab    from './tabs/PrivateInfoTab'

import log4js from 'log4js'

const logger = log4js.getLogger('profiles/EditProfilePage.js')

const accountTypes = [
  'twitter',
  'facebook',
  'linkedin',
  'github',
  'instagram',
  'hackernews',
  'bitcoin',
  'ethereum',
  'pgp',
  'ssh'
]

function mapStateToProps(state) {
  return {
    localIdentities: state.profiles.identity.localIdentities,
    api: state.settings.api,
    identityKeypairs: state.account.identityAccount.keypairs,
    identityAddresses: state.account.identityAccount.addresses

  }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(IdentityActions, dispatch)
}

class EditProfilePage extends Component {
  static propTypes = {
    updateProfile: PropTypes.func.isRequired,
    localIdentities: PropTypes.object.isRequired,
    api: PropTypes.object.isRequired,
    identityAddresses: PropTypes.array.isRequired,
    identityKeypairs: PropTypes.array.isRequired,
    routeParams: PropTypes.object.isRequired
  }

  constructor(props) {
    super(props)

    this.state = {
      domainName: null,
      profile: null,
      profileJustSaved: false,
      tabName: ""
    }

    this.saveProfile = this.saveProfile.bind(this)
    this.uploadProfilePhoto = this.uploadProfilePhoto.bind(this)
    this.hasUsername = this.hasUsername.bind(this)
    this.onChange = this.onChange.bind(this)
    this.onSocialAccountChange = this.onSocialAccountChange.bind(this)
    this.onChangePhotoClick = this.onChangePhotoClick.bind(this)
  }

  componentWillMount() {
    this.componentHasNewLocalIdentities(this.props)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.localIdentities !== this.props.localIdentities) {
      this.componentHasNewLocalIdentities(nextProps)
    }
  }

  componentWillUnmount() {
    this.saveProfile(this.state.profile)
  }

  componentHasNewLocalIdentities(props) {
    const profileIndex = this.props.routeParams.index
    if (props.localIdentities[profileIndex]) {
      const newDomainName = props.localIdentities[profileIndex].domainName
      const newProfile = props.localIdentities[profileIndex].profile
      newProfile.verifications = props.localIdentities[profileIndex].verifications
      if (profileIndex) {
        this.setState({
          domainName: newDomainName,
          profile: newProfile
        })
      }
    } else {
      // Do nothing
    }
  }

  saveProfile(newProfile) {
    logger.trace('saveProfile')
    this.props.updateProfile(this.props.routeParams.index, newProfile)
    if (this.hasUsername() && this.props.api.storageConnected) {
      logger.trace('saveProfile: Preparing to upload profile')
      const profileIndex = this.props.routeParams.index
      const ownerAddress = this.props.localIdentities[profileIndex].ownerAddress
      const addressIndex = findAddressIndex(ownerAddress, this.props.identityAddresses)
      logger.debug(`saveProfile: signing with key index ${addressIndex}`)

      const data = signProfileForUpload(this.state.profile,
        this.props.identityKeypairs[addressIndex])

      uploadProfile(this.props.api, this.state.domainName, data).catch((err) => {
        console.error(err)
        console.error('profile not uploaded')
      })
    } else {
      logger.trace('saveProfile: No username or storage so we skipped profile upload')
    }
  }

  uploadProfilePhoto(e) {
    const name = this.state.domainName
    let profile = this.state.profile
    uploadPhoto(this.props.api, name, e.target.files[0], 0)
    .then((avatarUrl) => {
      profile.image[0].contentUrl = avatarUrl
      this.setState({
        profile: profile
      })
    })
    .catch((error) => {
      console.error(error)
    })

  }

  hasUsername() {
    const localIdentities = this.props.localIdentities
    const currentDomainName = this.state.domainName
    return currentDomainName !== localIdentities[currentDomainName].ownerAddress
  }

  onChange(event) {
    let profile = this.state.profile
    profile[event.target.name] = event.target.value
    this.setState({profile: profile})
  }

  onChangePhotoClick() {
    this.photoUpload.click()
  }

  onSocialAccountChange(service, event) {
    let profile = this.state.profile
    if (profile.hasOwnProperty('account')) {
      profile.account.forEach(account => {
        if(account.service === service) {
          account.identifier = event.target.value
          this.setState({profile: profile})
        }
      })
    }
    else {
      profile.account = []
      profile.account.push({
        '@type': 'Account',
        'service': service,
        'identifier': '',
        'proofType': 'http',
        'proofUrl': ''
      })
      this.setState({profile: profile})
      this.saveProfile(profile)
    }
  }

  createPlaceholderAccount(accountType) {
    return {
      "@type": "Account",
      placeholder: true,
      service: accountType,
      identifier: "",
      proofType: "",
      proofURL: "",
    }
  }

  render() {

    const profileIndex = this.props.routeParams.index
    const identity = this.props.localIdentities[profileIndex]
    const verifications = identity.verifications

    // render() sometimes gets called before defaultIdentityName
    // is updated from ownerAddress to the actual name when adding
    // a username.
    if (!identity) {
      return null
    }

    var filledAccounts = []
    var placeholders = []

    if (this.state.profile.hasOwnProperty('account')) {
      accountTypes.forEach((accountType) => {

        var hasAccount = false
        this.state.profile.account.forEach((account) => {
          if (account.service === accountType) {
            hasAccount = true
            account.placeholder = false
            filledAccounts.push(account)
          }
        })

        if(!hasAccount) {
          placeholders.push(this.createPlaceholderAccount(accountType))
        }

      })
    }
    else {
      accountTypes.forEach((accountType) => {
        placeholders.push(this.createPlaceholderAccount(accountType))
      })
    }

    const accounts = filledAccounts.concat(placeholders)

    console.log(accounts)
    console.log(this.state.profile)
    const domainName = this.state.domainName
    return (

      {this.state.tabName === '' ? (
        <SecondaryNavBar
          leftButtonTitle="Edit"
          leftButtonLink={`/profiles/${domainName}/edit`}
          isLeftActive
          centerButtonTitle="View"
          centerButtonLink="/profiles"
          rightButtonTitle="More"
          rightButtonLink="/profiles/i/all"
        />
        ) : (
        <SecondaryNavBar
          leftButtonTitle="Edit"
          onLeftButtonClick={() => this.backClick()}
          isLeftActive
          centerButtonTitle="View"
          centerButtonLink="/profiles"
          rightButtonTitle="More"
          rightButtonLink="/profiles/i/all"
        />
        )}

          {this.state.profile && this.state.domainName ?

                    <Image
                      src={(this.state.profile.image && this.state.profile.image[0].contentUrl)
                        ? this.state.profile.image[0].contentUrl : "/images/avatar.png"}
                      fallbackSrc="/images/avatar.png" className="rounded-circle" />

                    <input type="file" ref={ ref => this.photoUpload = ref} onChange={this.uploadProfilePhoto} style={{display:'none'}} />
                    <button className="btn btn-link active m-b-30" onClick={this.onChangePhotoClick}>
                      Change Photo
                    </button>

                  <InputGroup name="givenName" label="First Name"
                      data={this.state.profile}
                      onChange={this.onChange} />
                  <InputGroup name="familyName" label="Last Name"
                      data={this.state.profile}
                      onChange={this.onChange} />
                  <InputGroup name="description" label="Short Bio"
                      data={this.state.profile}
                      onChange={this.onChange} />

                    {accounts &&
                      accounts.map((account) => {
                        let verified = false
                        if(verifications) {
                          for (let i = 0; i < verifications.length; i++) {
                            const verification = verifications[i]
                            if (verification.service === account.service &&
                              verification.valid === true) {
                              verified = true
                              break
                            }
                          }
                        }
                        if (account.service === 'pgp' || account.service === 'ssh') {
                          return (
                            <EditPGPAccountItem
                              key={`${account.service}`}
                              service={account.service}
                              identifier={account.identifier}
                              contentUrl={account.contentUrl}
                              placeholder={account.placeholder}
                              listItem
                            />
                          )
                        } else {
                          return (
                            <EditSocialAccountItem
                              key={`${account.service}`}
                              service={account.service}
                              identifier={account.identifier}
                              proofUrl={account.proofUrl}
                              listItem
                              verified={verified}
                              placeholder={account.placeholder}
                              onChange={this.onSocialAccountChange}
                            />
                          )
                        }
                      })
                    }

          :

              Page Not Found

You don't own this profile and therefore you cannot edit it.

          }

    )
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(EditProfilePage)
<commit_msg>Create new social accounts in user profile as user types. #805<commit_after>import React, { Component, PropTypes } from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { Link } from 'react-router'
import InputGroup from '../components/InputGroup'
import Image from '../components/Image'

import SecondaryNavBar from '../components/SecondaryNavBar'
import EditProfileHeader from './components/EditProfileHeader'
import ProfileEditingSidebar from './components/ProfileEditingSidebar'
import { IdentityActions } from './store/identity'
import { signProfileForUpload, findAddressIndex } from '../utils/index'
import { uploadProfile, uploadPhoto } from '../account/utils'

import EditSocialAccountItem from './components/EditSocialAccountItem'
import EditPGPAccountItem from './components/EditPGPAccountItem'

import BasicInfoTab      from './tabs/BasicInfoTab'
import PhotosTab         from './tabs/PhotosTab'
import SocialAccountsTab from './tabs/SocialAccountsTab'
import PublicKeysTab     from './tabs/PublicKeysTab'
import PrivateInfoTab    from './tabs/PrivateInfoTab'

import log4js from 'log4js'

const logger = log4js.getLogger('profiles/EditProfilePage.js')

const accountTypes = [
  'twitter',
  'facebook',
  'linkedin',
  'github',
  'instagram',
  'hackernews',
  'bitcoin',
  'ethereum',
  'pgp',
  'ssh'
]

function mapStateToProps(state) {
  return {
    localIdentities: state.profiles.identity.localIdentities,
    api: state.settings.api,
    identityKeypairs: state.account.identityAccount.keypairs,
    identityAddresses: state.account.identityAccount.addresses

  }
}

function mapDispatchToProps(dispatch) {
  return bindActionCreators(IdentityActions, dispatch)
}

class EditProfilePage extends Component {
  static propTypes = {
    updateProfile: PropTypes.func.isRequired,
    localIdentities: PropTypes.object.isRequired,
    api: PropTypes.object.isRequired,
    identityAddresses: PropTypes.array.isRequired,
    identityKeypairs: PropTypes.array.isRequired,
    routeParams: PropTypes.object.isRequired
  }

  constructor(props) {
    super(props)

    this.state = {
      domainName: null,
      profile: null,
      profileJustSaved: false,
      tabName: ""
    }

    this.saveProfile = this.saveProfile.bind(this)
    this.uploadProfilePhoto = this.uploadProfilePhoto.bind(this)
    this.hasUsername = this.hasUsername.bind(this)
    this.onChange = this.onChange.bind(this)
    this.onSocialAccountChange = this.onSocialAccountChange.bind(this)
    this.onChangePhotoClick = this.onChangePhotoClick.bind(this)
    this.createNewAccount= this.createNewAccount.bind(this)
    this.removeAccount = this.removeAccount.bind(this)
  }

  componentWillMount() {
    this.componentHasNewLocalIdentities(this.props)
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.localIdentities !== this.props.localIdentities) {
      this.componentHasNewLocalIdentities(nextProps)
    }
  }

  componentWillUnmount() {
    this.saveProfile(this.state.profile)
  }

  componentHasNewLocalIdentities(props) {
    const profileIndex = this.props.routeParams.index
    if (props.localIdentities[profileIndex]) {
      const newDomainName = props.localIdentities[profileIndex].domainName
      const newProfile = props.localIdentities[profileIndex].profile
      newProfile.verifications = props.localIdentities[profileIndex].verifications
      if (profileIndex) {
        this.setState({
          domainName: newDomainName,
          profile: newProfile
        })
      }
    } else {
      // Do nothing
    }
  }

  saveProfile(newProfile) {
    logger.trace('saveProfile')
    this.props.updateProfile(this.props.routeParams.index, newProfile)
    if (this.hasUsername() && this.props.api.storageConnected) {
      logger.trace('saveProfile: Preparing to upload profile')
      const profileIndex = this.props.routeParams.index
      const ownerAddress = this.props.localIdentities[profileIndex].ownerAddress
      const addressIndex = findAddressIndex(ownerAddress, this.props.identityAddresses)
      logger.debug(`saveProfile: signing with key index ${addressIndex}`)

      const data = signProfileForUpload(this.state.profile,
        this.props.identityKeypairs[addressIndex])

      uploadProfile(this.props.api, this.state.domainName, data).catch((err) => {
        console.error(err)
        console.error('profile not uploaded')
      })
    } else {
      logger.trace('saveProfile: No username or storage so we skipped profile upload')
    }
  }

  uploadProfilePhoto(e) {
    const name = this.state.domainName
    let profile = this.state.profile
    uploadPhoto(this.props.api, name, e.target.files[0], 0)
    .then((avatarUrl) => {
      profile.image[0].contentUrl = avatarUrl
      this.setState({
        profile: profile
      })
    })
    .catch((error) => {
      console.error(error)
    })

  }

  hasUsername() {
    const localIdentities = this.props.localIdentities
    const currentDomainName = this.state.domainName
    return currentDomainName !== localIdentities[currentDomainName].ownerAddress
  }

  onChange(event) {
    let profile = this.state.profile
    profile[event.target.name] = event.target.value
    this.setState({profile: profile})
  }

  onChangePhotoClick() {
    this.photoUpload.click()
  }

  onSocialAccountChange(service, event) {
    let profile = this.state.profile
    let identifier = event.target.value

    if (profile.hasOwnProperty('account')) {
      let hasAccount = false
      profile.account.forEach(account => {
        if(account.service === service) {
          hasAccount = true
          if (identifier.length > 0) {
            account.identifier = identifier
            this.setState({profile: profile})
          }
          else {
            this.removeAccount(service, identifier)
          }
        }
      })

      if (!hasAccount && identifier.length > 0) {
        profile.account.push(this.createNewAccount(service, identifier))
        this.setState({profile: profile})
        this.saveProfile(profile)
      }
    }
    else {
      profile.account = []
      profile.account.push(this.createNewAccount(service, identifier))
      this.setState({profile: profile})
      if(identifier.length > 0) {
        this.saveProfile(profile)
      }
    }
  }

  removeAccount(service, identifier) {
    let profile = this.state.profile
    let accounts = profile.account
    let newAccounts = accounts.filter(account => {
      return (account.service !== service && account.identifier !== identifier)
    })
    profile.account = newAccounts
    this.setState({profile: profile})
    this.saveProfile(profile)
  }

  createNewAccount(service, identifier) {
    return {
      '@type': 'Account',
      placeholder: false,
      service: service,
      identifier: identifier,
      proofType: 'http',
      proofUrl: ''
    }
  }

  createPlaceholderAccount(accountType) {
    return {
      "@type": "Account",
      placeholder: true,
      service: accountType,
      identifier: "",
      proofType: "",
      proofURL: "",
    }
  }

  render() {

    const profileIndex = this.props.routeParams.index
    const identity = this.props.localIdentities[profileIndex]
    const verifications = identity.verifications

    // render() sometimes gets called before defaultIdentityName
    // is updated from ownerAddress to the actual name when adding
    // a username.
    if (!identity) {
      return null
    }

    var filledAccounts = []
    var placeholders = []

    if (this.state.profile.hasOwnProperty('account')) {
      accountTypes.forEach((accountType) => {

        var hasAccount = false
        this.state.profile.account.forEach((account) => {
          if (account.service === accountType) {
            hasAccount = true
            account.placeholder = false
            filledAccounts.push(account)
          }
        })

        if(!hasAccount) {
          placeholders.push(this.createPlaceholderAccount(accountType))
        }

      })
    }
    else {
      accountTypes.forEach((accountType) => {
        placeholders.push(this.createPlaceholderAccount(accountType))
      })
    }

    const accounts = filledAccounts.concat(placeholders)

    console.log(accounts)
    console.log(this.state.profile)
    const domainName = this.state.domainName
    return (

      {this.state.tabName === '' ? (
        <SecondaryNavBar
          leftButtonTitle="Edit"
          leftButtonLink={`/profiles/${domainName}/edit`}
          isLeftActive
          centerButtonTitle="View"
          centerButtonLink="/profiles"
          rightButtonTitle="More"
          rightButtonLink="/profiles/i/all"
        />
        ) : (
        <SecondaryNavBar
          leftButtonTitle="Edit"
          onLeftButtonClick={() => this.backClick()}
          isLeftActive
          centerButtonTitle="View"
          centerButtonLink="/profiles"
          rightButtonTitle="More"
          rightButtonLink="/profiles/i/all"
        />
        )}

          {this.state.profile && this.state.domainName ?

                    <Image
                      src={(this.state.profile.image && this.state.profile.image[0].contentUrl)
                        ? this.state.profile.image[0].contentUrl : "/images/avatar.png"}
                      fallbackSrc="/images/avatar.png" className="rounded-circle" />

                    <input type="file" ref={ ref => this.photoUpload = ref} onChange={this.uploadProfilePhoto} style={{display:'none'}} />
                    <button className="btn btn-link active m-b-30" onClick={this.onChangePhotoClick}>
                      Change Photo
                    </button>

                  <InputGroup name="givenName" label="First Name"
                      data={this.state.profile}
                      onChange={this.onChange} />
                  <InputGroup name="familyName" label="Last Name"
                      data={this.state.profile}
                      onChange={this.onChange} />
                  <InputGroup name="description" label="Short Bio"
                      data={this.state.profile}
                      onChange={this.onChange} />

                    {accounts &&
                      accounts.map((account) => {
                        let verified = false
                        if(verifications) {
                          for (let i = 0; i < verifications.length; i++) {
                            const verification = verifications[i]
                            if (verification.service === account.service &&
                              verification.valid === true) {
                              verified = true
                              break
                            }
                          }
                        }
                        if (account.service === 'pgp' || account.service === 'ssh') {
                          return (
                            <EditPGPAccountItem
                              key={`${account.service}`}
                              service={account.service}
                              identifier={account.identifier}
                              contentUrl={account.contentUrl}
                              placeholder={account.placeholder}
                              listItem
                            />
                          )
                        } else {
                          return (
                            <EditSocialAccountItem
                              key={`${account.service}`}
                              service={account.service}
                              identifier={account.identifier}
                              proofUrl={account.proofUrl}
                              listItem
                              verified={verified}
                              placeholder={account.placeholder}
                              onChange={this.onSocialAccountChange}
                            />
                          )
                        }
                      })
                    }

          :

              Page Not Found

You don't own this profile and therefore you cannot edit it.

          }

    )
  }
}

export default connect(mapStateToProps, mapDispatchToProps)(EditProfilePage)
<|endoftext|>


<commit_before>/* from http://stackoverflow.com/a/21682946 */
function elementToHash(element) {
    const text = element.textContent;
    let hash = 0;
    for (let i = 0; i < text.length; i++) {
        hash = text.charCodeAt(i) + ((hash << 5) - hash);
    }
    return hash & hash; // convert to 32bit int
}

/* from http://stackoverflow.com/a/19303725 */
function rand(hash, max, i) {
    const x = Math.sin(hash + i) * 10000;
    return Math.floor((x - Math.floor(x)) * max);
}

function colorizeElement(element) {
    const hash = elementToHash(element);
    const red = rand(hash, 255, 0);
    const green = rand(hash, 255, 1);
    const blue = rand(hash, 255, 2);
    element.style.color = `rgb(${red}, ${green}, ${blue})`;
}

function colorizeElementDark(element, hours) {
    if (hours >= 14) {
        const hash = elementToHash(element);
        const hue = rand(hash, 360, 3);
        const saturation = 100;
        const luminance = rand(hash, 60, 4);
        element.style.color = `hsl(${hue}, ${saturation}%, ${luminance}%)`;
    }
}

function replaceHTML(element, hours) {
    if (hours >= 16) {
        let html = element.innerHTML;
        html = html.replace(/(?![^<]*>) und /g, ' und ein Einhorn und ');
        html = html.replace(/Schülerin/g, 'Gnomin');
        html = html.replace(/Schüler/g, 'Gnome');
        html = html.replace(/schülerin/g, 'gnomin');
        html = html.replace(/schüler/g, 'gnome');
        html = html.replace(/Lehrer/g, 'Li-La-Lehrer');
        html = html.replace(/Gryffindor/g, 'Löwchen');
        html = html.replace(/Hufflepuff/g, 'Dächschen');
        html = html.replace(/Slytherin/g, 'Schlängchen');
        html = html.replace(/Ravenclaw/g, 'Räbchen');
        html = html.replace(/Quidditch/g, 'Besendings');
        if (hours >= 18) {
            html = html.replace(/Mitarbeiter/g, 'Superhelden');
            html = html.replace(/Schnatz/g, 'Schmatz');
            html = html.replace(/Potter/g, 'Podder');
            html = html.replace(/Newt/g, 'Niut');
            html = html.replace(/alles/g, 'everything');
            html = html.replace(/Alles/g, 'Everything');
        }
        if (hours >= 20) {
            html = html.replace(/(?![^<]*>)t/g, 'd');
            html = html.replace(/T/g, 'D');
            html = html.replace(/(?![^<]*>)ph/g, 'pf');
            html = html.replace(/Ph/g, 'Pf');
            html = html.replace(/ß/g, ':ß:');
            html = html.replace(/(?![^<]*>)ss/g, 'ß');
            html = html.replace(/:ß:/g, 'ss');
            html = html.replace(/(?![^<]*>)(der|die|das)/g, 'the');
            html = html.replace(/(Der|Die|Das)/g, 'The');
        }
        element.innerHTML = html;
    }
}

function specializeElement(element, hours) {
    const hash = elementToHash(element);
    const factor = (hours - 12) / 2;
    const fontNumber = rand(hash, 400, 5);
    if (fontNumber < factor) {
        element.style.fontFamily = "'Bonbon', cursive";
    } else if (fontNumber < 6 + factor) {
        element.style.fontFamily = "'Jim Nightshade', cursive";
    } else if (fontNumber < 12 + factor) {
        element.style.fontFamily = "'Space Mono', monospace";
    } else if (fontNumber < 18 + factor) {
        element.style.fontFamily = "'Nova Oval', cursive";
    } else if (fontNumber < 24 + factor) {
        element.style.fontFamily = "'Indie Flower', cursive";
    } else if (fontNumber < 30 + factor) {
        element.style.fontFamily = "'VT323', monospace";
    } else if (fontNumber < 36 + factor) {
        element.style.fontFamily = "'Covered By Your Grace', cursive";
    } else if (fontNumber < 42 + factor) {
        element.style.fontFamily = "'Audiowide', cursive";
    } else if (fontNumber < 48 + factor) {
        element.style.fontFamily = "'Vidaloka', serif";
    } else if (fontNumber < 56 + factor) {
        element.style.fontFamily = "'Rock Salt', cursive";
    }
    if (rand(hash, 100, 6) < factor) {
        element.style.transform = 'rotate(180deg)';
    }
    if (rand(hash, 100, 7) < factor) {
        element.style.transform = 'scaleX(-1)';
    }
}
function animateImage(element) {
    if(hours >= 22){
        const avatar = element.src.match(/avatar-(\d+)\.(jpg|gif|png)/)[1];
        const quer = avatar < 10 ? avatar : avatar % 9;
        let animate = true;
        let pos = 0;
        let x = 0;
        let y = 0;
        let z = 0;

        switch(quer){
            case 0:
            case 3:
                x = 1;
            case 1:
            case 6:
                y = 1;
                break;
            case 4:
            case 9:
                z = 1;
                break;
            case 7:
                x = 1;
                y = 1;
                break;
            case 2:
                x = 1;
                z = 1;
                break;
            case 5:
                y = 1;
                z = 1;
                break;
            case 8:
                x = 1;
                y = 1;
                z = 1;
                break;
            default:
                animate = false;
        }
        let id = animate ? setInterval(function () {
            if (pos == 359) {
                pos = 0;
            } else {
                pos++;
                element.style.transform = 'rotate3d(' + x + ',' + y + ',' + z + ',' + pos + 'deg)';
            }
        }, rand(quer,100,0)): '';
    }
}
if(window.location.pathname != '/hpfc/board/editpost.php'){
	document.querySelectorAll('a[href^="profile.php"], a[href^="profile.php"] font').forEach(element => {
	    colorizeElement(element)
	});

	let date = new Date();
	let hours = date.getHours();

	if (hours >= 12) {
	    document.querySelectorAll('td[class="normalfont"][align="left"]').forEach(post => {
	        colorizeElementDark(post, hours);
	    });

	    document.querySelectorAll('.tablecat_fc td[align="left"] span.normalfont b, .smallfont, .tablea, .tableb').forEach(element => {
	        specializeElement(element, hours);
	        replaceHTML(element, hours);
	    });

	    document.querySelectorAll('img[src^="images/avatars/avatar-"]').forEach(avatar => {
	        animateImage(avatar, hours);
	    });
	}
}<commit_msg>Move some replacements<commit_after>/* from http://stackoverflow.com/a/21682946 */
function elementToHash(element) {
    const text = element.textContent;
    let hash = 0;
    for (let i = 0; i < text.length; i++) {
        hash = text.charCodeAt(i) + ((hash << 5) - hash);
    }
    return hash & hash; // convert to 32bit int
}

/* from http://stackoverflow.com/a/19303725 */
function rand(hash, max, i) {
    const x = Math.sin(hash + i) * 10000;
    return Math.floor((x - Math.floor(x)) * max);
}

function colorizeElement(element) {
    const hash = elementToHash(element);
    const red = rand(hash, 255, 0);
    const green = rand(hash, 255, 1);
    const blue = rand(hash, 255, 2);
    element.style.color = `rgb(${red}, ${green}, ${blue})`;
}

function colorizeElementDark(element, hours) {
    if (hours >= 14) {
        const hash = elementToHash(element);
        const hue = rand(hash, 360, 3);
        const saturation = 100;
        const luminance = rand(hash, 60, 4);
        element.style.color = `hsl(${hue}, ${saturation}%, ${luminance}%)`;
    }
}

function replaceHTML(element, hours) {
    if (hours >= 16) {
        let html = element.innerHTML;
        html = html.replace(/(?![^<]*>) und /g, ' und ein Einhorn und ');
        html = html.replace(/Schülerin/g, 'Gnomin');
        html = html.replace(/Schüler/g, 'Gnome');
        html = html.replace(/schülerin/g, 'gnomin');
        html = html.replace(/schüler/g, 'gnome');
        html = html.replace(/Lehrer/g, 'Li-La-Lehrer');
        html = html.replace(/Gryffindor/g, 'Löwchen');
        html = html.replace(/Hufflepuff/g, 'Dächschen');
        html = html.replace(/Slytherin/g, 'Schlängchen');
        html = html.replace(/Ravenclaw/g, 'Räbchen');
        if (hours >= 18) {
            html = html.replace(/Quidditch/g, 'Besendings');
            html = html.replace(/Mitarbeiter/g, 'Superhelden');
            html = html.replace(/Schnatz/g, 'Schmatz');
            html = html.replace(/Potter/g, 'Podder');
            html = html.replace(/Newt/g, 'Niut');
            html = html.replace(/alles/g, 'everything');
            html = html.replace(/Alles/g, 'Everything');
            html = html.replace(/(?![^<]*>)ph/g, 'pf');
            html = html.replace(/Ph/g, 'Pf');
            html = html.replace(/sunny/g, 'stirbsonnig1');
            html = html.replace(/Nina/g, 'diecheesy2');
        }
        if (hours >= 20) {
            html = html.replace(/(?![^<]*>)t/g, 'd');
            html = html.replace(/T/g, 'D');
            html = html.replace(/ß/g, ':ß:');
            html = html.replace(/(?![^<]*>)ss/g, 'ß');
            html = html.replace(/:ß:/g, 'ss');
            html = html.replace(/(?![^<]*>)(der|die|das)/g, 'the');
            html = html.replace(/(Der|Die|Das)/g, 'The');
        }
        element.innerHTML = html;
    }
}

function specializeElement(element, hours) {
    const hash = elementToHash(element);
    const factor = (hours - 12) / 2;
    const fontNumber = rand(hash, 400, 5);
    if (fontNumber < factor) {
        element.style.fontFamily = "'Bonbon', cursive";
    } else if (fontNumber < 6 + factor) {
        element.style.fontFamily = "'Jim Nightshade', cursive";
    } else if (fontNumber < 12 + factor) {
        element.style.fontFamily = "'Space Mono', monospace";
    } else if (fontNumber < 18 + factor) {
        element.style.fontFamily = "'Nova Oval', cursive";
    } else if (fontNumber < 24 + factor) {
        element.style.fontFamily = "'Indie Flower', cursive";
    } else if (fontNumber < 30 + factor) {
        element.style.fontFamily = "'VT323', monospace";
    } else if (fontNumber < 36 + factor) {
        element.style.fontFamily = "'Covered By Your Grace', cursive";
    } else if (fontNumber < 42 + factor) {
        element.style.fontFamily = "'Audiowide', cursive";
    } else if (fontNumber < 48 + factor) {
        element.style.fontFamily = "'Vidaloka', serif";
    } else if (fontNumber < 56 + factor) {
        element.style.fontFamily = "'Rock Salt', cursive";
    }
    if (rand(hash, 100, 6) < factor) {
        element.style.transform = 'rotate(180deg)';
    }
    if (rand(hash, 100, 7) < factor) {
        element.style.transform = 'scaleX(-1)';
    }
}
function animateImage(element) {
    if(hours >= 22){
        const avatar = element.src.match(/avatar-(\d+)\.(jpg|gif|png)/)[1];
        const quer = avatar < 10 ? avatar : avatar % 9;
        let animate = true;
        let pos = 0;
        let x = 0;
        let y = 0;
        let z = 0;

        switch(quer){
            case 0:
            case 3:
                x = 1;
            case 1:
            case 6:
                y = 1;
                break;
            case 4:
            case 9:
                z = 1;
                break;
            case 7:
                x = 1;
                y = 1;
                break;
            case 2:
                x = 1;
                z = 1;
                break;
            case 5:
                y = 1;
                z = 1;
                break;
            case 8:
                x = 1;
                y = 1;
                z = 1;
                break;
            default:
                animate = false;
        }
        let id = animate ? setInterval(function () {
            if (pos == 359) {
                pos = 0;
            } else {
                pos++;
                element.style.transform = 'rotate3d(' + x + ',' + y + ',' + z + ',' + pos + 'deg)';
            }
        }, rand(quer,100,0)): '';
    }
}
if(window.location.pathname != '/hpfc/board/editpost.php'){
	document.querySelectorAll('a[href^="profile.php"], a[href^="profile.php"] font').forEach(element => {
	    colorizeElement(element)
	});

	let date = new Date();
	let hours = date.getHours();

	if (hours >= 12) {
	    document.querySelectorAll('td[class="normalfont"][align="left"]').forEach(post => {
	        colorizeElementDark(post, hours);
	    });

	    document.querySelectorAll('.tablecat_fc td[align="left"] span.normalfont b, .smallfont, .tablea, .tableb').forEach(element => {
	        specializeElement(element, hours);
	        replaceHTML(element, hours);
	    });

	    document.querySelectorAll('img[src^="images/avatars/avatar-"]').forEach(avatar => {
	        animateImage(avatar, hours);
	    });
	}
}
<|endoftext|>


<commit_before>'use strict';
var turf = require('turf');
var _ = require('underscore');
var rbush = require('rbush');

module.exports = function(tileLayers, tile, writeData, done) {
  var layer = tileLayers.osm.osm;
  var highways = {};
  var bboxes = [];
  var majorRoads = {
    'motorway': true,
    'trunk': true,
    'primary': true,
    'secondary': true,
    'tertiary': true,
    'motorway_link': true,
    'trunk_link': true,
    'primary_link': true,
    'secondary_link': true,
    'tertiary_link': true
  };
  var minorRoads = {
    'unclassified': true,
    'residential': true,
    'living_street': true,
    // 'service': true,
    'road': true
  };
  var pathRoads = {
    'pedestrian': true,
    'track': true,
    'footway': true,
    'path': true,
    'cycleway': true,
    'steps': true
  };
  var preserveType = {};
  preserveType = _.extend(preserveType, majorRoads);
  preserveType = _.extend(preserveType, minorRoads);
  //preserveType = _.extend(preserveType, pathRoads);
  var osmlint = 'crossinghighways';

  for (var i = 0; i < layer.features.length; i++) {
    var val = layer.features[i];
    if (preserveType[val.properties.highway] && (val.geometry.type === 'LineString' || val.geometry.type === 'MultiLineString') && val.properties.layer === undefined) {
      var bboxHighway = turf.extent(val);
      bboxHighway.push(val.properties['@id']);
      bboxes.push(bboxHighway);
      highways[val.properties['@id']] = val;
    }
  }

  var highwaysTree = rbush(bboxes.length);
  highwaysTree.load(bboxes);
  var output = {};

  for (var j = 0; j < bboxes.length; j++) {
    var bbox = bboxes[j];
    var overlaps = highwaysTree.search(bbox);
    for (var k = 0; k < overlaps.length; k++) {
      var overlap = overlaps[k];
      if (bbox[4] !== overlap[4]) {
        var intersectPoint = turf.intersect(highways[overlap[4]], highways[bbox[4]]);
        if (intersectPoint !== undefined && (intersectPoint.geometry.type === 'Point' || intersectPoint.geometry.type === 'MultiPoint')) {
          var highwayCoord = _.flatten(highways[overlap[4]].geometry.coordinates);
          highwayCoord.concat(_.flatten(highways[bbox[4]].geometry.coordinates));
          var intersectPointCoord = _.flatten(intersectPoint.geometry.coordinates);
          if (_.difference(highwayCoord, intersectPointCoord).length === highwayCoord.length) {
            var fromHighway = highways[bbox[4]];
            var toHighway = highways[overlap[4]];
            fromHighway.properties._osmlint = osmlint;
            toHighway.properties._osmlint = osmlint;
            output[bbox[4]] = fromHighway;
            output[overlap[4]] = toHighway;
            var type;
            if (majorRoads[fromHighway.properties.highway] && majorRoads[toHighway.properties.highway]) {
              type = 'major-major';
            } else if ((majorRoads[fromHighway.properties.highway] && minorRoads[toHighway.properties.highway]) || (minorRoads[fromHighway.properties.highway] && majorRoads[toHighway.properties.highway])) {
              type = 'major-minor';
            } else if ((majorRoads[fromHighway.properties.highway] && pathRoads[toHighway.properties.highway]) || (pathRoads[fromHighway.properties.highway] && majorRoads[toHighway.properties.highway])) {
              type = 'major-path';
            } else if (minorRoads[fromHighway.properties.highway] && minorRoads[toHighway.properties.highway]) {
              type = 'minor-minor';
            } else if ((minorRoads[fromHighway.properties.highway] && pathRoads[toHighway.properties.highway]) || (pathRoads[fromHighway.properties.highway] && minorRoads[toHighway.properties.highway])) {
              type = 'minor-path';
            } else if (pathRoads[fromHighway.properties.highway] && pathRoads[toHighway.properties.highway]) {
              type = 'path-path';
            }
            intersectPoint.properties = {
              _fromWay: fromHighway.properties['@id'],
              _toWay: toHighway.properties['@id'],
              _osmlint: osmlint,
              _type: type
            };
            if (fromHighway.properties['@id'] > toHighway.properties['@id']) {
              output[bbox[4].toString().concat(overlap[4])] = intersectPoint;
            } else {
              output[overlap[4].toString().concat(bbox[4])] = intersectPoint;
            }
          }
        }
      }
    }
  }

  var result = _.values(output);

  if (result.length > 0) {
    var fc = turf.featurecollection(result);
    writeData(JSON.stringify(fc) + '\n');
  }

  done(null, null);

};
<commit_msg>fixing<commit_after>'use strict';
var turf = require('turf');
var _ = require('underscore');
var rbush = require('rbush');

module.exports = function(tileLayers, tile, writeData, done) {
  var layer = tileLayers.osm.osm;
  var listOfHighways = {};
  var highwaysBboxes = [];
  var majorRoads = {
    'motorway': true,
    'trunk': true,
    'primary': true,
    'secondary': true,
    'tertiary': true,
    'motorway_link': true,
    'trunk_link': true,
    'primary_link': true,
    'secondary_link': true,
    'tertiary_link': true
  };
  var minorRoads = {
    'unclassified': true,
    'residential': true,
    'living_street': true,
    // 'service': true,
    'road': true
  };
  var pathRoads = {
    'pedestrian': true,
    'track': true,
    'footway': true,
    'path': true,
    'cycleway': true,
    'steps': true
  };
  var preserveType = {};
  preserveType = _.extend(preserveType, majorRoads);
  preserveType = _.extend(preserveType, minorRoads);
  //preserveType = _.extend(preserveType, pathRoads);
  var osmlint = 'crossinghighways';

  for (var i = 0; i < layer.features.length; i++) {
    var val = layer.features[i];
    if (preserveType[val.properties.highway] && (val.geometry.type === 'LineString' || val.geometry.type === 'MultiLineString') && val.properties.layer === undefined) {
      var bboxHighway = turf.extent(val);
      bboxHighway.push(val.properties['@id']);
      highwaysBboxes.push(bboxHighway);
      listOfHighways[val.properties['@id']] = val;
    }
  }

  var highwaysTree = rbush(highwaysBboxes.length);
  highwaysTree.load(highwaysBboxes);
  var output = {};

  for (var j = 0; j < highwaysBboxes.length; j++) {
    var bbox = highwaysBboxes[j];
    var highwayToEvaluate = listOfHighways[bbox[4]];
    var overlaps = highwaysTree.search(bbox);
    for (var k = 0; k < overlaps.length; k++) {
      var overlapBbox = overlaps[k];
      var overlapHighway = listOfHighways[overlapBbox[4]];
      if (bbox[4] !== overlapBbox[4] && isIntersecting(highwayToEvaluate, overlapHighway) && !checkCoordinates(highwayToEvaluate, overlapHighway)) {
        var intersectPoint = turf.intersect(overlapHighway, highwayToEvaluate);
        if (intersectPoint && (intersectPoint.geometry.type === 'Point' || intersectPoint.geometry.type === 'MultiPoint')) {
          var highwayCoord = _.flatten(overlapHighway.geometry.coordinates);
          highwayCoord.concat(_.flatten(highwayToEvaluate.geometry.coordinates));
          var intersectPointCoord = _.flatten(intersectPoint.geometry.coordinates);
          if (_.difference(highwayCoord, intersectPointCoord).length === highwayCoord.length) {
            var fromHighway = highwayToEvaluate;
            var toHighway = overlapHighway;
            fromHighway.properties._osmlint = osmlint;
            toHighway.properties._osmlint = osmlint;
            output[bbox[4]] = fromHighway;
            output[overlapBbox[4]] = toHighway;
            intersectPoint.properties = {
              _fromWay: fromHighway.properties['@id'],
              _toWay: toHighway.properties['@id'],
              _osmlint: osmlint,
              _type: classification(majorRoads, minorRoads, pathRoads, highwayToEvaluate.properties.highway, overlapHighway.properties.highway)
            };
            if (fromHighway.properties['@id'] > toHighway.properties['@id']) {
              output[bbox[4].toString().concat(overlapBbox[4])] = intersectPoint;
            } else {
              output[overlapBbox[4].toString().concat(bbox[4])] = intersectPoint;
            }
          }
        }
      }
    }
  }

  var result = _.values(output);

  if (result.length > 0) {
    var fc = turf.featurecollection(result);
    writeData(JSON.stringify(fc) + '\n');
  }

  done(null, null);

};

function checkCoordinates(high1, high2) {
  var coord1 = high1.geometry.coordinates;
  var coord2 = high2.geometry.coordinates;
  if ((coord1[0][0] === coord2[0][0] && coord1[0][1] === coord2[0][1]) ||
    (coord1[0][0] === coord2[coord2.length - 1][0] && coord1[0][1] === coord2[coord2.length - 1][1]) ||
    (coord1[coord1.length - 1][0] === coord2[0][0] && coord1[coord1.length - 1][1] === coord2[0][1]) ||
    (coord1[coord1.length - 1][0] === coord2[coord2.length - 1][0] && coord1[coord1.length - 1][1] === coord2[coord2.length - 1][1])) {
    return true;
  }
  return false;
}

function isIntersecting(high1, high2) {
  var coord1 = high1.geometry.coordinates;
  var coord2 = high2.geometry.coordinates;
  var x1 = coord1[0][0];
  var y1 = coord1[0][1];
  var x2 = coord1[coord1.length - 1][0];
  var y2 = coord1[coord1.length - 1][1];
  var x3 = coord2[0][0];
  var y3 = coord2[0][1];
  var x4 = coord2[coord2.length - 1][0];
  var y4 = coord2[coord2.length - 1][1];
  var adx = x2 - x1;
  var ady = y2 - y1;
  var bdx = x4 - x3;
  var bdy = y4 - y3;
  var s = (-ady * (x1 - x3) + adx * (y1 - y3)) / (-bdx * ady + adx * bdy);
  var t = (+bdx * (y1 - y3) - bdy * (x1 - x3)) / (-bdx * ady + adx * bdy);
  return (s >= 0 && s <= 1 && t >= 0 && t <= 1);
}

function classification(major, minor, path, fromHighway, toHighway) {
  if (major[fromHighway] && major[toHighway]) {
    return 'major-major';
  } else if ((major[fromHighway] && minor[toHighway]) || (minor[fromHighway] && major[toHighway])) {
    return 'major-minor';
  } else if ((major[fromHighway] && path[toHighway]) || (path[fromHighway] && major[toHighway])) {
    return 'major-path';
  } else if (minor[fromHighway] && minor[toHighway]) {
    return 'minor-minor';
  } else if ((minor[fromHighway] && path[toHighway]) || (path[fromHighway] && minor[toHighway])) {
    return 'minor-path';
  } else if (path[fromHighway] && path[toHighway]) {
    return 'path-path';
  }
}
<|endoftext|>


<commit_before>// Sets a background image.
const _loadBackgroundImage = src => {
    const aboutBlankContainer = document.querySelector('.about-blank__background')
    aboutBlankContainer.style.backgroundImage = `url(${src})`
    aboutBlankContainer.classList.toggle('about-blank__background--loaded', !!src)
    return src
}

// Asynchronously downloads an image.
const _downloadImage = src => new Promise((resolve, reject) => {
    if (!src) return reject(new Error('No image specified'))
    const downloadingImage = new Image()
    downloadingImage.addEventListener('load', _ => resolve(src))
    downloadingImage.addEventListener('error', er => reject(er))
    downloadingImage.src = 'https://responsiveimages.io/v1/images/'+encodeURIComponent(src)
})

// Retrieves a random image from unsplash.
const _randomImage = _ => fetch('https://random.responsiveimages.io/v1/image').then(res => res.url)

// Bound to an Element this adjusts innerText to reflect the current time.
function displayTime() {
    const currentTime = new Date()
    this.innerText = currentTime.toLocaleTimeString('en-US')
}

// Toggles the visibility of the settings container.
const hideShowSettingsContainer = e => {
    e.preventDefault()
    const settingsContainer = document.querySelector('.settings__container')
    settingsContainer.setAttribute('aria-hidden', settingsContainer.getAttribute('aria-hidden') === "false" ? "true" : "false")
}

window.addEventListener('load', _ => {

    const clockElement = document.querySelector('.ab-time__clock')
    const incrementClock = displayTime.bind(clockElement)
    const clock = setInterval(incrementClock, 1000)
    incrementClock()

    const settingsOpenButton = document.querySelector('.about-blank__settings-button')
    const settingsCloseButton = document.querySelector('.settings__close-button')
    settingsOpenButton.addEventListener('click', hideShowSettingsContainer)
    settingsCloseButton.addEventListener('click', hideShowSettingsContainer)

    store = new AboutBlankStore()
    store.load()
        .then(_ => store.state.backgroundImage || _randomImage())
        .then(_downloadImage)
        .then(_loadBackgroundImage)
        .then(src => store.setState({ backgroundImage: src }))
        .catch(console.error)
        .then(_randomImage)
        .then(_downloadImage)
        .then(src => store.setState({ backgroundImage: src }))
        .catch(console.error)

    const debugPad = document.querySelector('.settings__debug')
    store.addEventListener('update', e => {
        debugPad.innerText = JSON.stringify(store.state, null, 2)
    })
})

// Simplistic store, allowing us to store minimal information offline via localStorage.
class AboutBlankStore {

    // Initial state.
    get initialState() {
        return {
            version: 1,
            createdAt: Date.now()
        }
    }

    // Constructor, takes an argument specifying which localStorage key to use.
    constructor(stateStorageKey = '__ABOUT:BLANK_PREVIOUS_STATE__') {
        this.stateStorageKey = stateStorageKey
        this.state = {}
        this.listeners = {
            update: []
        }
    }

    // Hydrates the state based on localStorage.
    // Required if you care about preserving data.
    load() {
        return new Promise((resolve, reject) => {
            this._loadState()
                .then(state => this.setState(state))
                .then(resolve)
                .catch(reject)
        })
    }

    // Attempts to load state from LocalStorage, and applies current minimum state to it.
    _loadState() {
        return new Promise((resolve, reject) => {
            try {
                const state = JSON.parse(localStorage.getItem(this.stateStorageKey)) || {}
                resolve(Object.assign(this.initialState, state))
            } catch (e) {
                reject(e)
            }
        })
    }

    // Persist data in LocalStorage.
    async _saveState() {
        const serializedState = JSON.stringify(this.state)
        localStorage.setItem(this.stateStorageKey, serializedState)
    }

    // Mimics React API, allowing to replace the current state with a diff.
    setState(state) {
        const newState = Object.assign(this.state, state)
        this._dispatchEvent('update', { state: this.state, newState })
        this.state = newState
        this._saveState()
    }

    // Dispatches events.
    async _dispatchEvent(type, event = {}) {
        this.listeners[type].forEach(f => f(event))
    }

    // Allows subscribing to a state change.
    addEventListener(type, listener) {
        if (this.listeners[type] instanceof Array
            && listener instanceof Function) {
            this.listeners[type].push(listener);
        }
    }

    // Unsubscribe from state changes.
    removeEventListener(type, listener) {
        for (let subscriber in this.listeners[type]) {
            if (subscriber === listener) {
                let index = this.listeners[type].indexOf(subscriber)
                this.listeners[type].splice(index, 1)
            }
        }
    }
}
<commit_msg>Start using JSON formatted response from random images api<commit_after>// Sets a background image.
const _loadBackgroundImage = src => {
    const aboutBlankContainer = document.querySelector('.about-blank__background')
    aboutBlankContainer.style.backgroundImage = `url(${src})`
    aboutBlankContainer.classList.toggle('about-blank__background--loaded', !!src)
    return src
}

// Asynchronously downloads an image.
const _downloadImage = src => new Promise((resolve, reject) => {
    if (!src) return reject(new Error('No image specified'))
    const downloadingImage = new Image()
    downloadingImage.addEventListener('load', _ => resolve(src))
    downloadingImage.addEventListener('error', er => reject(er))
    downloadingImage.src = 'https://responsiveimages.io/v1/images/'+encodeURIComponent(src)
})

// Retrieves a random image from unsplash.
const _randomImage = _ => fetch('https://random.responsiveimages.io/v1/image?format=json')
  .then(res => res.json())
  .then(json => json.url)
  .catch(console.error)

// Bound to an Element this adjusts innerText to reflect the current time.
function displayTime() {
    const currentTime = new Date()
    this.innerText = currentTime.toLocaleTimeString('en-US')
}

// Toggles the visibility of the settings container.
const hideShowSettingsContainer = e => {
    e.preventDefault()
    const settingsContainer = document.querySelector('.settings__container')
    settingsContainer.setAttribute('aria-hidden', settingsContainer.getAttribute('aria-hidden') === "false" ? "true" : "false")
}

window.addEventListener('load', _ => {

    const clockElement = document.querySelector('.ab-time__clock')
    const incrementClock = displayTime.bind(clockElement)
    const clock = setInterval(incrementClock, 1000)
    incrementClock()

    const settingsOpenButton = document.querySelector('.about-blank__settings-button')
    const settingsCloseButton = document.querySelector('.settings__close-button')
    settingsOpenButton.addEventListener('click', hideShowSettingsContainer)
    settingsCloseButton.addEventListener('click', hideShowSettingsContainer)

    store = new AboutBlankStore()
    store.load()
        .then(_ => store.state.backgroundImage || _randomImage())
        .then(_downloadImage)
        .then(_loadBackgroundImage)
        .then(src => store.setState({ backgroundImage: src }))
        .catch(console.error)
        .then(_randomImage)
        .then(_downloadImage)
        .then(src => store.setState({ backgroundImage: src }))
        .catch(console.error)

    const debugPad = document.querySelector('.settings__debug')
    store.addEventListener('update', e => {
        debugPad.innerText = JSON.stringify(store.state, null, 2)
    })
})

// Simplistic store, allowing us to store minimal information offline via localStorage.
class AboutBlankStore {

    // Initial state.
    get initialState() {
        return {
            version: 1,
            createdAt: Date.now()
        }
    }

    // Constructor, takes an argument specifying which localStorage key to use.
    constructor(stateStorageKey = '__ABOUT:BLANK_PREVIOUS_STATE__') {
        this.stateStorageKey = stateStorageKey
        this.state = {}
        this.listeners = {
            update: []
        }
    }

    // Hydrates the state based on localStorage.
    // Required if you care about preserving data.
    load() {
        return new Promise((resolve, reject) => {
            this._loadState()
                .then(state => this.setState(state))
                .then(resolve)
                .catch(reject)
        })
    }

    // Attempts to load state from LocalStorage, and applies current minimum state to it.
    _loadState() {
        return new Promise((resolve, reject) => {
            try {
                const state = JSON.parse(localStorage.getItem(this.stateStorageKey)) || {}
                resolve(Object.assign(this.initialState, state))
            } catch (e) {
                reject(e)
            }
        })
    }

    // Persist data in LocalStorage.
    async _saveState() {
        const serializedState = JSON.stringify(this.state)
        localStorage.setItem(this.stateStorageKey, serializedState)
    }

    // Mimics React API, allowing to replace the current state with a diff.
    setState(state) {
        const newState = Object.assign(this.state, state)
        this._dispatchEvent('update', { state: this.state, newState })
        this.state = newState
        this._saveState()
    }

    // Dispatches events.
    async _dispatchEvent(type, event = {}) {
        this.listeners[type].forEach(f => f(event))
    }

    // Allows subscribing to a state change.
    addEventListener(type, listener) {
        if (this.listeners[type] instanceof Array
            && listener instanceof Function) {
            this.listeners[type].push(listener);
        }
    }

    // Unsubscribe from state changes.
    removeEventListener(type, listener) {
        for (let subscriber in this.listeners[type]) {
            if (subscriber === listener) {
                let index = this.listeners[type].indexOf(subscriber)
                this.listeners[type].splice(index, 1)
            }
        }
    }
}
<|endoftext|>


<commit_before>'use babel';

const path = require('path');

export default class PaneByType {

  static activate() {
    this.skipIds = [];

    atom.workspace.onDidOpen(event => {
      const id = event.item.id;
      this.skipIds.push(id);
      this.moveToCorrectPane(event.item, event.pane);
      const index = this.skipIds.indexOf(id);
      this.skipIds.splice(index, 1);
    });
  }

  /**
   * Move item to the first pane that has a file with the same extension
   * @param  {object} item to move
   * @param  {Pane} pane current pane
   */
  static moveToCorrectPane(item, pane) {
    const ext = this.getFileExtension(item);
    if (!this.paneHasType(pane, ext)) {
      const paneWithType = this.getPaneWithType(ext);

      if (paneWithType) {
        pane.moveItemToPane(item, paneWithType);
        paneWithType.activateItem(item);
      }
    }
  }

  /**
   * Check to see if pane contains a specific type
   * @param  {Pane} pane
   * @param  {string} type
   * @return {boolean}
   */
  static paneHasType(pane, type) {
    const types = this.getPaneTypes(pane);
    if (types.indexOf(type) < 0) {
      return false;
    }

    return true;
  }

  /**
   * Get the pane that holds a certain type
   * @param  {string} type
   * @return {Pane}
   */
  static getPaneWithType(type) {
    const panes = atom.workspace.getPanes();
    for (let pane of panes) {
      if (this.paneHasType(pane, type)) {
        return pane;
      }
    }
  }

  static getPaneTypes(pane) {
    const items = pane.getItems();
    let extensions = [];
    for (let item of items) {
      const doNotSkip = this.skipIds.indexOf(item.id) < 0 ? true : false;
      if (item.buffer && item.buffer.file && doNotSkip) {
        extensions.push(path.extname(item.buffer.file.path));
      }
    }

    return extensions;
  }

  /**
   * Get extension of file
   * @param  {object} item
   * @return {string}
   */
  static getFileExtension(item) {
    if (item.buffer && item.buffer.file) {
      return path.extname(item.buffer.file.path);
    }

    return false;
  }

  static deactivate() {}
}
<commit_msg>Set correct pane as active<commit_after>'use babel';

const path = require('path');

export default class PaneByType {

  static activate() {
    this.skipIds = [];

    atom.workspace.onDidOpen(event => {
      const id = event.item.id;
      this.skipIds.push(id);
      this.moveToCorrectPane(event.item, event.pane);
      const index = this.skipIds.indexOf(id);
      this.skipIds.splice(index, 1);
    });
  }

  /**
   * Move item to the first pane that has a file with the same extension
   * @param  {object} item to move
   * @param  {Pane} pane current pane
   */
  static moveToCorrectPane(item, pane) {
    const ext = this.getFileExtension(item);
    if (!this.paneHasType(pane, ext)) {
      const paneWithType = this.getPaneWithType(ext);
      paneWithType.activate();

      if (paneWithType) {
        pane.moveItemToPane(item, paneWithType);
        paneWithType.activateItem(item);
      }
    }
  }

  /**
   * Check to see if pane contains a specific type
   * @param  {Pane} pane
   * @param  {string} type
   * @return {boolean}
   */
  static paneHasType(pane, type) {
    const types = this.getPaneTypes(pane);
    if (types.indexOf(type) < 0) {
      return false;
    }

    return true;
  }

  /**
   * Get the pane that holds a certain type
   * @param  {string} type
   * @return {Pane}
   */
  static getPaneWithType(type) {
    const panes = atom.workspace.getPanes();
    for (let pane of panes) {
      if (this.paneHasType(pane, type)) {
        return pane;
      }
    }
  }

  static getPaneTypes(pane) {
    const items = pane.getItems();
    let extensions = [];
    for (let item of items) {
      const doNotSkip = this.skipIds.indexOf(item.id) < 0 ? true : false;
      if (item.buffer && item.buffer.file && doNotSkip) {
        extensions.push(path.extname(item.buffer.file.path));
      }
    }

    return extensions;
  }

  /**
   * Get extension of file
   * @param  {object} item
   * @return {string}
   */
  static getFileExtension(item) {
    if (item.buffer && item.buffer.file) {
      return path.extname(item.buffer.file.path);
    }

    return false;
  }

  static deactivate() {}
}
<|endoftext|>