<commit_before>
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: '<json:package.json>',
    meta: {
      banner: '// <%= pkg.title %> v<%= pkg.version %>\n' +
              '//\n' +
              '// Copyright (c) 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author.name %>\n' +
              '// Distributed under MIT License\n' +
              '//\n' +
              '// Documentation and full license available at:\n' +
              '// <%= pkg.homepage %>'
    },
    rig: {
      browser: {
        src: ['<banner:meta.banner>', '<file_strip_banner:src/<%= pkg.name %>.js>'],
        dest: 'dist/<%= pkg.name %>.js'
      },
      amd: {
        src: ['<banner:meta.banner>', '<file_strip_banner:src/<%= pkg.name %>-amd.js>'],
        dest: 'dist/<%= pkg.name %>-amd.js'
      }
    },
    min: {
      browser: {
        src: ['<banner:meta.banner>', '<config:rig.browser.dest>'],
        dest: 'dist/<%= pkg.name %>-min.js'
      },
      amd: {
        src: ['<banner:meta.banner>', '<config:rig.amd.dest>'],
        dest: 'dist/<%= pkg.name %>-amd-min.js'
      }
    },
    watch: {
      files: '<config:lint.files>',
      tasks: 'default'
    },
    buster: {
      test: {
        'config': 'buster.js',
        'color': 'none',
        'config-group': 'Browser'
      },
      server: {
        'port': '1111'
      }
    },
    lint: {
      files: ['grunt.js', 'src/**/*.js', 'tests/**/*.js']
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        browser: true,
        node: true
      },
      globals: {
        Backbone: true,
        _: true,
        jQuery: true,
        $: true,
        buster: true,
        assert: true,
        refute: true,
        define: true
      }
    },
    uglify: {},
    docco: {
      app: {
        src: ['dist/backbone-validation.js'],
        options: {
          template: 'docco.jst'
        }
      }
    },

    shell: {
      npm: {
        command: 'npm publish',
        stdout: true
      },
      clone: {
        command: 'git clone git@github.com:thedersen/thedersen.github.com.git',
        stdout: true
      },
      copyDocco: {
        command: 'cp docs/backbone-validation.html thedersen.github.com/projects/backbone-validation/docs/index.html',
        stdout: true
      },
      copyCss: {
        command: 'cp docs/docco.css thedersen.github.com/projects/backbone-validation/docs/docco.css',
        stdout: true
      },
      copyExamples: {
        command: 'cp examples/* thedersen.github.com/projects/backbone-validation/example',
        stdout: true
      },
      push: {
        command: 'git commit -am "Updated docs for Backbone.Validation" && git push origin master',
        stdout: true,
        execOptions: {
          cwd: 'thedersen.github.com'
        }
      },
      cleanup: {
        command: 'rm -rf thedersen.github.com',
        stdout: true
      }
    }
  });

  grunt.registerTask('default', 'rig lint buster min');
  grunt.registerTask('publish', 'docco shell');

  grunt.loadNpmTasks('grunt-buster');
  grunt.loadNpmTasks('grunt-docco');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-rigger');
};
<commit_msg>Fixed error in cp command in grunt<commit_after>
module.exports = function(grunt) {

  // Project configuration.
  grunt.initConfig({
    pkg: '<json:package.json>',
    meta: {
      banner: '// <%= pkg.title %> v<%= pkg.version %>\n' +
              '//\n' +
              '// Copyright (c) 2011-<%= grunt.template.today("yyyy") %> <%= pkg.author.name %>\n' +
              '// Distributed under MIT License\n' +
              '//\n' +
              '// Documentation and full license available at:\n' +
              '// <%= pkg.homepage %>'
    },
    rig: {
      browser: {
        src: ['<banner:meta.banner>', '<file_strip_banner:src/<%= pkg.name %>.js>'],
        dest: 'dist/<%= pkg.name %>.js'
      },
      amd: {
        src: ['<banner:meta.banner>', '<file_strip_banner:src/<%= pkg.name %>-amd.js>'],
        dest: 'dist/<%= pkg.name %>-amd.js'
      }
    },
    min: {
      browser: {
        src: ['<banner:meta.banner>', '<config:rig.browser.dest>'],
        dest: 'dist/<%= pkg.name %>-min.js'
      },
      amd: {
        src: ['<banner:meta.banner>', '<config:rig.amd.dest>'],
        dest: 'dist/<%= pkg.name %>-amd-min.js'
      }
    },
    watch: {
      files: '<config:lint.files>',
      tasks: 'default'
    },
    buster: {
      test: {
        'config': 'buster.js',
        'color': 'none',
        'config-group': 'Browser'
      },
      server: {
        'port': '1111'
      }
    },
    lint: {
      files: ['grunt.js', 'src/**/*.js', 'tests/**/*.js']
    },
    jshint: {
      options: {
        curly: true,
        eqeqeq: true,
        immed: true,
        latedef: true,
        newcap: true,
        noarg: true,
        sub: true,
        undef: true,
        boss: true,
        eqnull: true,
        browser: true,
        node: true
      },
      globals: {
        Backbone: true,
        _: true,
        jQuery: true,
        $: true,
        buster: true,
        assert: true,
        refute: true,
        define: true
      }
    },
    uglify: {},
    docco: {
      app: {
        src: ['dist/backbone-validation.js'],
        options: {
          template: 'docco.jst'
        }
      }
    },

    shell: {
      npm: {
        command: 'npm publish',
        stdout: true
      },
      clone: {
        command: 'git clone git@github.com:thedersen/thedersen.github.com.git',
        stdout: true
      },
      copyDocco: {
        command: 'cp docs/backbone-validation.html thedersen.github.com/projects/backbone-validation/docs/index.html',
        stdout: true
      },
      copyCss: {
        command: 'cp docs/docco.css thedersen.github.com/projects/backbone-validation/docs/docco.css',
        stdout: true
      },
      copyExamples: {
        command: 'cp -rf examples/ thedersen.github.com/projects/backbone-validation/examples/',
        stdout: true
      },
      push: {
        command: 'git commit -am "Updated docs for Backbone.Validation" && git push origin master',
        stdout: true,
        execOptions: {
          cwd: 'thedersen.github.com'
        }
      },
      cleanup: {
        command: 'rm -rf thedersen.github.com',
        stdout: true
      }
    }
  });

  grunt.registerTask('default', 'rig lint buster min');
  grunt.registerTask('publish', 'docco shell');

  grunt.loadNpmTasks('grunt-buster');
  grunt.loadNpmTasks('grunt-docco');
  grunt.loadNpmTasks('grunt-shell');
  grunt.loadNpmTasks('grunt-rigger');
};
<|endoftext|>


<commit_before>const React = require('react');

class FileUpload extends React.Component {
  constructor() {
    super();
    this.state = {

    };
  }

  componentDidMount() {
    const Dropzone = window.Dropzone;
    const dropzone = new Dropzone('#dropzone', { url: 'http://localhost:3003/api/media' });
    dropzone.on('success', (err, res) => {
      console.log(`image name: ${res}`);
      this.props.handleFile(res);
    });
  }

  render() {
    return (

    );
  }
}

FileUpload.propTypes = {
  handleFile: React.PropTypes.func,
};

export default FileUpload;
<commit_msg>implemented file uploading with dropzone and media server microservice<commit_after>import React, { Component } from 'react';

class FileUpload extends Component {
  constructor() {
    super();
    this.state = {

    };
  }

  componentDidMount() {
    const Dropzone = window.Dropzone;
    const dropzone = new Dropzone('#dropzone', { url: 'http://localhost:3003/api/media' });
    dropzone.on('success', (err, res) => {
      console.log(`image name: ${res}`);
      this.props.handleFile(res);
    });
  }

  render() {
    return (

    );
  }
}

FileUpload.propTypes = {
  handleFile: React.PropTypes.func,
};

export default FileUpload;
<|endoftext|>


<commit_before>/*
 * jQuery The Final Countdown plugin v2.0.0
 * http://github.com/hilios/jquery.countdown
 *
 * Copyright (c) 2011 Edson Hilios
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 // AMD support (Thanks to @FagnerMartinsBrack)
;(function(factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else {
        factory(jQuery);
    }
})(function($){
    var PRECISION   = 100; // 0.1 seconds, used to update the DOM
    var instances   = {},
        matchers    = [];
    // Miliseconds
    matchers.push(/^[0-9]*$/.source);
    // Month/Day/Year [hours:minutes:seconds[.TZD]]
    matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}((\s|T)[0-9]{1,2}(\:[0-9]{2}){2})?/.source);
    // Year/Day/Month [hours:minutes:seconds[.TZD]]
    matchers.push(/[0-9]{4}(\/[0-9]{1,2}){2}((\s|T)[0-9]{1,2}(\:[0-9]{2}){2})?/.source);
    // Cast the matchers to a regular expression object
    matchers = new RegExp(matchers.join("|"));
    // Parse a Date formatted has String to a native object
    function parseDateString(dateString) {
        // Pass through when a native object is sent
        if(dateString instanceof Date) {
            return dateString;
        }
        // Caste string to date object
        if(String(dateString).match(matchers)) {
            // If looks like a milisecond value cast to number before
            // final casting (Thanks to @msigley)
            if(String(dateString).match(/^[0-9]*$/)) {
                dateString = Number(dateString);
            }
            return new Date(dateString);
        } else {
            throw new Error("Couldn't cast `" + dateString +
                "` to a date object.");
        }
    }
    var DIRECTIVE_KEY_MAP = {
        'Y': 'years',
        'm': 'months',
        'w': 'weeks',
        'd': 'days',
        'D': 'totalDays',
        'H': 'hours',
        'M': 'minutes',
        'S': 'seconds'
    };
    // Time string formatter
    function strftime(offsetObject) {
        return function(format) {
            var directives = format.match(/%(-|!)?[A-Z]{1,}(<[^>]+>)?/gi);
            if(directives) {
                for(var i = 0, len = directives.length; i < len; ++i) {
                    var directive   = directives[i]
                            .match(/%(-|!)?([a-zA-Z]+)(<[^>]+>)?/),
                        regexp      = new RegExp(directive[0]),
                        modifier    = directive[1] || '',
                        plural      = directive[3] || '',
                        value       = null;
                        // Get the key
                        directive = directive[2];
                    // Swap shot-versions directives
                    if(DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
                        value = DIRECTIVE_KEY_MAP[directive];
                        value = Number(offsetObject[value]);
                    }
                    if(offsetObject.hasOwnProperty(directive)) {
                        value = Number(offsetObject[directive]);
                    }
                    if(value !== null) {
                        // Pluralize
                        if(modifier === '!') {
                            value = pluralize(plural, value);
                        }
                        // Add zero-padding
                        if(modifier === '') {
                            if(value < 10) {
                                value = '0' + value.toString();
                            }
                        }
                        // Replace the directive
                        format = format.replace(regexp, value.toString());
                    }
                }
            }
            format = format.replace(/%%/, '%');
            return format;
        };
    }
    // Pluralize
    function pluralize(format, count) {
        var plural = 's', singular = '';
        if(format) {
            format = format.replace(/(<|>|\s)/gi, '').split(/\,/);
            if(format.length === 1) {
                plural = format[0];
            } else {
                singular = format[0];
                plural = format[1];
            }
        }
        if(Math.abs(count) === 1) {
            return singular;
        } else {
            return plural;
        }

    }

    // The Final Countdown
    var Countdown = function(el, finalDate, callback) {
        this.el             = el;
        this.$el            = $(el);
        this.interval       = null;
        this.offset         = {};
        // Set the final date
        this.setFinalDate(finalDate);
        // Register the callbacks when supplied
        if(callback) {
            this.$el.on('update.countdown', callback);
            this.$el.on('stoped.countdown', callback);
            this.$el.on('finish.countdown', callback);
        }
        this.start();
    };
    $.extend(Countdown.prototype, {
        start: function() {
            if(this.interval !== null) {
                throw new Error("Countdown is already running!");
            }
            var self = this;
            this.update();
            this.interval = setInterval(function() {
                self.update.call(self);
            }, PRECISION);
        },
        stop: function() {
            clearInterval(this.interval);
            this.interval = null;
            this.dispatchEvent('stoped');
        },
        pause: function() {
            this.stop.call(this);
        },
        resume: function() {
            this.start.call(this);
        },
        remove: function() {
            this.stop();
            delete instances[this.el];
        },
        setFinalDate: function(value) {
            this.finalDate = parseDateString(value); // Cast the given date
        },
        update: function() {
            // Stop if dom is not in the html (Thanks to @dleavitt)
            if(this.$el.closest('html').length === 0) {
                this.remove();
                return;
            }
            // Calculate the remaining time
            this.totalSecsLeft = this.finalDate.valueOf() -
                new Date().valueOf(); // In miliseconds
            this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1000);
            this.totalSecsLeft = this.totalSecsLeft < 0 ?
                0 : this.totalSecsLeft;
            // Calculate the offsets
            this.offset = {
                seconds     : this.totalSecsLeft % 60,
                minutes     : Math.floor(this.totalSecsLeft / 60) % 60,
                hours       : Math.floor(this.totalSecsLeft / 60 / 60) % 24,
                days        : Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
                totalDays   : Math.floor(this.totalSecsLeft / 60 / 60 / 24),
                weeks       : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
                months      : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30),
                years       : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365)
            };
            // Dispatch an event
            if(this.totalSecsLeft === 0) {
                this.stop();
                this.dispatchEvent('finish');
            } else {
                this.dispatchEvent('update');
            }
        },
        dispatchEvent: function(eventName) {
            var event = $.Event(eventName + '.countdown');
            event.finalDate     = this.finalDate;
            event.offset        = $.extend({}, this.offset);
            event.offsetDate    = new Date(this.totalSecsLeft);
            event.strftime      = strftime(this.offset);
            this.$el.trigger(event);
        }
    });
    // Register the jQuery selector actions
    $.fn.countdown = function() {
        var argumentsArray = Array.prototype.slice.call(arguments, 0);
        return this.each(function() {
            // Verify if we already have a countdown for this node ...
            if(instances.hasOwnProperty(this)) {
                var method = argumentsArray[0];
                // If method exists in the prototype execute
                if(Countdown.prototype.hasOwnProperty(method)) {
                    instances[this][method].apply(instances[this],
                        argumentsArray.slice(1));
                // If method look like a date try to set a new final date
                } else if(method.match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
                    instances[this].setFinalDate.call(instances[this],
                        method);
                } else {
                    $.error('Method %s does not exist on jQuery.countdown'.
                        replace(/\%s/gi, method));
                }
            } else {
                // ... if not we create an instance
                instances[this] = new Countdown(this, argumentsArray[0],
                    argumentsArray[1]);
            }
        });
    };
});<commit_msg>Remove the T from date parse regexp, not rely in iso formats<commit_after>/*
 * jQuery The Final Countdown plugin v2.0.0
 * http://github.com/hilios/jquery.countdown
 *
 * Copyright (c) 2011 Edson Hilios
 *
 * Permission is hereby granted, free of charge, to any person obtaining
 * a copy of this software and associated documentation files (the
 * "Software"), to deal in the Software without restriction, including
 * without limitation the rights to use, copy, modify, merge, publish,
 * distribute, sublicense, and/or sell copies of the Software, and to
 * permit persons to whom the Software is furnished to do so, subject to
 * the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
 // AMD support (Thanks to @FagnerMartinsBrack)
;(function(factory) {
    if (typeof define === 'function' && define.amd) {
        define(['jquery'], factory);
    } else {
        factory(jQuery);
    }
})(function($){
    var PRECISION   = 100; // 0.1 seconds, used to update the DOM
    var instances   = {},
        matchers    = [];
    // Miliseconds
    matchers.push(/^[0-9]*$/.source);
    // Month/Day/Year [hours:minutes:seconds[.TZD]]
    matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}(\s[0-9]{1,2}(\:[0-9]{2}){2})?/.source);
    // Year/Day/Month [hours:minutes:seconds[.TZD]]
    matchers.push(/[0-9]{4}(\/[0-9]{1,2}){2}(\s[0-9]{1,2}(\:[0-9]{2}){2})?/.source);
    // Cast the matchers to a regular expression object
    matchers = new RegExp(matchers.join("|"));
    // Parse a Date formatted has String to a native object
    function parseDateString(dateString) {
        // Pass through when a native object is sent
        if(dateString instanceof Date) {
            return dateString;
        }
        // Caste string to date object
        if(String(dateString).match(matchers)) {
            // If looks like a milisecond value cast to number before
            // final casting (Thanks to @msigley)
            if(String(dateString).match(/^[0-9]*$/)) {
                dateString = Number(dateString);
            }
            return new Date(dateString);
        } else {
            throw new Error("Couldn't cast `" + dateString +
                "` to a date object.");
        }
    }
    var DIRECTIVE_KEY_MAP = {
        'Y': 'years',
        'm': 'months',
        'w': 'weeks',
        'd': 'days',
        'D': 'totalDays',
        'H': 'hours',
        'M': 'minutes',
        'S': 'seconds'
    };
    // Time string formatter
    function strftime(offsetObject) {
        return function(format) {
            var directives = format.match(/%(-|!)?[A-Z]{1,}(<[^>]+>)?/gi);
            if(directives) {
                for(var i = 0, len = directives.length; i < len; ++i) {
                    var directive   = directives[i]
                            .match(/%(-|!)?([a-zA-Z]+)(<[^>]+>)?/),
                        regexp      = new RegExp(directive[0]),
                        modifier    = directive[1] || '',
                        plural      = directive[3] || '',
                        value       = null;
                        // Get the key
                        directive = directive[2];
                    // Swap shot-versions directives
                    if(DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) {
                        value = DIRECTIVE_KEY_MAP[directive];
                        value = Number(offsetObject[value]);
                    }
                    if(offsetObject.hasOwnProperty(directive)) {
                        value = Number(offsetObject[directive]);
                    }
                    if(value !== null) {
                        // Pluralize
                        if(modifier === '!') {
                            value = pluralize(plural, value);
                        }
                        // Add zero-padding
                        if(modifier === '') {
                            if(value < 10) {
                                value = '0' + value.toString();
                            }
                        }
                        // Replace the directive
                        format = format.replace(regexp, value.toString());
                    }
                }
            }
            format = format.replace(/%%/, '%');
            return format;
        };
    }
    // Pluralize
    function pluralize(format, count) {
        var plural = 's', singular = '';
        if(format) {
            format = format.replace(/(<|>|\s)/gi, '').split(/\,/);
            if(format.length === 1) {
                plural = format[0];
            } else {
                singular = format[0];
                plural = format[1];
            }
        }
        if(Math.abs(count) === 1) {
            return singular;
        } else {
            return plural;
        }

    }

    // The Final Countdown
    var Countdown = function(el, finalDate, callback) {
        this.el             = el;
        this.$el            = $(el);
        this.interval       = null;
        this.offset         = {};
        // Set the final date
        this.setFinalDate(finalDate);
        // Register the callbacks when supplied
        if(callback) {
            this.$el.on('update.countdown', callback);
            this.$el.on('stoped.countdown', callback);
            this.$el.on('finish.countdown', callback);
        }
        this.start();
    };
    $.extend(Countdown.prototype, {
        start: function() {
            if(this.interval !== null) {
                throw new Error("Countdown is already running!");
            }
            var self = this;
            this.update();
            this.interval = setInterval(function() {
                self.update.call(self);
            }, PRECISION);
        },
        stop: function() {
            clearInterval(this.interval);
            this.interval = null;
            this.dispatchEvent('stoped');
        },
        pause: function() {
            this.stop.call(this);
        },
        resume: function() {
            this.start.call(this);
        },
        remove: function() {
            this.stop();
            delete instances[this.el];
        },
        setFinalDate: function(value) {
            this.finalDate = parseDateString(value); // Cast the given date
        },
        update: function() {
            // Stop if dom is not in the html (Thanks to @dleavitt)
            if(this.$el.closest('html').length === 0) {
                this.remove();
                return;
            }
            // Calculate the remaining time
            this.totalSecsLeft = this.finalDate.valueOf() -
                new Date().valueOf(); // In miliseconds
            this.totalSecsLeft = Math.ceil(this.totalSecsLeft / 1000);
            this.totalSecsLeft = this.totalSecsLeft < 0 ?
                0 : this.totalSecsLeft;
            // Calculate the offsets
            this.offset = {
                seconds     : this.totalSecsLeft % 60,
                minutes     : Math.floor(this.totalSecsLeft / 60) % 60,
                hours       : Math.floor(this.totalSecsLeft / 60 / 60) % 24,
                days        : Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7,
                totalDays   : Math.floor(this.totalSecsLeft / 60 / 60 / 24),
                weeks       : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7),
                months      : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30),
                years       : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 365)
            };
            // Dispatch an event
            if(this.totalSecsLeft === 0) {
                this.stop();
                this.dispatchEvent('finish');
            } else {
                this.dispatchEvent('update');
            }
        },
        dispatchEvent: function(eventName) {
            var event = $.Event(eventName + '.countdown');
            event.finalDate     = this.finalDate;
            event.offset        = $.extend({}, this.offset);
            event.offsetDate    = new Date(this.totalSecsLeft);
            event.strftime      = strftime(this.offset);
            this.$el.trigger(event);
        }
    });
    // Register the jQuery selector actions
    $.fn.countdown = function() {
        var argumentsArray = Array.prototype.slice.call(arguments, 0);
        return this.each(function() {
            // Verify if we already have a countdown for this node ...
            if(instances.hasOwnProperty(this)) {
                var method = argumentsArray[0];
                // If method exists in the prototype execute
                if(Countdown.prototype.hasOwnProperty(method)) {
                    instances[this][method].apply(instances[this],
                        argumentsArray.slice(1));
                // If method look like a date try to set a new final date
                } else if(method.match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) {
                    instances[this].setFinalDate.call(instances[this],
                        method);
                } else {
                    $.error('Method %s does not exist on jQuery.countdown'.
                        replace(/\%s/gi, method));
                }
            } else {
                // ... if not we create an instance
                instances[this] = new Countdown(this, argumentsArray[0],
                    argumentsArray[1]);
            }
        });
    };
});<|endoftext|>


<commit_before>// Based on
// https://github.com/reasonml/reasonml.github.io/blob/source/regenerateStdlibForBrowser.js

const fs = require('fs');
const path = require('path');
const browserify = require('browserify');

const b = browserify();

const stdlibDir = path.join(__dirname, 'stdlib');

let stdlibDirFiles;
try {
  stdlibDirFiles = fs.readdirSync(stdlibDir);
} catch (e) {
  console.log(`
** There's an error while reading ${stdlibDir}.`);
  process.exit(1);
};

stdlibDirFiles.forEach(file => {
  const exposedRequireName = path.basename(file, '.js');
  // map `require('stdlib/list')` from the playground to `require('./stdlib/list.js')`
  b.require(path.join(stdlibDir, file), {expose: exposedRequireName});
});

b
  .transform('uglifyify', { global: true })
  .require(path.join(__dirname, 'dummy.js'), {expose: 'fs'})
  .bundle()
  .pipe(fs.createWriteStream(path.join(__dirname, 'stdlibBundle.js')));

<commit_msg>Fix regenerateStdlibForBrowser.js<commit_after>#!/usr/bin/env node

// Based on:
// https://github.com/reasonml/reasonml.github.io/blob/source/regenerateStdlibForBrowser.js

const fs = require('fs');
const path = require('path');
const browserify = require('browserify');

const b = browserify();

const stdlibDir = path.join(__dirname, 'stdlib');

let stdlibDirFiles;
try {
  stdlibDirFiles = fs.readdirSync(stdlibDir);
} catch (e) {
  console.log(`
** There's an error while reading ${stdlibDir}.`);
  process.exit(1);
};

stdlibDirFiles.forEach(file => {
  const exposedRequireName = path.join('stdlib', path.basename(file, '.js'));
  // map `require('stdlib/list')` from the playground to `require('./stdlib/list.js')`
  b.require(path.join(stdlibDir, file), {expose: exposedRequireName});
});

b
  .transform('deamdify')
  .transform('uglifyify', { global: true })
  .require(path.join(__dirname, 'dummy.js'), {expose: 'fs'})
  .bundle()
  .pipe(fs.createWriteStream(path.join(__dirname, 'stdlibBundle.js')));

<|endoftext|>


<commit_before>import React from 'react';
import gql from 'graphql-tag';
import cx from 'clsx';
import { makeStyles, withStyles } from '@material-ui/core/styles';
import { Badge } from '@material-ui/core';
import { TYPE_ICON } from 'constants/replyType';
import Peep from 'react-peeps';

const NULL_USER_IMG =
  'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp';

const useStyles = makeStyles({
  root: {
    width: size => size,
    height: size => size,
    borderRadius: '50%',
    cursor: 'pointer',
  },
});

const peepsStyles = {
  peepStyle: {
    justifyContent: 'center',
    alignSelf: 'center',
  },
  circleStyle: {
    alignSelf: 'center',
    borderRadius: '50%',
    overflow: 'hidden',
  },
};

const LevelBadge = withStyles(theme => ({
  container: {
    position: 'relative',
  },
  badge: {
    position: 'absolute',
    left: -1,
    bottom: -8,
    right: -1,
    background: theme.palette.secondary[500],
    color: theme.palette.common.white,
    border: `1px solid ${theme.palette.common.white}`,
    fontSize: 10,
    borderRadius: 25,
    textAlign: 'center',
    [theme.breakpoints.up('md')]: {
      width: 48,
      margin: '0 auto',
      bottom: 0,
      fontSize: 12,
      fontWeight: 'bold',
    },
  },
}))(({ level, classes, children, props }) => (

    {children}

Lv{+level}

));

const StatusBadge = withStyles(theme => ({
  badge: {
    transform: 'translate(30%, -20%)',
    [theme.breakpoints.up('md')]: {
      transform: 'translate(30%, -5%)',
    },
  },
  icon: {
    fontSize: 16,
    [theme.breakpoints.up('md')]: {
      fontSize: 40,
    },
  },
}))(({ classes, status, ...props }) => {
  const Component = TYPE_ICON[status];
  return (
    <Badge
      badgeContent={<Component className={classes.icon} />}
      classes={{ badge: classes.badge }}
      {...props}
    />
  );
});

const OpenPeepsAvatar = withStyles(theme => ({
  showcaseWrapper: {
    display: 'flex',
    justifyContent: 'center',
    height: '-webkit-fill-available',
    cursor: 'pointer',
    '& div': {
      width: ({ size }) => size,
      height: ({ size }) => size,
      [theme.breakpoints.up('md')]: {
        width: ({ size, mdSize }) => mdSize ?? size,
        height: ({ size, mdSize }) => mdSize ?? size,
      },
    },
    '& svg': {
      width: ({ size }) => size,
      height: ({ size }) => size,
      [theme.breakpoints.up('md')]: {
        width: ({ size, mdSize }) => mdSize ?? size,
        height: ({ size, mdSize }) => mdSize ?? size,
      },
      transform: ({ avatarData }) =>
        avatarData?.flip ? 'scale(-1, 1)' : 'scale(1, 1)',
      backgroundColor: ({ avatarData }) => {
        const cofactsColors = Object.values(theme.palette.common);
        if (avatarData?.backgroundColor) return avatarData.backgroundColor;
        if (avatarData?.backgroundColorIndex) {
          const index = Math.floor(
            cofactsColors.length * avatarData.backgroundColorIndex
          );
          return cofactsColors[index];
        }
        return '#FFF';
      },
    },
  },
  // eslint-disable-next-line no-unused-vars
}))(({ className, classes, avatarData, size, mdSize, ...rest }) => {
  return (

        <Peep
          {...avatarData}
          style={peepsStyles.peepStyle}
          circleStyle={peepsStyles.circleStyle}
          strokeColor="#000"
        />

  );
});

function Avatar({
  user,
  size = 24,
  mdSize = null,
  showLevel = false,
  status = null,
  className,
  ...rest
}) {
  const classes = useStyles(size);
  let avatarData;
  let avatar;

  if (user?.avatarType === 'OpenPeeps') {
    try {
      avatarData = JSON.parse(user.avatarData);
      avatar = (
        <OpenPeepsAvatar
          className={className}
          avatarData={avatarData}
          size={size}
          mdSize={mdSize}
          {...rest}
        />
      );
    } catch {} // eslint-disable-line no-empty
  }

  if (!avatar) {
    avatar = (

    );
  }

  if (showLevel) {
    avatar = <LevelBadge level={user?.level}>{avatar}</LevelBadge>;
  }
  if (status) {
    avatar = <StatusBadge status={status}>{avatar}</StatusBadge>;
  }
  return avatar;
}

Avatar.fragments = {
  AvatarData: gql`
    fragment AvatarData on User {
      id
      level
      avatarUrl
      avatarType
      avatarData
    }
  `,
};

export default Avatar;
<commit_msg>remove black and white as avatar background options<commit_after>import React from 'react';
import gql from 'graphql-tag';
import cx from 'clsx';
import { makeStyles, withStyles } from '@material-ui/core/styles';
import { Badge } from '@material-ui/core';
import { TYPE_ICON } from 'constants/replyType';
import Peep from 'react-peeps';
import { omit } from 'lodash';

const NULL_USER_IMG =
  'https://www.gravatar.com/avatar/00000000000000000000000000000000?d=mp';

const useStyles = makeStyles({
  root: {
    width: size => size,
    height: size => size,
    borderRadius: '50%',
    cursor: 'pointer',
  },
});

const peepsStyles = {
  peepStyle: {
    justifyContent: 'center',
    alignSelf: 'center',
  },
  circleStyle: {
    alignSelf: 'center',
    borderRadius: '50%',
    overflow: 'hidden',
  },
};

const LevelBadge = withStyles(theme => ({
  container: {
    position: 'relative',
  },
  badge: {
    position: 'absolute',
    left: -1,
    bottom: -8,
    right: -1,
    background: theme.palette.secondary[500],
    color: theme.palette.common.white,
    border: `1px solid ${theme.palette.common.white}`,
    fontSize: 10,
    borderRadius: 25,
    textAlign: 'center',
    [theme.breakpoints.up('md')]: {
      width: 48,
      margin: '0 auto',
      bottom: 0,
      fontSize: 12,
      fontWeight: 'bold',
    },
  },
}))(({ level, classes, children, props }) => (

    {children}

Lv{+level}

));

const StatusBadge = withStyles(theme => ({
  badge: {
    transform: 'translate(30%, -20%)',
    [theme.breakpoints.up('md')]: {
      transform: 'translate(30%, -5%)',
    },
  },
  icon: {
    fontSize: 16,
    [theme.breakpoints.up('md')]: {
      fontSize: 40,
    },
  },
}))(({ classes, status, ...props }) => {
  const Component = TYPE_ICON[status];
  return (
    <Badge
      badgeContent={<Component className={classes.icon} />}
      classes={{ badge: classes.badge }}
      {...props}
    />
  );
});

const OpenPeepsAvatar = withStyles(theme => ({
  showcaseWrapper: {
    display: 'flex',
    justifyContent: 'center',
    height: '-webkit-fill-available',
    cursor: 'pointer',
    '& div': {
      width: ({ size }) => size,
      height: ({ size }) => size,
      [theme.breakpoints.up('md')]: {
        width: ({ size, mdSize }) => mdSize ?? size,
        height: ({ size, mdSize }) => mdSize ?? size,
      },
    },
    '& svg': {
      width: ({ size }) => size,
      height: ({ size }) => size,
      [theme.breakpoints.up('md')]: {
        width: ({ size, mdSize }) => mdSize ?? size,
        height: ({ size, mdSize }) => mdSize ?? size,
      },
      transform: ({ avatarData }) =>
        avatarData?.flip ? 'scale(-1, 1)' : 'scale(1, 1)',
      backgroundColor: ({ avatarData }) => {
        const cofactsColors = Object.values(omit(theme.palette.common, ['black', 'white']));
        if (avatarData?.backgroundColor) return avatarData.backgroundColor;
        if (avatarData?.backgroundColorIndex) {
          const index = Math.floor(
            cofactsColors.length * avatarData.backgroundColorIndex
          );
          return cofactsColors[index];
        }
        return theme.palette.common.yellow;
      },
    },
  },
  // eslint-disable-next-line no-unused-vars
}))(({ className, classes, avatarData, size, mdSize, ...rest }) => {
  return (

        <Peep
          {...avatarData}
          style={peepsStyles.peepStyle}
          circleStyle={peepsStyles.circleStyle}
          strokeColor="#000"
        />

  );
});

function Avatar({
  user,
  size = 24,
  mdSize = null,
  showLevel = false,
  status = null,
  className,
  ...rest
}) {
  const classes = useStyles(size);
  let avatarData;
  let avatar;

  if (user?.avatarType === 'OpenPeeps') {
    try {
      avatarData = JSON.parse(user.avatarData);
      avatar = (
        <OpenPeepsAvatar
          className={className}
          avatarData={avatarData}
          size={size}
          mdSize={mdSize}
          {...rest}
        />
      );
    } catch {} // eslint-disable-line no-empty
  }

  if (!avatar) {
    avatar = (

    );
  }

  if (showLevel) {
    avatar = <LevelBadge level={user?.level}>{avatar}</LevelBadge>;
  }
  if (status) {
    avatar = <StatusBadge status={status}>{avatar}</StatusBadge>;
  }
  return avatar;
}

Avatar.fragments = {
  AvatarData: gql`
    fragment AvatarData on User {
      id
      level
      avatarUrl
      avatarType
      avatarData
    }
  `,
};

export default Avatar;
<|endoftext|>


<commit_before>/**
 *
 * Content Style - Image (JS)
 *
 * @author Takuto Yanagida @ Space-Time Inc.
 * @version 2018-04-03
 *
 */

document.addEventListener('DOMContentLoaded', function () {

	const TARGET_SELECTOR = '.stile';

	modifyFigureStyle();
	initializeLazyImageLoading();

	// -------------------------------------------------------------------------
	// Figure Styles

	function modifyFigureStyle() {
		const figs = document.querySelectorAll(TARGET_SELECTOR + ' figure');
		for (let i = 0; i < figs.length; i += 1) {
			figs[i].style.width = '';
		}
	}

	// -------------------------------------------------------------------------
	// Lazy Image Loading

	function initializeLazyImageLoading() {
		const OFFSET = 100;
		const imgs = document.querySelectorAll(TARGET_SELECTOR + ' img');
		const imgsInTbl = document.querySelectorAll(TARGET_SELECTOR + ' table img');

		const winY = window.scrollY | window.pageYOffset;
		for (let i = 0; i < imgs.length; i += 1) {
			const img = imgs[i];
			if ([].indexOf.call(imgsInTbl, img) !== -1) continue;
			if (elementTopOnWindow(img) >= winY + window.innerHeight + OFFSET) hide(img);
		}
		window.addEventListener('scroll', onScroll);
		onScroll();

		function onScroll() {
			const winY = window.scrollY | window.pageYOffset;
			for (let i = 0; i < imgs.length; i += 1) {
				const img = imgs[i];
				if (!img.dataset.src) continue;
				const imgY = elementTopOnWindow(img);
				if (imgY < winY + window.innerHeight + OFFSET) show(img);
			}
		}

		doBeforePrint(onPrint);
		function onPrint() {
			for (let i = 0; i < imgs.length; i += 1) {
				const img = imgs[i];
				if (!img.dataset.src) continue;
				show(img, true);
			}
			setTimeout(onPrint, 200);
		}
	}

	function hide(img) {
		img.dataset['src'] = img.src;
		img.src = 'data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=';
		if (img.srcset) {
			img.dataset['srcset'] = img.srcset;
			img.srcset = '';
		}
		img.style.opacity = 0;
		const h = img.getAttribute('height');
		if (h) img.style.minHeight = h + 'px';
	}

	function show(img, immediately = false) {
		if (img.dataset.srcset) {
			img.srcset = img.dataset.srcset;
			img.dataset.srcset = '';
		}
		img.src = img.dataset.src;
		img.dataset.src = '';
		img.style.minHeight = '';
		if (immediately) {
			img.style.opacity = '';
		} else {
			setTimeout(function () {img.style.opacity = '';}, 200);
		}
	}

	function elementTopOnWindow(elm) {
		let top = 0;
		while (elm) {
			top += elm.offsetTop;
			elm = elm.offsetParent;
		}
		return top;
	}

	function doBeforePrint(func, forceMediaCheck = true) {
		window.addEventListener('beforeprint', func, false);
		if (forceMediaCheck || !('onbeforeprint' in window)) {
			if (window.matchMedia) {
				let mediaQueryList = window.matchMedia('print');
				mediaQueryList.addListener(function (mql) {
					if (mql.matches) func();
				});
			}
		}
	}

});
<commit_msg>Modify that lazy image loading function does not run on firefox<commit_after>/**
 *
 * Content Style - Image (JS)
 *
 * @author Takuto Yanagida @ Space-Time Inc.
 * @version 2018-04-05
 *
 */

document.addEventListener('DOMContentLoaded', function () {

	const TARGET_SELECTOR = '.stile';

	modifyFigureStyle();
	if (!document.body.classList.contains('firefox')) {
		initializeLazyImageLoading();
	}

	// -------------------------------------------------------------------------
	// Figure Styles

	function modifyFigureStyle() {
		const figs = document.querySelectorAll(TARGET_SELECTOR + ' figure');
		for (let i = 0; i < figs.length; i += 1) {
			figs[i].style.width = '';
		}
	}

	// -------------------------------------------------------------------------
	// Lazy Image Loading

	function initializeLazyImageLoading() {
		const OFFSET = 100;
		const imgs = document.querySelectorAll(TARGET_SELECTOR + ' img');
		const imgsInTbl = document.querySelectorAll(TARGET_SELECTOR + ' table img');

		const winY = window.scrollY | window.pageYOffset;
		for (let i = 0; i < imgs.length; i += 1) {
			const img = imgs[i];
			if ([].indexOf.call(imgsInTbl, img) !== -1) continue;
			if (elementTopOnWindow(img) >= winY + window.innerHeight + OFFSET) hide(img);
		}
		window.addEventListener('scroll', onScroll);
		onScroll();

		function onScroll() {
			const winY = window.scrollY | window.pageYOffset;
			for (let i = 0; i < imgs.length; i += 1) {
				const img = imgs[i];
				if (!img.dataset.src) continue;
				const imgY = elementTopOnWindow(img);
				if (imgY < winY + window.innerHeight + OFFSET) show(img);
			}
		}

		doBeforePrint(onPrint);
		function onPrint() {
			for (let i = 0; i < imgs.length; i += 1) {
				const img = imgs[i];
				if (!img.dataset.src) continue;
				show(img, true);
			}
		}
	}

	function hide(img) {
		img.dataset['src'] = img.src;
		img.src = 'data:image/gif;base64,R0lGODdhAQABAPAAAP///wAAACwAAAAAAQABAEACAkQBADs=';
		if (img.srcset) {
			img.dataset['srcset'] = img.srcset;
			img.srcset = '';
		}
		img.style.opacity = 0;
		const h = img.getAttribute('height');
		if (h) img.style.minHeight = h + 'px';
	}

	function show(img, immediately = false) {
		if (img.dataset.srcset) {
			img.srcset = img.dataset.srcset;
			img.dataset.srcset = '';
		}
		img.src = img.dataset.src;
		img.dataset.src = '';
		img.style.minHeight = '';
		if (immediately) {
			img.style.opacity = '';
		} else {
			setTimeout(function () {img.style.opacity = '';}, 200);
		}
	}

	function elementTopOnWindow(elm) {
		let top = 0;
		while (elm) {
			top += elm.offsetTop;
			elm = elm.offsetParent;
		}
		return top;
	}

	function doBeforePrint(func, forceMediaCheck = true) {
		window.addEventListener('beforeprint', func, false);
		if (forceMediaCheck || !('onbeforeprint' in window)) {
			if (window.matchMedia) {
				let mediaQueryList = window.matchMedia('print');
				mediaQueryList.addListener(function (mql) {
					if (mql.matches) func();
				});
			}
		}
	}

});
<|endoftext|>


<commit_before>import 'expose?$!expose?jQuery!jquery/dist/jquery.min.js';
import 'expose?Vue!vue/dist/vue.min.js'; // Can't just import Vue from 'vue' because of async dependencies
import VueI18n from 'vue-i18n';

import RR from './rr';
import RRLocales from './i18n/locales.js';
import { extractors as pageDataExtractor } from './sites/index';
import { streetNamePredicate, addStyles, getNoiseLevelAsText } from './utils';
import { loadParkingZones, loadNoise, loadAirPollution, loadTags, loadLocation } from './services/api';
import { getPOIs } from './services/storage';

import '../css/cssnormalize.scss';
import '../css/panel.scss';
import panelTemplate from 'html!../templates/panel.html';

import { App } from './components/App';
import { AvailabilityComponent } from './components/Availability';

RR.logInfo('contentscript loaded');

chrome.runtime.sendMessage({ 'switchIconOn': true });

const initVueTranslations = () => {
  RR.logDebug('Initializing translations');
  chrome.i18n.getAcceptLanguages(languages => {
    const [appLanguage] = languages;
    RR.logDebug('Detected accepted languages: ', languages);
    RR.logInfo('Selected app language: ', appLanguage);
    Vue.use(VueI18n);
    Vue.config.lang = appLanguage;
    Vue.config.fallbackLang = 'en';

    Object.keys(RRLocales).forEach(function (lang) {
      RR.logDebug('RRLocales key: ', lang, '. Localization bundle: ', RRLocales[lang]);
      Vue.locale(lang, RRLocales[lang]);
    });
  });
};

const loadPanel = function(address) {
  RR.logDebug('Injecting panel (template) to page');
  $('body').append(panelTemplate);
  // html from panel.html is just vue.js template so let's render it

  RR.logDebug('Initializing view (replacing values in panel.html template)');

  initVueTranslations();
  Vue.config.devtools = true; // does not work in extension
  Vue.config.silent = false;
  Vue.filter('street-name', streetNamePredicate);
  Vue.directive('focus', {
    inserted(element) {
      element.focus();
    },
    update: function(element) {
      element.focus();
    }
  });
  Vue.component('availibility-component', AvailabilityComponent);

  const vueApp = new Vue(App);
  vueApp.$data.address = address;
  vueApp.$data.details.price.perSquareMeter = pageDataExtractor.getPrices(window.location.host);

  // populate vueApp here with Data
  getPOIs()
    .then(pois => { vueApp.$data.pois = pois; }) // must be in curly braces because of sideEffect
    .catch(err => console.error('An error occurred during POI load from storage' + err.message));

  loadLocation()
    .then(({ results }) => {
      const location = results[0].geometry.location;
      RR.logDebug('geocoding api response: ', location);

      loadNoise(location, 'day')
        .then((result) => {
          RR.logDebug('Noise during the day response: ', result);
          vueApp.$data.noiseLevel.day = Vue.t(getNoiseLevelAsText(result));
        });

      loadNoise(location, 'night')
        .then((result) => {
          RR.logDebug('Noise during the night response: ', result);
          vueApp.$data.noiseLevel.night = Vue.t(getNoiseLevelAsText(result));
        });

      loadAirPollution(location)
        .then((airPollutionApiResult) => {
          RR.logDebug('Air pollution api response: ', airPollutionApiResult);
          // Definice: Klasifikace klimatologické charakteristiky
          // 1 = velmi dobrá 2 = dobrá 3 = přijatelná 4 = zhoršená 5 = špatná
          vueApp.$data.airQuality = Vue.t('pollution.value.val' + airPollutionApiResult.value);
        });

      // TODO vire: map to array of promises and resolve at once
      // tags
      loadTags('night_club', location, 500, 2, vueApp);
      loadTags('transit_station', location, 400, 3, vueApp);
      loadTags('park', location, 600, 0, vueApp);
      loadTags('school', location, 1000, 2, vueApp);
      loadTags('restaurant', location, 500, 3, vueApp);

      loadParkingZones(location, 1000)
        .then(zones => {
          if (zones.length > 0) {
            /*
             Description of type values  see on the very end of the page
             http://www.geoportalpraha.cz/cs/fulltext_geoportal?id=BBDE6394B0E14E8BA656DD69CA2EB0F8#.V_Da1HV97eR
             */
            const closeBlueZones = zones.filter(pz => {
              return pz.dist <= 100 /*m*/ && pz.type === 'M';
              /* Modra  blue zone = parking only for residents */
            });
            if (closeBlueZones.length > 0) {
              vueApp.tags += '' +
                Vue.t('tags.resident_parking.title') + '';

              if (zones.filter(pz => pz.dist < 600 && pz.type !== 'M').length > 0) {
                vueApp.tags += '' +
                  Vue.t('tags.paid_parking.title') + '';
              }
            }
          }
        }); // parking zones
    }); // geoCode
}; // loadPanel

let addressOfProperty;
function initApp() {
  RR.logInfo('Initializing app widget');
  addressOfProperty = pageDataExtractor.getAddress(window.location.host);
  RR.logDebug('Address parsed: ', addressOfProperty);

  if (RR.String.isNotBlank(addressOfProperty)) {
    addStyles();
    loadPanel(addressOfProperty);
  } else {
    RR.logError('Cannot obtain address of property. URL:', window.location);
  }

  pollAddress();
}

let pollAddressTimerId;
function pollAddress() {
  //RR.logDebug('Polling address...'); // you can filter it out in console with regexp filter ^(?=.*?\b.*\b)((?!Poll).)*$ (match all except lines with 'Poll' match)
  const currentAddressOfProperty = pageDataExtractor.getAddress(window.location.host);
  //RR.logDebug('Polled address:', currentAddressOfProperty);
  if (currentAddressOfProperty !== addressOfProperty) {
    $(document).trigger(RR.ADDRESS_CHANGED_EVENT);
    clearTimeout(pollAddressTimerId);
  }
  pollAddressTimerId = setTimeout(pollAddress, 500);
}

$(document).on(RR.ADDRESS_CHANGED_EVENT, (event) => {
  RR.logDebug('Address change in page detected.');
  RR.logDebug('Removing widget');
  $('.reality-panel').remove(); // TODO replace w/ proper teardown & destroy mechanism
  initApp();
});

initApp();
<commit_msg>fix not working loadLocation<commit_after>import 'expose?$!expose?jQuery!jquery/dist/jquery.min.js';
import 'expose?Vue!vue/dist/vue.min.js'; // Can't just import Vue from 'vue' because of async dependencies
import VueI18n from 'vue-i18n';

import RR from './rr';
import RRLocales from './i18n/locales.js';
import { extractors as pageDataExtractor } from './sites/index';
import { streetNamePredicate, addStyles, getNoiseLevelAsText } from './utils';
import { loadParkingZones, loadNoise, loadAirPollution, loadTags, loadLocation } from './services/api';
import { getPOIs } from './services/storage';

import '../css/cssnormalize.scss';
import '../css/panel.scss';
import panelTemplate from 'html!../templates/panel.html';

import { App } from './components/App';
import { AvailabilityComponent } from './components/Availability';

RR.logInfo('contentscript loaded');

chrome.runtime.sendMessage({ 'switchIconOn': true });

const initVueTranslations = () => {
  RR.logDebug('Initializing translations');
  chrome.i18n.getAcceptLanguages(languages => {
    const [appLanguage] = languages;
    RR.logDebug('Detected accepted languages: ', languages);
    RR.logInfo('Selected app language: ', appLanguage);
    Vue.use(VueI18n);
    Vue.config.lang = appLanguage;
    Vue.config.fallbackLang = 'en';

    Object.keys(RRLocales).forEach(function (lang) {
      RR.logDebug('RRLocales key: ', lang, '. Localization bundle: ', RRLocales[lang]);
      Vue.locale(lang, RRLocales[lang]);
    });
  });
};

const loadPanel = function(address) {
  RR.logDebug('Injecting panel (template) to page');
  $('body').append(panelTemplate);
  // html from panel.html is just vue.js template so let's render it

  RR.logDebug('Initializing view (replacing values in panel.html template)');

  initVueTranslations();
  Vue.config.devtools = true; // does not work in extension
  Vue.config.silent = false;
  Vue.filter('street-name', streetNamePredicate);
  Vue.directive('focus', {
    inserted(element) {
      element.focus();
    },
    update: function(element) {
      element.focus();
    }
  });
  Vue.component('availibility-component', AvailabilityComponent);

  const vueApp = new Vue(App);
  vueApp.$data.address = address;
  vueApp.$data.details.price.perSquareMeter = pageDataExtractor.getPrices(window.location.host);

  // populate vueApp here with Data
  getPOIs()
    .then(pois => { vueApp.$data.pois = pois; }) // must be in curly braces because of sideEffect
    .catch(err => console.error('An error occurred during POI load from storage' + err.message));

  loadLocation(address)
    .then(({ results }) => {
      const location = results[0].geometry.location;
      RR.logDebug('geocoding api response: ', location);

      loadNoise(location, 'day')
        .then((result) => {
          RR.logDebug('Noise during the day response: ', result);
          vueApp.$data.noiseLevel.day = Vue.t(getNoiseLevelAsText(result));
        });

      loadNoise(location, 'night')
        .then((result) => {
          RR.logDebug('Noise during the night response: ', result);
          vueApp.$data.noiseLevel.night = Vue.t(getNoiseLevelAsText(result));
        });

      loadAirPollution(location)
        .then((airPollutionApiResult) => {
          RR.logDebug('Air pollution api response: ', airPollutionApiResult);
          // Definice: Klasifikace klimatologické charakteristiky
          // 1 = velmi dobrá 2 = dobrá 3 = přijatelná 4 = zhoršená 5 = špatná
          vueApp.$data.airQuality = Vue.t('pollution.value.val' + airPollutionApiResult.value);
        });

      // TODO vire: map to array of promises and resolve at once
      // tags
      loadTags('night_club', location, 500, 2, vueApp);
      loadTags('transit_station', location, 400, 3, vueApp);
      loadTags('park', location, 600, 0, vueApp);
      loadTags('school', location, 1000, 2, vueApp);
      loadTags('restaurant', location, 500, 3, vueApp);

      loadParkingZones(location, 1000)
        .then(zones => {
          if (zones.length > 0) {
            /*
             Description of type values  see on the very end of the page
             http://www.geoportalpraha.cz/cs/fulltext_geoportal?id=BBDE6394B0E14E8BA656DD69CA2EB0F8#.V_Da1HV97eR
             */
            const closeBlueZones = zones.filter(pz => {
              return pz.dist <= 100 /*m*/ && pz.type === 'M';
              /* Modra  blue zone = parking only for residents */
            });
            if (closeBlueZones.length > 0) {
              vueApp.tags += '' +
                Vue.t('tags.resident_parking.title') + '';

              if (zones.filter(pz => pz.dist < 600 && pz.type !== 'M').length > 0) {
                vueApp.tags += '' +
                  Vue.t('tags.paid_parking.title') + '';
              }
            }
          }
        }); // parking zones
    }); // geoCode
}; // loadPanel

let addressOfProperty;
function initApp() {
  RR.logInfo('Initializing app widget');
  addressOfProperty = pageDataExtractor.getAddress(window.location.host);
  RR.logDebug('Address parsed: ', addressOfProperty);

  if (RR.String.isNotBlank(addressOfProperty)) {
    addStyles();
    loadPanel(addressOfProperty);
  } else {
    RR.logError('Cannot obtain address of property. URL:', window.location);
  }

  pollAddress();
}

let pollAddressTimerId;
function pollAddress() {
  //RR.logDebug('Polling address...'); // you can filter it out in console with regexp filter ^(?=.*?\b.*\b)((?!Poll).)*$ (match all except lines with 'Poll' match)
  const currentAddressOfProperty = pageDataExtractor.getAddress(window.location.host);
  //RR.logDebug('Polled address:', currentAddressOfProperty);
  if (currentAddressOfProperty !== addressOfProperty) {
    $(document).trigger(RR.ADDRESS_CHANGED_EVENT);
    clearTimeout(pollAddressTimerId);
  }
  pollAddressTimerId = setTimeout(pollAddress, 500);
}

$(document).on(RR.ADDRESS_CHANGED_EVENT, (event) => {
  RR.logDebug('Address change in page detected.');
  RR.logDebug('Removing widget');
  $('.reality-panel').remove(); // TODO replace w/ proper teardown & destroy mechanism
  initApp();
});

initApp();
<|endoftext|>


<commit_before>var URLHelper = require('./url-helper');
var _ = require('underscore');

function Dashboard (dashboard) {
  this._dashboard = dashboard;
}

Dashboard.prototype = {

  /**
   * @return {View} used in the dashboard
   */
  getView: function () {
    return this._dashboard.dashboardView;
  },

  /**
   * @return {Map} the map used in the dashboard
   */
  getMap: function () {
    return this._dashboard.vis;
  },

  /**
   * @return {Array} of widgets in the dashboard
   */
  getWidgets: function () {
    return this._dashboard.widgets.getList();
  },

  getDashboardURL: function () {
    return URLHelper.getURLFromState(this.getState());
  },

  getState: function () {
    var state = {};
    var mapState = this.getMapState(); // TODO
    if (!_.isEmpty(mapState)) state.map = mapState;
    /*
     * TODO: Disabled widget states until issues are fixed.
     * See https://github.com/CartoDB/deep-insights.js/issues/416
     */
    var widgetsState = this._dashboard.widgets._widgetsCollection.getStates();
    if (!_.isEmpty(widgetsState)) state.widgets = widgetsState;
    return state;
  },

  getMapState: function () {
    var initialState = this._dashboard.dashboardView.getInitialMapState();
    var currentCenter = this._dashboard.vis.map.get('center');
    var currentZoom = this._dashboard.vis.map.getZoom();
    var upperLat = initialState.center[0] * 0.01;
    var upperLon = initialState.center[1] * 0.01;
    var inside = (Math.abs(initialState.center[0] - currentCenter[0]) < upperLat) && (Math.abs(initialState.center[1] - currentCenter[1]) < upperLon);
    if (inside && _.isEqual(currentZoom, initialState.zoom)) {
      return {};
    } else {
      return {
        center: currentCenter,
        zoom: currentZoom
      };
    }
  },

  setState: function (state) {
    // todo: set map state
    this._dashboard.widgets.setWidgetsState(state.widgets);
    this._dashboard.vis.map.setView(state.map.center, state.map.zoom);
  },

  onStateChanged: function (callback) {
    /*
     * TODO: Disabled widget states until issues are fixed.
     * See https://github.com/CartoDB/deep-insights.js/issues/416
     */
    this._dashboard.widgets._widgetsCollection.bind('change', function () {
      callback(this.getState(), this.getDashboardURL());
    }, this);

    this._dashboard.vis.map.bind('change', function () {
      callback(this.getState(), this.getDashboardURL());
    }, this);
  },

  /**
   * @param {Integer} id - widget id
   * @return a widget object
   */
  getWidget: function (id) {
    return this._dashboard.widgets.get(id);
  },

  /**
   * Create a category widget.
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {CategoryWidget} The new widget
   */
  createCategoryWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createCategoryModel(widgetAttrs, layer);
  },

  /**
   * Create a histogram widget
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {HistogramWidget} The new widget
   */
  createHistogramWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createHistogramModel(widgetAttrs, layer);
  },

  /**
   * Create a formula widget
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {FormulaWidget} The new widget
   */
  createFormulaWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createFormulaModel(widgetAttrs, layer);
  },

  /**
   * Create a timesier es widget
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {TimeSeriesWidget} The new widget
   */
  createTimeSeriesWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createTimeSeriesModel(widgetAttrs, layer);
  }

};

module.exports = Dashboard;
<commit_msg>Listen to dataviewsFetched event in order to initialise state.<commit_after>var URLHelper = require('./url-helper');
var _ = require('underscore');

function Dashboard (dashboard) {
  this._dashboard = dashboard;
}

Dashboard.prototype = {

  /**
   * @return {View} used in the dashboard
   */
  getView: function () {
    return this._dashboard.dashboardView;
  },

  /**
   * @return {Map} the map used in the dashboard
   */
  getMap: function () {
    return this._dashboard.vis;
  },

  /**
   * @return {Array} of widgets in the dashboard
   */
  getWidgets: function () {
    return this._dashboard.widgets.getList();
  },

  getDashboardURL: function () {
    return URLHelper.getURLFromState(this.getState());
  },

  getState: function () {
    var state = {};
    var mapState = this.getMapState(); // TODO
    if (!_.isEmpty(mapState)) state.map = mapState;
    /*
     * TODO: Disabled widget states until issues are fixed.
     * See https://github.com/CartoDB/deep-insights.js/issues/416
     */
    var widgetsState = this._dashboard.widgets._widgetsCollection.getStates();
    if (!_.isEmpty(widgetsState)) state.widgets = widgetsState;
    return state;
  },

  getMapState: function () {
    var initialState = this._dashboard.dashboardView.getInitialMapState();
    var currentCenter = this._dashboard.vis.map.get('center');
    var currentZoom = this._dashboard.vis.map.getZoom();
    var upperLat = initialState.center[0] * 0.01;
    var upperLon = initialState.center[1] * 0.01;
    var inside = (Math.abs(initialState.center[0] - currentCenter[0]) < upperLat) && (Math.abs(initialState.center[1] - currentCenter[1]) < upperLon);
    if (inside && _.isEqual(currentZoom, initialState.zoom)) {
      return {};
    } else {
      return {
        center: currentCenter,
        zoom: currentZoom
      };
    }
  },

  setState: function (state) {
    // todo: set map state
    this._dashboard.widgets.setWidgetsState(state.widgets);
    this._dashboard.vis.map.setView(state.map.center, state.map.zoom);
  },

  onStateChanged: function (callback) {
    this._dashboard.vis.once('dataviewsFetched', function () {
      this._bindChange(callback);
    }, this);
  },

  _bindChange: function (callback) {
    this._dashboard.widgets._widgetsCollection.bind('change', function () {
      callback(this.getState(), this.getDashboardURL());
    }, this);

    this._dashboard.vis.map.bind('change', function () {
      callback(this.getState(), this.getDashboardURL());
    }, this);
  },

  /**
   * @param {Integer} id - widget id
   * @return a widget object
   */
  getWidget: function (id) {
    return this._dashboard.widgets.get(id);
  },

  /**
   * Create a category widget.
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {CategoryWidget} The new widget
   */
  createCategoryWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createCategoryModel(widgetAttrs, layer);
  },

  /**
   * Create a histogram widget
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {HistogramWidget} The new widget
   */
  createHistogramWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createHistogramModel(widgetAttrs, layer);
  },

  /**
   * Create a formula widget
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {FormulaWidget} The new widget
   */
  createFormulaWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createFormulaModel(widgetAttrs, layer);
  },

  /**
   * Create a timesier es widget
   * @param {Object} widgetAttrs - attributes for the new widget
   * @param {string} widgetAttrs.id - id (required)
   * @param {string} widgetAttrs.title - title (required)
   * @param {number} widgetAttrs.order - index of the widget (optional)
   * @param ...
   * @return {TimeSeriesWidget} The new widget
   */
  createTimeSeriesWidget: function (widgetAttrs, layer) {
    return this._dashboard.widgets.createTimeSeriesModel(widgetAttrs, layer);
  }

};

module.exports = Dashboard;
<|endoftext|>


<commit_before>import { config } from '../config';
import { parseDocumentsData, parseDocumentsMarkup } from './SlidehubParser';
import { SlidehubDocumentLoader } from './SlidehubDocumentLoader';
import { SlidehubImageLoader } from './SlidehubImageLoader';
import { SlidehubMouseInteraction } from './SlidehubMouseInteraction';
import { SlidehubKeyboardInteraction } from './SlidehubKeyboardInteraction';
import { DocumentNavigator } from './DocumentNavigator';
import { enableModals } from './Modal';

import * as plugin from '../plugins/namespace';

import { debounce } from '../util/debounce';
import { getOuterWidth } from '../util/getOuterWidth';
import { getFragmentIdentifier } from '../util/getFragmentIdentifier';

export { Slidehub };

const selectClassName = 'selected';
const hoverClassName = 'highlighted';

class Slidehub {
  /**
   * @public
   */
  constructor() {
    this._node = null;
    this._documents = null;
    this._selectedDocument = null;
    this._hoveredDocument = null;
    this._documentNavigator = null;

    this._itemWidth = null;
    this._visibleItems = null;
    this._scrollboxWidth = null;

    document.addEventListener('DOMContentLoaded', () => {
      this._node = this.getNode();
      this._documents = this.getDocuments();

      let documentLoader;

      if (!config.staticContent) {
        documentLoader = new SlidehubDocumentLoader(this);
        documentLoader.insertDocumentFrames();
      }

      const targetDoc = this.determineTargetDocument();

      if (!config.staticContent) {
        documentLoader.start(targetDoc);
      }

      this.selectDocument(targetDoc);
      this.jumpToTargetDocument(targetDoc);

      this.start();
      this.loadPlugins();
    });
  }

  /**
   * Sets up the main Slidehub HTML element.
   *
   * @returns {HTMLElement} the Slidehub DOM node.
   * @private
   */
  getNode() {
    const existingNode = document.querySelector(config.selector.slidehub);
    const slidehubNode = existingNode ? existingNode : this.createNode();

    // Expose select/highlight color overrides to the DOM.
    // This allows CSS to use inside of a rule declaration.
    if (config.selectColor && config.selectColor !== '') {
      slidehubNode.style.setProperty('--c-selected', config.selectColor);
    }

    if (config.highlightColor && config.highlightColor !== '') {
      slidehubNode.style.setProperty('--c-highlighted', config.highlightColor);
    }

    return slidehubNode;
  }

  /**
   * Hooks the Slidehub container element into the DOM.
   *
   * Requires an element with a custom attribute `data-slidehub` to be present
   * in the DOM. A new <div> element will be created inside of it. No existing
   * markup will be changed or removed.
   *
   * @returns {HTMLDivElement} the empty Slidehub DOM node.
   * @private
   */
  createNode() {
    const slidehubNode = document.createElement('div');
    slidehubNode.classList.add(config.selector.slidehub.slice(1));

    document.querySelector('[data-slidehub]').appendChild(slidehubNode);

    return slidehubNode;
  }

  /**
   * @returns {ReverseIterableMap} the internal documents data structure.
   */
  getDocuments() {
    return config.staticContent ? parseDocumentsMarkup(this) : parseDocumentsData(this);
  }

  /**
   * @returns {SlidehubDocument}
   */
  determineTargetDocument() {
    const fragmentIdentifier = getFragmentIdentifier(window.location.toString());

    let targetDoc;

    if (this.documents.has(fragmentIdentifier)) {
      targetDoc = this.documents.get(fragmentIdentifier);
    } else if (document.documentElement.scrollTop === 0) {
      // If the viewport was not scrolled already, just start from the top
      targetDoc = this.documents.values().next().value;
    } else {
      // The page was scrolled (e.g. the page was reloaded with a non-zero scroll position)
      // In this case, Slidehub attempts to load the document in the center of the view.
      const slidehubWidth = this.node.clientWidth;
      const centerElement = document.elementFromPoint(slidehubWidth / 2, window.innerHeight / 2);
      const centerDocument = centerElement.closest(config.selector.doc);
      targetDoc = this.documents.get(centerDocument.id);
    }

    return targetDoc;
  }

  jumpToTargetDocument(targetDoc) {
    const fragmentIdentifier = getFragmentIdentifier(window.location.toString());
    if (document.documentElement.scrollTop !== 0 || fragmentIdentifier) {
      const centerOffset = window.innerHeight / 2 - targetDoc.node.clientHeight / 2;
      // After a short while, scroll the viewport to center the document
      // In the future, `Element.scrollIntoView({ block: 'center' })` should work
      setTimeout(() => window.scrollBy(0, centerOffset), 200);
    }
  }

  /**
   * Initializes all core functionality.
   *
   * @private
   */
  start() {
    this.navigateDocument = new DocumentNavigator(this);

    this.exposeDocumentInfo();

    const imageLoader = new SlidehubImageLoader(this);
    imageLoader.start();

    const mouseInteraction = new SlidehubMouseInteraction(this);
    mouseInteraction.start();

    const keyboardInteraction = new SlidehubKeyboardInteraction(this);
    keyboardInteraction.start();

    enableModals();
  }

  /**
   * Loads optional plugins.
   *
   * @private
   */
  loadPlugins() {
    const documentSourceLinker = new plugin.DocumentSourceLinker(this);
    documentSourceLinker.enable();
  }

  /**
   * @returns {HTMLElement} the Slidehub DOM node.
   * @public
   */
  get node() {
    return this._node;
  }

  /**
   * @returns {ReverseIterableMap} the Slidehub documents data structure.
   * @public
   */
  get documents() {
    return this._documents;
  }

  /**
   * @returns {SlidehubDocument} the currently selected document.
   * @public
   */
  get selectedDocument() {
    return this._selectedDocument;
  }

  /**
   * @param {SlidehubDocument} doc the new selected document.
   * @private
   */
  set selectedDocument(doc) {
    this._selectedDocument = doc;
  }

  /**
   * Sets a new selected document.
   *
   * @param {SlidehubDocument} doc
   * @public
   */
  selectDocument(doc) {
    // Remove selected class from currently selected document
    if (this.selectedDocument) {
      this.selectedDocument.node.classList.remove(selectClassName);
    }

    // Set new selected document
    this.selectedDocument = doc;
    this.selectedDocument.node.classList.add(selectClassName);

    if (document.activeElement instanceof HTMLElement) {
      document.activeElement.blur();
    }
  }

  /**
   * @returns {SlidehubDocument} the currently hovered document.
   * @public
   */
  get hoveredDocument() {
    return this._hoveredDocument;
  }

  /**
   * @param {SlidehubDocument} doc the new hovered document.
   * @private
   */
  set hoveredDocument(doc) {
    this._hoveredDocument = doc;
  }

  /**
   * Sets a new hovered document after unsetting the old one.
   *
   * @param {SlidehubDocument} doc the new hovered document.
   * @public
   */
  hoverDocument(doc) {
    this.unhoverDocument();

    // Set new hovered document
    this.hoveredDocument = doc;
    this.hoveredDocument.node.classList.add(hoverClassName);

    if (document.activeElement instanceof HTMLElement) {
      document.activeElement.blur();
    }
  }

  /**
   * Removes the hover from the currently hovered document.
   *
   * **Side effect**: Also removes the hover from the currently hovered item
   * within that document.
   *
   * @public
   */
  unhoverDocument() {
    // Remove hovered class from currently hovered document
    if (this.hoveredDocument) {
      this.hoveredDocument.unhoverItem();
      this.hoveredDocument.node.classList.remove(hoverClassName);
      this.hoveredDocument = null;
    }
  }

  /**
   * @returns {DocumentNavigator} the document navigator object.
   * @public
   */
  get navigateDocument() {
    return this._documentNavigator;
  }

  /**
   * @param {DocumentNavigator} documentNavigator
   * @private
   */
  set navigateDocument(documentNavigator) {
    this._documentNavigator = documentNavigator;
  }

  /**
   * @returns {Number}
   * @public
   */
  get itemWidth() {
    return this._itemWidth;
  }

  /**
   * @param {Number} itemWidth
   * @private
   */
  set itemWidth(itemWidth) {
    this._itemWidth = itemWidth;
  }

  /**
   * @returns {Number}
   * @public
   */
  get visibleItems() {
    return this._visibleItems;
  }

  /**
   * @param {Number} visibleItems
   * @private
   */
  set visibleItems(visibleItems) {
    this._visibleItems = visibleItems;
  }

  /**
   * @returns {Number}
   * @public
   */
  get scrollboxWidth() {
    return this._scrollboxWidth;
  }

  /**
   * @param {Number} scrollboxWidth
   * @private
   */
  set scrollboxWidth(scrollboxWidth) {
    this._scrollboxWidth = scrollboxWidth;
  }

  /**
   * Wrapper method for all expose methods.
   *
   * @private
   */
  exposeDocumentInfo() {
    this.exposeItemWidth();
    this.exposeScrollboxWidth();
    this.exposeNumberOfVisibleItems();

    // Recalculate the scrollbox width on resize.
    window.addEventListener('resize', debounce(() => {
      this.exposeItemWidth();
      this.exposeScrollboxWidth();
      this.exposeNumberOfVisibleItems();
    }, 200));
  }

  /**
   * Exposes the current outer width of an item to the DOM.
   *
   * @private
   */
  exposeItemWidth() {
    const item = this.selectedDocument.node.querySelector(config.selector.item);
    const itemOuterWidth = getOuterWidth(item);

    if (this.itemWidth !== itemOuterWidth) {
      this.itemWidth = itemOuterWidth;

      this.node.style.setProperty('--page-outer-width', this.itemWidth + 'px');
    }
  }

  /**
   * Exposes the current `clientWidth` of the selected scrollbox to the DOM.
   *
   * @private
   */
  exposeScrollboxWidth() {
    const scrollboxNode = this.selectedDocument.node.querySelector(config.selector.scrollbox);

    if (this.scrollboxWidth !== scrollboxNode.clientWidth) {
      this.scrollboxWidth = scrollboxNode.clientWidth;

      this.node.style.setProperty('--scrollbox-width', this.scrollboxWidth + 'px');
    }
  }

  /**
   * Exposes the current number of visible items in a document to the DOM.
   *
   * @private
   */
  exposeNumberOfVisibleItems() {
    this.visibleItems = Math.floor(this.scrollboxWidth / this.itemWidth);
  }
};
<commit_msg>Fix target document jumping going in the wrong direction<commit_after>import { config } from '../config';
import { parseDocumentsData, parseDocumentsMarkup } from './SlidehubParser';
import { SlidehubDocumentLoader } from './SlidehubDocumentLoader';
import { SlidehubImageLoader } from './SlidehubImageLoader';
import { SlidehubMouseInteraction } from './SlidehubMouseInteraction';
import { SlidehubKeyboardInteraction } from './SlidehubKeyboardInteraction';
import { DocumentNavigator } from './DocumentNavigator';
import { enableModals } from './Modal';

import * as plugin from '../plugins/namespace';

import { debounce } from '../util/debounce';
import { getOuterWidth } from '../util/getOuterWidth';
import { getFragmentIdentifier } from '../util/getFragmentIdentifier';

export { Slidehub };

const selectClassName = 'selected';
const hoverClassName = 'highlighted';

class Slidehub {
  /**
   * @public
   */
  constructor() {
    this._node = null;
    this._documents = null;
    this._selectedDocument = null;
    this._hoveredDocument = null;
    this._documentNavigator = null;

    this._itemWidth = null;
    this._visibleItems = null;
    this._scrollboxWidth = null;

    document.addEventListener('DOMContentLoaded', () => {
      this._node = this.getNode();
      this._documents = this.getDocuments();

      let documentLoader;

      if (!config.staticContent) {
        documentLoader = new SlidehubDocumentLoader(this);
        documentLoader.insertDocumentFrames();
      }

      const targetDoc = this.determineTargetDocument();

      if (!config.staticContent) {
        documentLoader.start(targetDoc);
      }

      this.selectDocument(targetDoc);
      this.jumpToTargetDocument(targetDoc);

      this.start();
      this.loadPlugins();
    });
  }

  /**
   * Sets up the main Slidehub HTML element.
   *
   * @returns {HTMLElement} the Slidehub DOM node.
   * @private
   */
  getNode() {
    const existingNode = document.querySelector(config.selector.slidehub);
    const slidehubNode = existingNode ? existingNode : this.createNode();

    // Expose select/highlight color overrides to the DOM.
    // This allows CSS to use inside of a rule declaration.
    if (config.selectColor && config.selectColor !== '') {
      slidehubNode.style.setProperty('--c-selected', config.selectColor);
    }

    if (config.highlightColor && config.highlightColor !== '') {
      slidehubNode.style.setProperty('--c-highlighted', config.highlightColor);
    }

    return slidehubNode;
  }

  /**
   * Hooks the Slidehub container element into the DOM.
   *
   * Requires an element with a custom attribute `data-slidehub` to be present
   * in the DOM. A new <div> element will be created inside of it. No existing
   * markup will be changed or removed.
   *
   * @returns {HTMLDivElement} the empty Slidehub DOM node.
   * @private
   */
  createNode() {
    const slidehubNode = document.createElement('div');
    slidehubNode.classList.add(config.selector.slidehub.slice(1));

    document.querySelector('[data-slidehub]').appendChild(slidehubNode);

    return slidehubNode;
  }

  /**
   * @returns {ReverseIterableMap} the internal documents data structure.
   */
  getDocuments() {
    return config.staticContent ? parseDocumentsMarkup(this) : parseDocumentsData(this);
  }

  /**
   * @returns {SlidehubDocument}
   */
  determineTargetDocument() {
    const fragmentIdentifier = getFragmentIdentifier(window.location.toString());

    let targetDoc;

    if (this.documents.has(fragmentIdentifier)) {
      targetDoc = this.documents.get(fragmentIdentifier);
    } else if (document.documentElement.scrollTop === 0) {
      // If the viewport was not scrolled already, just start from the top
      targetDoc = this.documents.values().next().value;
    } else {
      // The page was scrolled (e.g. the page was reloaded with a non-zero scroll position)
      // In this case, Slidehub attempts to load the document in the center of the view.
      const slidehubWidth = this.node.clientWidth;
      const centerElement = document.elementFromPoint(slidehubWidth / 2, window.innerHeight / 2);
      const centerDocument = centerElement.closest(config.selector.doc);
      targetDoc = this.documents.get(centerDocument.id);
    }

    return targetDoc;
  }

  jumpToTargetDocument(targetDoc) {
    const fragmentIdentifier = getFragmentIdentifier(window.location.toString());
    if (document.documentElement.scrollTop !== 0 || fragmentIdentifier) {
      const centerOffset = (window.innerHeight - targetDoc.node.clientHeight) / 2;
      // After a short while, scroll the viewport to center the document
      // In the future, `Element.scrollIntoView({ block: 'center' })` should work
      setTimeout(() => window.scrollBy(0, -centerOffset), 200);
    }
  }

  /**
   * Initializes all core functionality.
   *
   * @private
   */
  start() {
    this.navigateDocument = new DocumentNavigator(this);

    this.exposeDocumentInfo();

    const imageLoader = new SlidehubImageLoader(this);
    imageLoader.start();

    const mouseInteraction = new SlidehubMouseInteraction(this);
    mouseInteraction.start();

    const keyboardInteraction = new SlidehubKeyboardInteraction(this);
    keyboardInteraction.start();

    enableModals();
  }

  /**
   * Loads optional plugins.
   *
   * @private
   */
  loadPlugins() {
    const documentSourceLinker = new plugin.DocumentSourceLinker(this);
    documentSourceLinker.enable();
  }

  /**
   * @returns {HTMLElement} the Slidehub DOM node.
   * @public
   */
  get node() {
    return this._node;
  }

  /**
   * @returns {ReverseIterableMap} the Slidehub documents data structure.
   * @public
   */
  get documents() {
    return this._documents;
  }

  /**
   * @returns {SlidehubDocument} the currently selected document.
   * @public
   */
  get selectedDocument() {
    return this._selectedDocument;
  }

  /**
   * @param {SlidehubDocument} doc the new selected document.
   * @private
   */
  set selectedDocument(doc) {
    this._selectedDocument = doc;
  }

  /**
   * Sets a new selected document.
   *
   * @param {SlidehubDocument} doc
   * @public
   */
  selectDocument(doc) {
    // Remove selected class from currently selected document
    if (this.selectedDocument) {
      this.selectedDocument.node.classList.remove(selectClassName);
    }

    // Set new selected document
    this.selectedDocument = doc;
    this.selectedDocument.node.classList.add(selectClassName);

    if (document.activeElement instanceof HTMLElement) {
      document.activeElement.blur();
    }
  }

  /**
   * @returns {SlidehubDocument} the currently hovered document.
   * @public
   */
  get hoveredDocument() {
    return this._hoveredDocument;
  }

  /**
   * @param {SlidehubDocument} doc the new hovered document.
   * @private
   */
  set hoveredDocument(doc) {
    this._hoveredDocument = doc;
  }

  /**
   * Sets a new hovered document after unsetting the old one.
   *
   * @param {SlidehubDocument} doc the new hovered document.
   * @public
   */
  hoverDocument(doc) {
    this.unhoverDocument();

    // Set new hovered document
    this.hoveredDocument = doc;
    this.hoveredDocument.node.classList.add(hoverClassName);

    if (document.activeElement instanceof HTMLElement) {
      document.activeElement.blur();
    }
  }

  /**
   * Removes the hover from the currently hovered document.
   *
   * **Side effect**: Also removes the hover from the currently hovered item
   * within that document.
   *
   * @public
   */
  unhoverDocument() {
    // Remove hovered class from currently hovered document
    if (this.hoveredDocument) {
      this.hoveredDocument.unhoverItem();
      this.hoveredDocument.node.classList.remove(hoverClassName);
      this.hoveredDocument = null;
    }
  }

  /**
   * @returns {DocumentNavigator} the document navigator object.
   * @public
   */
  get navigateDocument() {
    return this._documentNavigator;
  }

  /**
   * @param {DocumentNavigator} documentNavigator
   * @private
   */
  set navigateDocument(documentNavigator) {
    this._documentNavigator = documentNavigator;
  }

  /**
   * @returns {Number}
   * @public
   */
  get itemWidth() {
    return this._itemWidth;
  }

  /**
   * @param {Number} itemWidth
   * @private
   */
  set itemWidth(itemWidth) {
    this._itemWidth = itemWidth;
  }

  /**
   * @returns {Number}
   * @public
   */
  get visibleItems() {
    return this._visibleItems;
  }

  /**
   * @param {Number} visibleItems
   * @private
   */
  set visibleItems(visibleItems) {
    this._visibleItems = visibleItems;
  }

  /**
   * @returns {Number}
   * @public
   */
  get scrollboxWidth() {
    return this._scrollboxWidth;
  }

  /**
   * @param {Number} scrollboxWidth
   * @private
   */
  set scrollboxWidth(scrollboxWidth) {
    this._scrollboxWidth = scrollboxWidth;
  }

  /**
   * Wrapper method for all expose methods.
   *
   * @private
   */
  exposeDocumentInfo() {
    this.exposeItemWidth();
    this.exposeScrollboxWidth();
    this.exposeNumberOfVisibleItems();

    // Recalculate the scrollbox width on resize.
    window.addEventListener('resize', debounce(() => {
      this.exposeItemWidth();
      this.exposeScrollboxWidth();
      this.exposeNumberOfVisibleItems();
    }, 200));
  }

  /**
   * Exposes the current outer width of an item to the DOM.
   *
   * @private
   */
  exposeItemWidth() {
    const item = this.selectedDocument.node.querySelector(config.selector.item);
    const itemOuterWidth = getOuterWidth(item);

    if (this.itemWidth !== itemOuterWidth) {
      this.itemWidth = itemOuterWidth;

      this.node.style.setProperty('--page-outer-width', this.itemWidth + 'px');
    }
  }

  /**
   * Exposes the current `clientWidth` of the selected scrollbox to the DOM.
   *
   * @private
   */
  exposeScrollboxWidth() {
    const scrollboxNode = this.selectedDocument.node.querySelector(config.selector.scrollbox);

    if (this.scrollboxWidth !== scrollboxNode.clientWidth) {
      this.scrollboxWidth = scrollboxNode.clientWidth;

      this.node.style.setProperty('--scrollbox-width', this.scrollboxWidth + 'px');
    }
  }

  /**
   * Exposes the current number of visible items in a document to the DOM.
   *
   * @private
   */
  exposeNumberOfVisibleItems() {
    this.visibleItems = Math.floor(this.scrollboxWidth / this.itemWidth);
  }
};
<|endoftext|>


<commit_before>/**
 * util-events.js - The minimal events support
 */

var events = data.events = {}

// Bind event
seajs.on = function(name, callback) {
  var list = events[name] || (events[name] = [])
  list.push(callback)
  return seajs
}

// Remove event. If `callback` is undefined, remove all callbacks for the
// event. If `event` and `callback` are both undefined, remove all callbacks
// for all events
seajs.off = function(name, callback) {
  // Remove *all* events
  if (!(name || callback)) {
    for (var prop in events) {
      delete events[prop]
    }
    return seajs
  }

  var list = events[name]
  if (list) {
    if (callback) {
      for (var i = list.length - 1; i >= 0; i--) {
        if (list[i] === callback) {
          list.splice(i, 1)
        }
      }
    }
    else {
      delete events[name]
    }
  }

  return seajs
}

// Emit event, firing all bound callbacks. Callbacks are passed the same
// arguments as `emit` is, apart from the event name
var emit = seajs.emit = function(name, data) {
  var list = events[name], fn

  if (list) {
    // Copy callback lists to prevent modification
    list = list.slice()

    // Execute event callbacks
    while ((fn = list.shift())) {
      fn(data)
    }
  }

  return seajs
}

<commit_msg>Simplify events cache empty<commit_after>/**
 * util-events.js - The minimal events support
 */

var events = data.events = {}

// Bind event
seajs.on = function(name, callback) {
  var list = events[name] || (events[name] = [])
  list.push(callback)
  return seajs
}

// Remove event. If `callback` is undefined, remove all callbacks for the
// event. If `event` and `callback` are both undefined, remove all callbacks
// for all events
seajs.off = function(name, callback) {
  // Remove *all* events
  if (!(name || callback)) {
    events = data.events = {}
    return seajs
  }

  var list = events[name]
  if (list) {
    if (callback) {
      for (var i = list.length - 1; i >= 0; i--) {
        if (list[i] === callback) {
          list.splice(i, 1)
        }
      }
    }
    else {
      delete events[name]
    }
  }

  return seajs
}

// Emit event, firing all bound callbacks. Callbacks are passed the same
// arguments as `emit` is, apart from the event name
var emit = seajs.emit = function(name, data) {
  var list = events[name], fn

  if (list) {
    // Copy callback lists to prevent modification
    list = list.slice()

    // Execute event callbacks
    while ((fn = list.shift())) {
      fn(data)
    }
  }

  return seajs
}

<|endoftext|>


<commit_before>angular.module('project.home', [
    'ui.router'
])

    .config(function config($stateProvider) {
        $stateProvider.state('home', {
            url: '/home',
            controller: 'HomeCtrl',
            templateUrl: 'home/home.tpl.html',
            data: {pageTitle: 'Home'},
            requireLogin: false
        });
    })
    .controller('HomeCtrl', ['$rootScope', '$scope', '$state', '$q', 'HomeService', 'P_ConstantsService', 'P_UtilsService',
        function ($rootScope, $scope, $state, $q, HomeService, P_ConstantsService, P_UtilsService) {
            //Bubble Chart
            var deferred = $q.defer();
            var bubbleChartPromise = deferred.promise;
            bubbleChartPromise = HomeService.getDeviceUserComments();
            bubbleChartPromise
                .then(function (data) {
                    if (data) {
                        if (!P_UtilsService.isObjectEmpty(data)) {
                            //Construct Data for Bubble Chart
                            var resObj = {};
                            resObj.name = P_ConstantsService.COMMENTS;
                            var tempArr = [];
                            angular.forEach(data, function (value, key) {
                                var tempObj = {};
                                tempObj.name = value.deviceKey;
                                tempObj.size = value.userTalkedCount;
                                tempArr.push(tempObj);
                            });
                            resObj.children = tempArr;
                            constructConnectionMonitoringChart(resObj);
                        }
                    }
                },
                function (error) {
                    console.log(error);
                },
                function (progress) {
                });

            var constructConnectionMonitoringChart = function (data) {
                var diameter = 460,
                    format = d3.format(",d"),
                    color = d3.scale.category20c();

                var bubble = d3.layout.pack()
                    .sort(null)
                    .size([diameter, diameter])
                    .padding(1.5);

                var svg = d3.select("body").append("svg")
                    .attr("width", diameter)
                    .attr("height", diameter)
                    .attr("class", "bubble");

                d3.json("data", function (error, root) {
                    /*if (error) {
                     throw error;
                     }*/
                    root = data;
                    var node = svg.selectAll(".node")
                        .data(bubble.nodes(classes(root))
                            .filter(function (d) {
                                return !d.children;
                            }))
                        .enter().append("g")
                        .attr("class", "node")
                        .attr("transform", function (d) {
                            return "translate(" + d.x + "," + d.y + ")";
                        });

                    node.append("title")
                        .text(function (d) {
                            return d.className + ": " + format(d.value);
                        });

                    node.append("circle")
                        .attr("r", function (d) {
                            return d.r;
                        })
                        .style("fill", function (d) {
                            return color(d.packageName);
                        });

                    node.append("text")
                        .attr("dy", ".3em")
                        .style("text-anchor", "middle")
                        .text(function (d) {
                            return d.className.substring(0, d.r / 3);
                        });

                    node.on("click", function (d) {
                        alert(d);
                    });
                });

                // Returns a flattened hierarchy containing all leaf nodes under the root.
                function classes(root) {
                    var classes1 = [];

                    function recurse(name, node) {
                        if (node.children) {
                            node.children.forEach(function (child) {
                                recurse(node.name, child);
                            });
                        }
                        else {
                            classes1.push({packageName: node.size, className: node.name, value: node.size});
                        }
                    }

                    recurse(null, root);
                    return {children: classes1};
                }

                d3.select(self.frameElement).style("height", diameter + "px");
            };
        }]);

<commit_msg>Fixed onclick issue.<commit_after>angular.module('project.home', [
    'ui.router'
])

    .config(function config($stateProvider) {
        $stateProvider.state('home', {
            url: '/home',
            controller: 'HomeCtrl',
            templateUrl: 'home/home.tpl.html',
            data: {pageTitle: 'Home'},
            requireLogin: false
        });
    })
    .controller('HomeCtrl', ['$rootScope', '$scope', '$state', '$q', 'HomeService', 'P_ConstantsService', 'P_UtilsService',
        function ($rootScope, $scope, $state, $q, HomeService, P_ConstantsService, P_UtilsService) {
            //Bubble Chart
            var deferred = $q.defer();
            var bubbleChartPromise = deferred.promise;
            bubbleChartPromise = HomeService.getDeviceUserComments();
            bubbleChartPromise
                .then(function (data) {
                    if (data) {
                        if (!P_UtilsService.isObjectEmpty(data)) {
                            //Construct Data for Bubble Chart
                            var resObj = {};
                            resObj.name = P_ConstantsService.COMMENTS;
                            var tempArr = [];
                            angular.forEach(data, function (value, key) {
                                var tempObj = {};
                                tempObj.name = value.deviceKey;
                                tempObj.size = value.userTalkedCount;
                                tempArr.push(tempObj);
                            });
                            resObj.children = tempArr;
                            constructConnectionMonitoringChart(resObj);
                        }
                    }
                },
                function (error) {
                    console.log(error);
                },
                function (progress) {
                });

            var constructConnectionMonitoringChart = function (data) {
                var diameter = 460,
                    format = d3.format(",d"),
                    color = d3.scale.category20c();

                var bubble = d3.layout.pack()
                    .sort(null)
                    .size([diameter, diameter])
                    .padding(1.5);

                var svg = d3.select("#bubbles").append("svg")
                    .attr("width", diameter)
                    .attr("height", diameter)
                    .attr("class", "bubble");

                d3.json("data", function (error, root) {
                    /*if (error) {
                     throw error;
                     }*/
                    root = data;
                    var node = svg.selectAll(".node")
                        .data(bubble.nodes(flatten(root))
                            .filter(function (d) {
                                return !d.children;
                            }))
                        .enter().append("g")
                        .attr("class", "node")
                        .attr("transform", function (d) {
                            return "translate(" + d.x + "," + d.y + ")";
                        });

                    node.append("title")
                        .text(function (d) {
                            return d.className + ": " + format(d.value);
                        });

                    node.append("circle")
                        .attr("r", function (d) {
                            return d.r;
                        })
                        .style("fill", function (d) {
                            return color(d.packageName);
                        });

                    node.append("text")
                        .attr("dy", ".3em")
                        .style("text-anchor", "middle")
                        .attr("cursor", "pointer")
                        .text(function (d) {
                            return d.className.substring(0, d.r / 3);
                        });

                    node.on("click", function (d) {
                        console.log(d);
                    });
                });

                // Returns a flattened hierarchy containing all leaf nodes under the root.
                function flatten(root) {
                    var nodes = [];

                    function recurse(node) {
                        if (node.children) {
                            node.children.forEach(recurse);
                        }
                        else {
                            nodes.push({packageName: node.size, className: node.name, value: node.size});
                        }
                    }

                    recurse(root);
                    return {children: nodes};
                }

                d3.select(self.frameElement).style("height", diameter + "px");
            };
        }]);

<|endoftext|>