<commit_before>// --------------------------------------------------
// Add file preview to selected images
// --------------------------------------------------
define(function (require) {

	// Dependencies
	var $ = require('jquery'),
		_ = require('underscore'),
		Backbone = require('backbone');
	  require('jcrop');
	  require('imagesloaded');

	// Define a backbone view for each image
	var Crop = Backbone.View.extend({

		// Instance vars
		jcrop: null, // A jcrop API instance
		activeCrop: false,
		width: null,
		height: null,
		ratio: undefined,
		initted: false,
		$input: null, // The hidden field that stores the output

		// Constructor
		initialize: function() {
			_.bindAll(this);

			// Cache selectors
			this.$upload = this.$el.closest('.image-upload');
			this.$crop = this.$upload.find('.input-crop_box');
			this.$focus = this.$upload.find('.input-focal_point');
			this.$title = this.$upload.find('input.title');
			this.$cropTool = this.$upload.find('.crop.btn');
			this.$focusTool = this.$upload.find('.focal.btn');
			this.$file = this.$upload.find('[type="file"]');

			// Remove clicking on the parent a tag
			this.$el.parent('a').click(function(e) { e.preventDefault(); });

			// Cache configruation variables
			var ratio = this.$upload.data('aspect-ratio');
			this.ratio = ratio;

			// Listen for window resizing as a way to check whether the img has been resized
			// since it resizes responsively.  We listen on the leading edge for the start
			// and the tailing edge for the end
			var $window = $(window), delay = 400;
			$window.resize(_.debounce(this.destroy, delay, true));
			$window.resize(_.debounce(this.init, delay, false));

			this.$cropTool.on('click', this.beginCrop);
			this.$focusTool.on('click', this.beginFocus);

			// Start jcrop up once the images loaded
			this.$el.imagesLoaded(this.init);

		},

		// Events
		events: {
			'active': 'activate' // This image has now been activated
		},

		// Activated, meaning a tab has been clicked to reveal it.  Note: the first
		// image is assumed to be activated on load.
		activate: function() {
			if (!this.initted) this.init();
		},

		// Add jcrop to the element
		init: function() {

			// Only init once and only add jcrop if the image is visible.  Otherwise, it will
			// wait until it is first activated by the style tabs.  It needs to be visible
			// so the size can be measured correctly
			if (this.initted || !this.visible()) return;
			this.initted = true;

			// Cache the visible dimensions of the image
			this.width = this.$el.width();
			this.height = this.$el.height();

			// Check if there is any crop selection defined
			var cropVal = this.input_to_json(this.$crop);
			if (cropVal['x1'] != null) var selection = this.convert_from_perc(cropVal);

			// Init jcrop
			var self = this;
			this.$el.Jcrop({
				onSelect: this.select,
				onRelease: this.select,
				aspectRatio: this.ratio,
				setSelect: selection,
				keySupport: false // Stop the page scroll from jumping: http://cl.ly/0e1e1615262h

			// Store a reference to jcrop and call the ready function
			}, function() {
				self.jcrop = this;
				activeCrop = true;

				// Put all of the jcrop instances in a parent to give them the polariod effecast
				self.$el.siblings('.jcrop-holder').wrap('
');
			});

			// Check if focal point is set
			var focalVal = this.input_to_json(this.$focus);
			if(this.$focusTool.length != 0) {
				this.$el.next('div').append('

');
				this.$focalPoint = this.$el.next('div').find('.focal-point');
				this.$focalPoint.css({'left' : focalVal.x * this.$el.outerWidth(), 'top' : focalVal.y * this.$el.outerHeight()});

				if(!$.isEmptyObject(focalVal)) {
					this.$focalPoint.css('opacity', 1);
				}
			}

		},

		// Set up cropping when crop tool is clicked
		beginCrop: function() {
			// remove the set focus listener
			this.$el.next('div').unbind();

			// make the crop tool active
			this.$cropTool.addClass('active');
			this.$focusTool.removeClass('active');
			$('.jcrop-holder').css('pointer-events', 'auto');

			this.jcrop.enable();
			this.activeCrop = true;
		},

		// Switch to set focal point
		beginFocus: function() {
			this.$cropTool.removeClass('active');
			this.$focusTool.addClass('active');
			$('.jcrop-holder').css('pointer-events', 'none');

			this.jcrop.disable();
			this.activeCrop = false;

			this.$el.next('div').on('click', this.setFocus);
		},

		setFocus: function(e) {
			var image = $(e.currentTarget);
			var offset = image.offset();

			var pointX = e.pageX - offset.left;
			var pointY = e.pageY - offset.top;

			var location = {
				x : pointX / image.outerWidth(),
				y : pointY / image.outerHeight()
			};

			var cropVal = this.input_to_json(this.$crop);
			var selection = this.convert_from_perc(cropVal);
			this.$focus.val(JSON.stringify(location));

			if(!$.isEmptyObject(cropVal)) {
				if(pointX < selection[0] || pointY < selection[1] || pointX > selection[2] || pointY > selection[3]) {
					console.log('Focal point must be inside crop')
					return;
				}
			}

			this.$focalPoint.css({'left' : location.x * this.$el.outerWidth(), 'top' : location.y * this.$el.outerHeight(), 'opacity' : 1 });
		},

		// Remove jcrop from the element
		destroy: function() {

			// Only valid if currently initted
			if (!this.jcrop || !this.initted) return;

			// Unset everything
			this.jcrop.destroy();
			this.$el.siblings('.img-thumbnail').remove();
			this.jcrop = null;
			this.initted = false;

			// Jcrop will have set width/height on the style
			this.$el.css({width:'', height:''});

		},

		// Perist the user's selection
		select: function(c) {

			// Convert the coordinates from jcrop into percentages.  It may be undefined if the user
			// cleared the crop
			if (c) c = this.convert_to_perc(c);

			// Add the coordinates to the input's value
			var val = this.input_to_json(this.$crop);
			val = c;
			this.$crop.val(JSON.stringify(val));

		},

		// Clear out the hidden input values for a new image
		clear: function() {
			this.$crop.val("");
			this.$focus.val("");
			this.$title.val("");
			this.$focusTool.removeClass('active');
			this.$cropTool.addClass('active');
		},

		// Check if the this crop is visible
		visible: function() {
			return this.$el.is(":visible");
		},

		// Convert the coordinates from jcrop into percentages.  So an x value of 10
		// in a 100px wide image would become .1.  This is done because Croppa will already
		// be serving an image that is resized from it's source, so a perc offset
		// is the only thing that will be useful.
		convert_to_perc: function(c) {
			return {
				x1 : c.x / this.width,
				x2 : c.x2 / this.width,
				y1 : c.y / this.height,
				y2 : c.y2 / this.height
			};
		},

		// Convert from perc back to pixels of the current image size
		convert_from_perc: function(c) {
			return [
				c.x1 * this.width,
				c.y1 * this.height,
				c.x2 * this.width,
				c.y2 * this.height
			];
		},

		// Get JSON from the $input
		input_to_json: function(input) {
			var val = $(input).val();
			if (!val) return {};
			else return JSON.parse(val);
		}

	});

	return Crop;

});
<commit_msg>Whitespace<commit_after>// --------------------------------------------------
// Add file preview to selected images
// --------------------------------------------------
define(function (require) {

	// Dependencies
	var $ = require('jquery'),
		_ = require('underscore'),
		Backbone = require('backbone');
	  require('jcrop');
	  require('imagesloaded');

	// Define a backbone view for each image
	var Crop = Backbone.View.extend({

		// Instance vars
		jcrop: null, // A jcrop API instance
		activeCrop: false,
		width: null,
		height: null,
		ratio: undefined,
		initted: false,
		$input: null, // The hidden field that stores the output

		// Constructor
		initialize: function() {
			_.bindAll(this);

			// Cache selectors
			this.$upload = this.$el.closest('.image-upload');
			this.$crop = this.$upload.find('.input-crop_box');
			this.$focus = this.$upload.find('.input-focal_point');
			this.$title = this.$upload.find('input.title');
			this.$cropTool = this.$upload.find('.crop.btn');
			this.$focusTool = this.$upload.find('.focal.btn');
			this.$file = this.$upload.find('[type="file"]');

			// Remove clicking on the parent a tag
			this.$el.parent('a').click(function(e) { e.preventDefault(); });

			// Cache configruation variables
			var ratio = this.$upload.data('aspect-ratio');
			this.ratio = ratio;

			// Listen for window resizing as a way to check whether the img has been resized
			// since it resizes responsively.  We listen on the leading edge for the start
			// and the tailing edge for the end
			var $window = $(window), delay = 400;
			$window.resize(_.debounce(this.destroy, delay, true));
			$window.resize(_.debounce(this.init, delay, false));

			this.$cropTool.on('click', this.beginCrop);
			this.$focusTool.on('click', this.beginFocus);

			// Start jcrop up once the images loaded
			this.$el.imagesLoaded(this.init);

		},

		// Events
		events: {
			'active': 'activate' // This image has now been activated
		},

		// Activated, meaning a tab has been clicked to reveal it.  Note: the first
		// image is assumed to be activated on load.
		activate: function() {
			if (!this.initted) this.init();
		},

		// Add jcrop to the element
		init: function() {

			// Only init once and only add jcrop if the image is visible.  Otherwise, it will
			// wait until it is first activated by the style tabs.  It needs to be visible
			// so the size can be measured correctly
			if (this.initted || !this.visible()) return;
			this.initted = true;

			// Cache the visible dimensions of the image
			this.width = this.$el.width();
			this.height = this.$el.height();

			// Check if there is any crop selection defined
			var cropVal = this.input_to_json(this.$crop);
			if (cropVal['x1'] != null) var selection = this.convert_from_perc(cropVal);

			// Init jcrop
			var self = this;
			this.$el.Jcrop({
				onSelect: this.select,
				onRelease: this.select,
				aspectRatio: this.ratio,
				setSelect: selection,
				keySupport: false // Stop the page scroll from jumping: http://cl.ly/0e1e1615262h

			// Store a reference to jcrop and call the ready function
			}, function() {
				self.jcrop = this;
				activeCrop = true;

				// Put all of the jcrop instances in a parent to give them the polariod effecast
				self.$el.siblings('.jcrop-holder').wrap('
');
			});

			// Check if focal point is set
			var focalVal = this.input_to_json(this.$focus);
			if(this.$focusTool.length != 0) {
				this.$el.next('div').append('

');
				this.$focalPoint = this.$el.next('div').find('.focal-point');
				this.$focalPoint.css({'left' : focalVal.x * this.$el.outerWidth(), 'top' : focalVal.y * this.$el.outerHeight()});

				if(!$.isEmptyObject(focalVal)) {
					this.$focalPoint.css('opacity', 1);
				}
			}

		},

		// Set up cropping when crop tool is clicked
		beginCrop: function() {
			// remove the set focus listener
			this.$el.next('div').unbind();

			// make the crop tool active
			this.$cropTool.addClass('active');
			this.$focusTool.removeClass('active');
			$('.jcrop-holder').css('pointer-events', 'auto');

			this.jcrop.enable();
			this.activeCrop = true;
		},

		// Switch to set focal point
		beginFocus: function() {
			this.$cropTool.removeClass('active');
			this.$focusTool.addClass('active');
			$('.jcrop-holder').css('pointer-events', 'none');

			this.jcrop.disable();
			this.activeCrop = false;

			this.$el.next('div').on('click', this.setFocus);
		},

		setFocus: function(e) {
			var image = $(e.currentTarget);
			var offset = image.offset();

			var pointX = e.pageX - offset.left;
			var pointY = e.pageY - offset.top;

			var location = {
				x : pointX / image.outerWidth(),
				y : pointY / image.outerHeight()
			};

			var cropVal = this.input_to_json(this.$crop);
			var selection = this.convert_from_perc(cropVal);
			this.$focus.val(JSON.stringify(location));

			if(!$.isEmptyObject(cropVal)) {
				if(pointX < selection[0] || pointY < selection[1] || pointX > selection[2] || pointY > selection[3]) {
					console.log('Focal point must be inside crop')
					return;
				}
			}

			this.$focalPoint.css({'left' : location.x * this.$el.outerWidth(), 'top' : location.y * this.$el.outerHeight(), 'opacity' : 1 });
		},

		// Remove jcrop from the element
		destroy: function() {

			// Only valid if currently initted
			if (!this.jcrop || !this.initted) return;

			// Unset everything
			this.jcrop.destroy();
			this.$el.siblings('.img-thumbnail').remove();
			this.jcrop = null;
			this.initted = false;

			// Jcrop will have set width/height on the style
			this.$el.css({width:'', height:''});

		},

		// Perist the user's selection
		select: function(c) {

			// Convert the coordinates from jcrop into percentages.  It may be undefined if the user
			// cleared the crop
			if (c) c = this.convert_to_perc(c);

			// Add the coordinates to the input's value
			var val = this.input_to_json(this.$crop);
			val = c;
			this.$crop.val(JSON.stringify(val));

		},

		// Clear out the hidden input values for a new image
		clear: function() {
			this.$crop.val("");
			this.$focus.val("");
			this.$title.val("");
			this.$focusTool.removeClass('active');
			this.$cropTool.addClass('active');
		},

		// Check if the this crop is visible
		visible: function() {
			return this.$el.is(":visible");
		},

		// Convert the coordinates from jcrop into percentages.  So an x value of 10
		// in a 100px wide image would become .1.  This is done because Croppa will already
		// be serving an image that is resized from it's source, so a perc offset
		// is the only thing that will be useful.
		convert_to_perc: function(c) {
			return {
				x1 : c.x / this.width,
				x2 : c.x2 / this.width,
				y1 : c.y / this.height,
				y2 : c.y2 / this.height
			};
		},

		// Convert from perc back to pixels of the current image size
		convert_from_perc: function(c) {
			return [
				c.x1 * this.width,
				c.y1 * this.height,
				c.x2 * this.width,
				c.y2 * this.height
			];
		},

		// Get JSON from the $input
		input_to_json: function(input) {
			var val = $(input).val();
			if (!val) return {};
			else return JSON.parse(val);
		}

	});

	return Crop;

});
<|endoftext|>


<commit_before>const gulp = require('gulp');
const $ = require('gulp-load-plugins')();
const cleanCSS = require('gulp-clean-css');
const browserSync = require('browser-sync').create();
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const webpackConfig = require('./webpack.config');
const pkg = require('./package.json');
const banner = `/*! UNITS v${pkg.version} | MIT License | Copyright 2017 @kokushing | mail@kokush.in | http://unitscss.com */\n`;
const processors = [
  require('postcss-import')(),
  require('postcss-nested')(),
  require('postcss-for')(),
  require('postcss-cssnext')({
    features: {
      nesting: false
    },
    browsers: ['last 2 version'],
  })
];

/* Build task */

gulp.task('styles', ['styles:partial'], () => {
  return gulp.src('./src/css/_import.css')
    .pipe($.plumber())
    .pipe($.postcss(processors))
    .pipe($.header(banner))
    .pipe($.rename('units.css'))
    .pipe(gulp.dest('./dist'))
    .pipe(cleanCSS())
    .pipe($.rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest('./dist'));
});

gulp.task('styles:partial', () => {
  return gulp.src(['./src/css/*.css', '!./src/css/_import.css', '!./src/css/variables.css'])
    .pipe($.plumber())
    .pipe($.postcss(processors))
    .pipe($.header(banner))
    .pipe(gulp.dest('./dist/partial'));
});

gulp.task('javascripts', () => {
  return gulp.src('./src/js/_import.js')
    .pipe($.plumber())
    .pipe(webpackStream(webpackConfig, webpack))
    .pipe($.uglify())
    .pipe($.header(banner))
    .pipe($.rename('units.min.js'))
    .pipe(gulp.dest('./dist'));
});

gulp.task('default', ['styles', 'javascripts']);

/* Development task */

gulp.task('dev:serve', ['dev:styles', 'dev:javascripts'], () => {
  browserSync.init({
    server: './public',
    notify: false,
    ghostMode: false
  });

  gulp.watch('./src/css/**/*.css', ['dev:styles']);
  gulp.watch('./src/js/**/*.js', ['dev:js-reload']);
  gulp.watch('./public/**/*.html').on('change', browserSync.reload);
});

gulp.task('dev:styles', () => {
  return gulp.src('./src/css/_import.css')
    .pipe($.plumber())
    .pipe($.sourcemaps.init())
    .pipe($.postcss(processors))
    .pipe($.rename('units.css'))
    .pipe($.sourcemaps.write('./maps'))
    .pipe(gulp.dest('./public/css'))
    .pipe(browserSync.stream());
});

gulp.task('dev:javascripts', () => {
  return gulp.src('./src/js/_import.js')
    .pipe($.plumber())
    .pipe(webpackStream(webpackConfig, webpack))
    .pipe($.rename('units.js'))
    .pipe(gulp.dest('./public/js'));
});

gulp.task('dev:js-reload', ['dev:javascripts'], (done) => {
  browserSync.reload();
  done();
});

gulp.task('dev', ['dev:serve']);
<commit_msg>[add] development tasks<commit_after>const gulp = require('gulp');
const $ = require('gulp-load-plugins')();
const cleanCSS = require('gulp-clean-css');
const browserSync = require('browser-sync').create();
const webpack = require('webpack');
const webpackStream = require('webpack-stream');
const webpackConfig = require('./webpack.config');
const pkg = require('./package.json');
const banner = `/*! UNITS v${pkg.version} | MIT License | Copyright 2017 @kokushing | mail@kokush.in | http://unitscss.com */\n`;
const processors = [
  require('postcss-import')(),
  require('postcss-nested')(),
  require('postcss-for')(),
  require('postcss-cssnext')({
    features: {
      nesting: false
    },
    browsers: ['last 2 version'],
  })
];

/* Build task */

gulp.task('styles', ['styles:partial'], () => {
  return gulp.src('./src/css/_import.css')
    .pipe($.plumber())
    .pipe($.postcss(processors))
    .pipe($.header(banner))
    .pipe($.rename('units.css'))
    .pipe(gulp.dest('./dist'))
    .pipe(cleanCSS())
    .pipe($.rename({
      suffix: '.min'
    }))
    .pipe(gulp.dest('./dist'));
});

gulp.task('styles:partial', () => {
  return gulp.src(['./src/css/*.css', '!./src/css/_import.css', '!./src/css/variables.css'])
    .pipe($.plumber())
    .pipe($.postcss(processors))
    .pipe($.header(banner))
    .pipe(gulp.dest('./dist/partial'));
});

gulp.task('javascripts', () => {
  return gulp.src('./src/js/_import.js')
    .pipe($.plumber())
    .pipe(webpackStream(webpackConfig, webpack))
    .pipe($.uglify())
    .pipe($.header(banner))
    .pipe($.rename('units.min.js'))
    .pipe(gulp.dest('./dist'));
});

gulp.task('default', ['styles', 'javascripts']);

/* Development task */

gulp.task('dev:serve', ['dev:styles', 'dev:javascripts'], () => {
  browserSync.init({
    server: './public',
    notify: false,
    ghostMode: false
  });

  gulp.watch('./src/css/**/*.css', ['dev:styles']);
  gulp.watch('./src/js/**/*.js', ['dev:js-reload']);
  gulp.watch('./public/**/*.html').on('change', browserSync.reload);
});

gulp.task('dev:styles', ['styles'], () => {
  return gulp.src('./src/css/_import.css')
    .pipe($.plumber())
    .pipe($.sourcemaps.init())
    .pipe($.postcss(processors))
    .pipe($.rename('units.css'))
    .pipe($.sourcemaps.write('./maps'))
    .pipe(gulp.dest('./public/css'))
    .pipe(browserSync.stream());
});

gulp.task('dev:javascripts', ['javascripts'], () => {
  return gulp.src('./src/js/_import.js')
    .pipe($.plumber())
    .pipe(webpackStream(webpackConfig, webpack))
    .pipe($.rename('units.js'))
    .pipe(gulp.dest('./public/js'));
});

gulp.task('dev:js-reload', ['dev:javascripts'], (done) => {
  browserSync.reload();
  done();
});

gulp.task('dev', ['dev:serve']);
<|endoftext|>


<commit_before>hbControllers.controller('StatisticCtrl', ['$scope', '$routeParams', 'utils', 'Transaction',
    function($scope, $routeParams, utils, Transaction) {

        $scope.periods = [
            {
                title: 'last week',
                startdate: utils.getFirstDayOfWeek(),
                enddate: utils.getLastDayOfWeek()
            },
            {
                title: 'last month',
                startdate: utils.getFirstDayOfMonth(),
                enddate: utils.getLastDayOfMonth()
            },
            {
                title: 'last year',
                startdate: utils.getFirstDayOfYear(),
                enddate: utils.getLastDayOfYear()
            }
        ];

        $scope.period = $scope.periods[1];

        $scope.fetch = function(callback) {
            $scope.labels = [];
            $scope.datasets = [];

            var param = {
                id: 'statistic',
                startdate: $scope.period.startdate,
                enddate: $scope.period.enddate
            };
            Transaction.query(param, function(data) {
                $scope.transactions = data.items;

                $scope.transactions.sort(function(a, b) {
                    return a['amount'] < b['amount'];
                });

                $scope.prepareBarchartData($scope.transactions);
                callback();
            });
            $scope.orderProp = 'age';
        };

        $scope.prepareBarchartData = function(rawTransactions) {

            var data = [];
            rawTransactions.forEach(function(transaction) {
                var amount = parseFloat(transaction.amount, 10);

                if($scope.labels.indexOf(transaction.category) === -1) {
                    $scope.labels.push(transaction.category);
                }

                data.push(amount);
            });
            $scope.datasets = data;
        };

        $scope.drawBarchart = function() {
            $scope.chart = {
                options: {
                    chart: {
                        type: $scope.type
                    }
                },
                xAxis: {
                    categories: $scope.labels
                },
                yAxis: {
                    title: {
                        enabled: false
                    }
                },
                series: [{
                        data: $scope.datasets
                }],
                plotOptions: {
                    bar: {
                        dataLabels: {
                            enabled: true
                        }
                    }
                },
                legend: {
                    enabled: false
                },
                title: {
                    text: $scope.period.startdate + ' - ' + $scope.period.enddate
                },
                loading: false
            };
        };

        $scope.drawPiechart = function() {
            var data = [];
            if (!$scope.transactions) {
                return false;
            }
            $scope.transactions.forEach(function(transaction) {
                var amount = parseFloat(transaction.amount, 10);
                if (amount > 0) {
                    return;
                }
                var item = {
                    value: amount,
                    color: utils.getHexColor(),
                    label: transaction.category,
                    labelColor: 'white',
                    labelFontSize: '16'
                };
                data.push(item);
            });

            $scope.piechartOptions = {
                animation: false
            };

            $scope.piechart = data;
        };

        $scope.runQuery = function() {
            $scope.type = $routeParams.type;
            if ($scope.type === 'piechart') {
                $scope.fetch($scope.drawPiechart);
            } else {
                $scope.fetch($scope.drawBarchart);
            }
        };

        $scope.addBarchartData = function() {
            $scope.period.startdate = '01.01.2012';
            $scope.period.enddate = '31.12.2012';
            $scope.fetch(function() {

            });
        };

        $scope.runQuery();
        //$scope.addBarchartData();
    }]);<commit_msg>removed unused code<commit_after>hbControllers.controller('StatisticCtrl', ['$scope', '$routeParams', 'utils', 'Transaction',
    function($scope, $routeParams, utils, Transaction) {

        $scope.periods = [
            {
                title: 'last week',
                startdate: utils.getFirstDayOfWeek(),
                enddate: utils.getLastDayOfWeek()
            },
            {
                title: 'last month',
                startdate: utils.getFirstDayOfMonth(),
                enddate: utils.getLastDayOfMonth()
            },
            {
                title: 'last year',
                startdate: utils.getFirstDayOfYear(),
                enddate: utils.getLastDayOfYear()
            }
        ];

        $scope.period = $scope.periods[1];

        $scope.fetch = function(callback) {
            $scope.labels = [];
            $scope.datasets = [];

            var param = {
                id: 'statistic',
                startdate: $scope.period.startdate,
                enddate: $scope.period.enddate
            };
            Transaction.query(param, function(data) {
                $scope.transactions = data.items;

                $scope.transactions.sort(function(a, b) {
                    return a['amount'] < b['amount'];
                });

                $scope.prepareBarchartData($scope.transactions);
                callback();
            });
        };

        $scope.prepareBarchartData = function(rawTransactions) {

            var data = [];
            rawTransactions.forEach(function(transaction) {
                var amount = parseFloat(transaction.amount, 10);

                if($scope.labels.indexOf(transaction.category) === -1) {
                    $scope.labels.push(transaction.category);
                }

                data.push(amount);
            });
            $scope.datasets = data;
        };

        $scope.drawChart = function() {
            $scope.chart = {
                options: {
                    chart: {
                        type: $scope.type
                    }
                },
                xAxis: {
                    categories: $scope.labels
                },
                yAxis: {
                    title: {
                        enabled: false
                    }
                },
                series: [{
                        data: $scope.datasets
                }],
                plotOptions: {
                    bar: {
                        dataLabels: {
                            enabled: true
                        }
                    }
                },
                legend: {
                    enabled: false
                },
                title: {
                    text: $scope.period.startdate + ' - ' + $scope.period.enddate
                },
                loading: false
            };
        };

        $scope.runQuery = function() {
            $scope.type = $routeParams.type;
            $scope.fetch($scope.drawChart);
        };

        $scope.runQuery();
    }]);<|endoftext|>


<commit_before>chrome.contextMenus.create({
  "title": "LookUpInOALD",
  "type": "normal",
  "contexts": ["selection"],
  "onclick":function() {
    chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
      var activeTab = tabs[0];
      chrome.tabs.sendMessage(activeTab.id, { "message": "clicked_browser_action" });
    });
  }
});

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.message === "open_new_tab") {
    var oald = 'http://www.oxfordlearnersdictionaries.com/search/english/?q=' + request.word;
    chrome.tabs.create({ "url": oald });
  }
});<commit_msg>add eow<commit_after>chrome.contextMenus.create({
  "title": "LookUpInOALD",
  "type": "normal",
  "contexts": ["selection"],
  "onclick":function() {
    chrome.tabs.query({ active: true, currentWindow: true }, function(tabs) {
      var activeTab = tabs[0];
      chrome.tabs.sendMessage(activeTab.id, { "message": "clicked_browser_action" });
    });
  }
});

chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
  if (request.message === "open_new_tab") {
    var oald = 'http://www.oxfordlearnersdictionaries.com/search/english/?q=' + request.word;
    var eow = 'http://eow.alc.co.jp/search?q=' + request.word;
    chrome.tabs.create({ "url": oald });
    chrome.tabs.create({ "url": eow });
  }
});<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import Relay from 'react-relay/classic';
import styled from 'styled-components';

import FriendlyTime from '../shared/FriendlyTime';
import RevealableDownChevron from '../shared/Icon/RevealableDownChevron';
import Panel from '../shared/Panel';
import UserAvatar from '../shared/UserAvatar';

import AuditLogDrawer from './Drawer';

import { indefiniteArticleFor } from '../../lib/words';

import cssVariables from '../../css';

const TransitionMaxHeight = styled.div`
  transition: max-height 400ms;
`;

class AuditLogRow extends React.PureComponent {
  static propTypes = {
    auditEvent: PropTypes.shape({
      uuid: PropTypes.string.isRequired,
      type: PropTypes.string.isRequired,
      occurredAt: PropTypes.string.isRequired,
      actor: PropTypes.shape({
        name: PropTypes.string,
        node: PropTypes.shape({
          name: PropTypes.string,
          avatar: PropTypes.shape({
            url: PropTypes.string
          })
        })
      }).isRequired,
      subject: PropTypes.shape({
        type: PropTypes.string.isRequired,
        name: PropTypes.string,
        node: PropTypes.shape({
          name: PropTypes.string
        })
      }).isRequired,
      context: PropTypes.shape({
        __typename: PropTypes.string.isRequired
      }).isRequired
    }).isRequired,
    relay: PropTypes.object.isRequired
  };

  state = {
    isExpanded: false,
    loading: false
  };

  getContextName() {
    return this.props.auditEvent.context.__typename.replace(/^Audit|Context$/g, '');
  }

  render() {
    const actorName = this.props.auditEvent.actor.name || this.props.auditEvent.actor.node && this.props.auditEvent.actor.node.name;

    return (
      <Panel.Row>

          <div
            className="flex items-center cursor-pointer hover-bg-silver mxn3 py2 px3"
            style={{
              marginTop: -10,
              // this is a hack to give the expandable section
              // a top border, without it taking up any space
              boxShadow: `0 1px 0 ${cssVariables['--gray']}`
            }}
            onClick={this.handleHeaderClick}
          >

              {this.props.auditEvent.actor.node && (

                  <UserAvatar
                    style={{ width: 39, height: 39 }}
                    user={this.props.auditEvent.actor.node}
                  />

              )}

                  {actorName}

                  {this.renderEventSentence()}

                <FriendlyTime
                  className="flex-none dark-gray"
                  value={this.props.auditEvent.occurredAt}
                />

              <RevealableDownChevron
                className="dark-gray"
                revealed={this.state.isExpanded}
              />

          <TransitionMaxHeight
            className="mxn3 overflow-hidden"
            style={{
              marginBottom: -10,
              maxHeight: this.state.isExpanded ? '80vh' : 0,
              overflowY: 'auto',
              overflowScrolling: 'touch',
              WebkitOverflowScrolling: 'touch'
            }}
          >
            <AuditLogDrawer
              auditEvent={this.props.auditEvent}
              hasExpanded={this.props.relay.variables.hasExpanded}
              loading={this.state.loading}
            />
          </TransitionMaxHeight>

      </Panel.Row>
    );
  }

  renderEventSentence() {
    const { type, subject } = this.props.auditEvent;

    // Take a guess at the verb. Usually the event type is subject type + event
    // verb, so strip off the subject type if it matches or just take the last
    // word, then sentence case the verb.

    let eventVerb;

    if (type.indexOf(`${subject.type}_`) === 0) {
      // "ORGANIZATION_TEAMS_ENABLED" with an "ORGANIZATION" subject => "TEAMS ENABLED"
      eventVerb = type.slice(subject.type.length + 1).replace('_', ' ');
    } else {
      // "PIPELINE_CREATED" => "CREATED"
      eventVerb = type.split('_').pop();
    }

    eventVerb = eventVerb.charAt(0).toUpperCase() + eventVerb.slice(1).toLowerCase();

    const renderedSubject = this.renderEventObject(subject);

    if (type === 'ORGANIZATION_CREATED') {
      // Welcome!
      return `Created ${renderedSubject} 🎉`;
    } else if (type === 'ORGANIZATION_TEAMS_ENABLED') {
      return `Enabled teams for ${renderedSubject}`;
    } else if (type === 'ORGANIZATION_TEAMS_DISABLED') {
      return `Disabled teams for ${renderedSubject}`;
    } else if (subject.type === 'TEAM_MEMBER') {
      const renderedTeam = this.renderEventObject({ type: 'TEAM', node: subject.node && subject.node.team });
      const renderedUser = this.renderEventObject({ type: 'USER', node: subject.node && subject.node.user });

      if (type === 'TEAM_MEMBER_CREATED') {
        return `Added ${renderedUser} to ${renderedTeam}`;
      } else if (type === 'TEAM_MEMBER_DELETED') {
        return `Removed ${renderedUser} from ${renderedTeam}`;
      } else {
        return `${eventVerb} ${renderedUser} in ${renderedTeam}`;
      }
    } else if (subject.type === 'TEAM_PIPELINE') {
      const renderedTeam = this.renderEventObject({ type: 'TEAM', node: subject.node && subject.node.team });
      const renderedPipeline = this.renderEventObject({ type: 'PIPELINE', node: subject.node && subject.node.pipeline });

      if (type === 'TEAM_PIPELINE_CREATED') {
        return `Added ${renderedPipeline} to ${renderedTeam}`;
      } else if (type === 'TEAM_PIPELINE_DELETED') {
        return `Removed ${renderedPipeline} from ${renderedTeam}`;
      } else {
        return `${eventVerb} ${renderedPipeline} in ${renderedTeam}`;
      }
    } else {
      return `${eventVerb} ${renderedSubject}`;
    }
  }

  renderEventObject({ type, name, node }) {
    // "ORGANIZATION_INVITATION" => "organzation invitation"
    const friendlyType = type && type.split('_').pop().toLowerCase();

    // Check if we can still see the node and its current name, fall back to
    // the name recorded at the time of the event if present, or just an
    // indefinite type name
    if (node && node.name) {
      return `${friendlyType} “${node.name}”`;
    } else if (name) {
      return `${friendlyType} “${name}”`;
    } else if (type === "USER") {
      // "an user" feels weird
      return 'a user';
    } else {
      return `${indefiniteArticleFor(friendlyType)} ${friendlyType}`;
    }
  }

  handleHeaderClick = () => {
    const isExpanded = !this.state.isExpanded;

    this.setState({
      loading: true,
      isExpanded
    }, () => {
      this.props.relay.setVariables(
        {
          hasExpanded: true
        },
        (readyState) => {
          if (readyState.done) {
            this.setState({ loading: false });
          }
        }
      );
    });
  };
}

export default Relay.createContainer(AuditLogRow, {
  initialVariables: {
    hasExpanded: false
  },

  fragments: {
    auditEvent: ({ hasExpanded }) => Relay.QL`
      fragment on AuditEvent {
        ${AuditLogDrawer.getFragment('auditEvent', { hasExpanded })}
        uuid
        type
        occurredAt
        actor {
          name
          node {
            ...on User {
              name
              avatar {
                url
              }
            }
          }
        }
        subject {
          type
          name
          node {
            ...on Organization {
              name
            }
            ...on Pipeline {
              name
            }
            ...on Team {
              name
            }
            ...on TeamMember {
              team {
                name
              }
              user {
                name
              }
            }
            ...on TeamPipeline {
              team {
                name
              }
              pipeline {
                name
              }
            }
          }
        }
        context {
          __typename
        }
      }
    `
  }
});
<commit_msg>eslint advises avoiding else return<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import Relay from 'react-relay/classic';
import styled from 'styled-components';

import FriendlyTime from '../shared/FriendlyTime';
import RevealableDownChevron from '../shared/Icon/RevealableDownChevron';
import Panel from '../shared/Panel';
import UserAvatar from '../shared/UserAvatar';

import AuditLogDrawer from './Drawer';

import { indefiniteArticleFor } from '../../lib/words';

import cssVariables from '../../css';

const TransitionMaxHeight = styled.div`
  transition: max-height 400ms;
`;

class AuditLogRow extends React.PureComponent {
  static propTypes = {
    auditEvent: PropTypes.shape({
      uuid: PropTypes.string.isRequired,
      type: PropTypes.string.isRequired,
      occurredAt: PropTypes.string.isRequired,
      actor: PropTypes.shape({
        name: PropTypes.string,
        node: PropTypes.shape({
          name: PropTypes.string,
          avatar: PropTypes.shape({
            url: PropTypes.string
          })
        })
      }).isRequired,
      subject: PropTypes.shape({
        type: PropTypes.string.isRequired,
        name: PropTypes.string,
        node: PropTypes.shape({
          name: PropTypes.string
        })
      }).isRequired,
      context: PropTypes.shape({
        __typename: PropTypes.string.isRequired
      }).isRequired
    }).isRequired,
    relay: PropTypes.object.isRequired
  };

  state = {
    isExpanded: false,
    loading: false
  };

  getContextName() {
    return this.props.auditEvent.context.__typename.replace(/^Audit|Context$/g, '');
  }

  render() {
    const actorName = this.props.auditEvent.actor.name || this.props.auditEvent.actor.node && this.props.auditEvent.actor.node.name;

    return (
      <Panel.Row>

          <div
            className="flex items-center cursor-pointer hover-bg-silver mxn3 py2 px3"
            style={{
              marginTop: -10,
              // this is a hack to give the expandable section
              // a top border, without it taking up any space
              boxShadow: `0 1px 0 ${cssVariables['--gray']}`
            }}
            onClick={this.handleHeaderClick}
          >

              {this.props.auditEvent.actor.node && (

                  <UserAvatar
                    style={{ width: 39, height: 39 }}
                    user={this.props.auditEvent.actor.node}
                  />

              )}

                  {actorName}

                  {this.renderEventSentence()}

                <FriendlyTime
                  className="flex-none dark-gray"
                  value={this.props.auditEvent.occurredAt}
                />

              <RevealableDownChevron
                className="dark-gray"
                revealed={this.state.isExpanded}
              />

          <TransitionMaxHeight
            className="mxn3 overflow-hidden"
            style={{
              marginBottom: -10,
              maxHeight: this.state.isExpanded ? '80vh' : 0,
              overflowY: 'auto',
              overflowScrolling: 'touch',
              WebkitOverflowScrolling: 'touch'
            }}
          >
            <AuditLogDrawer
              auditEvent={this.props.auditEvent}
              hasExpanded={this.props.relay.variables.hasExpanded}
              loading={this.state.loading}
            />
          </TransitionMaxHeight>

      </Panel.Row>
    );
  }

  renderEventSentence() {
    const { type, subject } = this.props.auditEvent;

    // Take a guess at the verb. Usually the event type is subject type + event
    // verb, so strip off the subject type if it matches or just take the last
    // word, then sentence case the verb.

    let eventVerb;

    if (type.indexOf(`${subject.type}_`) === 0) {
      // "ORGANIZATION_TEAMS_ENABLED" with an "ORGANIZATION" subject => "TEAMS ENABLED"
      eventVerb = type.slice(subject.type.length + 1).replace('_', ' ');
    } else {
      // "PIPELINE_CREATED" => "CREATED"
      eventVerb = type.split('_').pop();
    }

    eventVerb = eventVerb.charAt(0).toUpperCase() + eventVerb.slice(1).toLowerCase();

    const renderedSubject = this.renderEventObject(subject);

    if (type === 'ORGANIZATION_CREATED') {
      // Welcome!
      return `Created ${renderedSubject} 🎉`;
    } else if (type === 'ORGANIZATION_TEAMS_ENABLED') {
      return `Enabled teams for ${renderedSubject}`;
    } else if (type === 'ORGANIZATION_TEAMS_DISABLED') {
      return `Disabled teams for ${renderedSubject}`;
    } else if (subject.type === 'TEAM_MEMBER') {
      const renderedTeam = this.renderEventObject({ type: 'TEAM', node: subject.node && subject.node.team });
      const renderedUser = this.renderEventObject({ type: 'USER', node: subject.node && subject.node.user });

      if (type === 'TEAM_MEMBER_CREATED') {
        return `Added ${renderedUser} to ${renderedTeam}`;
      } else if (type === 'TEAM_MEMBER_DELETED') {
        return `Removed ${renderedUser} from ${renderedTeam}`;
      }

      return `${eventVerb} ${renderedUser} in ${renderedTeam}`;
    } else if (subject.type === 'TEAM_PIPELINE') {
      const renderedTeam = this.renderEventObject({ type: 'TEAM', node: subject.node && subject.node.team });
      const renderedPipeline = this.renderEventObject({ type: 'PIPELINE', node: subject.node && subject.node.pipeline });

      if (type === 'TEAM_PIPELINE_CREATED') {
        return `Added ${renderedPipeline} to ${renderedTeam}`;
      } else if (type === 'TEAM_PIPELINE_DELETED') {
        return `Removed ${renderedPipeline} from ${renderedTeam}`;
      }

      return `${eventVerb} ${renderedPipeline} in ${renderedTeam}`;
    }

    return `${eventVerb} ${renderedSubject}`;
  }

  renderEventObject({ type, name, node }) {
    // "ORGANIZATION_INVITATION" => "organzation invitation"
    const friendlyType = type && type.split('_').pop().toLowerCase();

    // Check if we can still see the node and its current name, fall back to
    // the name recorded at the time of the event if present, or just an
    // indefinite type name
    if (node && node.name) {
      return `${friendlyType} “${node.name}”`;
    } else if (name) {
      return `${friendlyType} “${name}”`;
    } else if (type === "USER") {
      // "an user" feels weird
      return 'a user';
    } else {
      return `${indefiniteArticleFor(friendlyType)} ${friendlyType}`;
    }
  }

  handleHeaderClick = () => {
    const isExpanded = !this.state.isExpanded;

    this.setState({
      loading: true,
      isExpanded
    }, () => {
      this.props.relay.setVariables(
        {
          hasExpanded: true
        },
        (readyState) => {
          if (readyState.done) {
            this.setState({ loading: false });
          }
        }
      );
    });
  };
}

export default Relay.createContainer(AuditLogRow, {
  initialVariables: {
    hasExpanded: false
  },

  fragments: {
    auditEvent: ({ hasExpanded }) => Relay.QL`
      fragment on AuditEvent {
        ${AuditLogDrawer.getFragment('auditEvent', { hasExpanded })}
        uuid
        type
        occurredAt
        actor {
          name
          node {
            ...on User {
              name
              avatar {
                url
              }
            }
          }
        }
        subject {
          type
          name
          node {
            ...on Organization {
              name
            }
            ...on Pipeline {
              name
            }
            ...on Team {
              name
            }
            ...on TeamMember {
              team {
                name
              }
              user {
                name
              }
            }
            ...on TeamPipeline {
              team {
                name
              }
              pipeline {
                name
              }
            }
          }
        }
        context {
          __typename
        }
      }
    `
  }
});
<|endoftext|>


<commit_before>var FidoHTML = require('fidohtml');
var FidoMail2IPFS = require('fidomail2ipfs');
var fiunis = require('fiunis');
var escape = require('lodash.escape');
var IPFSAPI = require('ipfs-api');
var JAM = require('fidonet-jam');
var moment = require('moment');
var RSS = require('rss');
var Squish = require('fidonet-squish');
var UUE2IPFS = require('uue2ipfs');

// Error processing:
var findErrorsInOptions = (opts, callback) => {
   /* jshint bitwise: false */

   if( typeof opts.msg !== 'string' || opts.msg.length < 1 ){
      opts.msg = 23;
   } else {
      opts.msg = opts.msg |0;
   }

   if(
      typeof opts.base !== 'string' || opts.base.length < 1
   ) return callback(new Error('The base path is not given.'));

   if(
      typeof opts.area !== 'string' || opts.area.length < 1
   ) return callback(new Error('The area name is not given.'));

   if( typeof opts.IPFS === 'undefined' ){
      opts.IPFS = null;
   } else {
      if( opts.IPFS === true ){
         opts.IPFS = {
            host: 'localhost',
            port: 5001
         };
      } else {
         var matchesIPFS = /^(.+):(\d+)$/.exec(opts.IPFS);
         if( matchesIPFS === null ) return callback(
            new Error('The IPFS host:port is invalid.')
         );
         opts.IPFS = {
            host: matchesIPFS[1],
            port: matchesIPFS[2]
         };
      }
   }

   callback(null, opts);
};

var dirToHashIPFS = (IPFS, dirPath, dirName, hashName, cbErr) => {
   if( hashCache[hashName] ) return cbErr(null); // already cached

   IPFS.util.addFromFs(
      dirPath,
      { recursive: true },
      (err, arrIPFS) => {
         if( err ) return cbErr(err);
         if(!( Array.isArray(arrIPFS) )) return cbErr(
            new Error(`[${dirName}] ${errors.notArrDir}`)
         );
         var arrDirIPFS = arrIPFS.filter(
            nextIPFS => (nextIPFS.path || '').endsWith(dirName)
         );
         if( arrDirIPFS.length < 1 ) return cbErr(
            new Error(`[${dirName}] ${errors.notFoundDir}`)
         );
         var hashIPFS = arrDirIPFS[ arrDirIPFS.length - 1 ].hash;
         // if the hash is fine, put to cache and quit
         if( hashIPFS ){
            hashCache[hashName] = hashIPFS;
            return cbErr(null);
         }
         // otherwise invalidate cache
         hashCache[hashName] = false;
         return cbErr(
            new Error(`[${dirName}] ${errors.undefinedDirHash}`)
         );
      }
   );
};

var messageImgUUE2IPFS = (msgText, optsIPFS, doneImgUUE2IPFS) => {
   if( optsIPFS === null ) return doneImgUUE2IPFS(null, msgText);

   UUE2IPFS.UUE2IPFS(
      msgText,
      (fileData, fileDone) => fileDone(null,
         [
            '![(',
            fileData.name.replace(/]/g, '\\]'),
            ')](fs:/ipfs/', fileData.hash, ')'
         ].join('')
      ),
      {
         API: IPFSAPI(optsIPFS.host, optsIPFS.port),
         filterMIME: UUE2IPFS.imgMIME()
      },
      doneImgUUE2IPFS
   );
};

var FGHIURL2IPFSURL = (FGHIURL, optsIPFS, optsIPFSURL, callback) => {
   if( optsIPFS === null ) return callback(null, FGHIURL);
   if(! optsIPFSURL ) return callback(null, FGHIURL);

   var escapedURL = escape(FGHIURL);

   var bufFGHIHTML = Buffer(`<meta charset="utf-8">${ ''
      }<title>FGHI URL</title>FGHI URL: ${escapedURL}`);

   IPFSAPI(
      optsIPFS.host, optsIPFS.port
   ).add(bufFGHIHTML, (err, resultIPFS) => {
      if( err ) return callback(err);
      if( !resultIPFS ) return callback(new Error(
         'Error putting a FGHI URL to IPFS.'
      ));
      if(!( Array.isArray(resultIPFS) )) return callback(new Error(
         'Not an Array received while putting a FGHI URL to IPFS.'
      ));
      if( resultIPFS.length !== 1 ) return callback(new Error(
         'Weird array received while putting a FGHI URL to IPFS.'
      ));
      var hashIPFS = resultIPFS[0].hash;
      if( typeof hashIPFS === 'undefined' ) return callback(new Error(
         'Undefined hash received while putting a FGHI URL to IPFS.'
      ));
      callback(null, `https://ipfs.io/ipfs/${hashIPFS}`);
   });
};

var MSGID2URL = someMSGID => someMSGID.split(
   /([A-Za-z01-9:/]+)/
).map((nextChunk, IDX) => {
   if( IDX % 2 === 0 ) return encodeURIComponent(nextChunk);
   return nextChunk; // captured by the regular expression
}).join('').replace( /%20/g, '+' );

module.exports = (options, callback) => {
   findErrorsInOptions(options, (err, opts) => {
      if( err ) return callback(err);

      // Access Fidonet mail:
      var fidomail;
      if(
         typeof opts.type === 'string' &&
         opts.type.toLowerCase() === 'squish'
      ){
         fidomail = Squish(opts.base);
      } else {
         fidomail = JAM(opts.base);
      }
      var feed = new RSS({
         title: opts.area,
         author: 'Fidonet authors of ' + opts.area,
         description: opts.area + ' area (Fidonet)',
         generator: 'Fido2RSS ' + require('./package.json').version,
         site_url: 'area://' + opts.area
      });

      var mailCounter = 0;
      var renderNextItem = () => {
         var nextItemNum = fidomail.size() - mailCounter;
         if( nextItemNum < 1 || mailCounter >= opts.msg ){
            // Finish:
            callback(null, feed.xml());
         } else {
            // Render one more mail item:
            fidomail.readHeader(nextItemNum, (err, header) => {
               if( err ) return callback(err);

               var decoded = fidomail.decodeHeader(header);
               var itemURL = 'area://' + opts.area;
               var itemURLFilters = '';

               if( typeof decoded.msgid !== 'undefined' ){
                  itemURLFilters = [
                     '?msgid=', MSGID2URL(decoded.msgid),
                     '&time=', decoded.origTime[0]
                  ].join('');
               } else {
                  itemURLFilters = [
                     '?time=',
                     decoded.origTime[0],
                     '-',
                     decoded.origTime[1],
                     '-',
                     decoded.origTime[2],
                     'T',
                     decoded.origTime[3],
                     ':',
                     decoded.origTime[4],
                     ':',
                     decoded.origTime[5]
                  ].join('');
               }
               itemURL += itemURLFilters;

               var itemDateZone = '+0';
               if( typeof decoded.timezone !== 'undefined' ){
                  if( /^\d+$/.test(decoded.timezone) ){
                     decoded.timezone = '+' + decoded.timezone;
                  }
                  if( /^[+-]\d+$/.test(decoded.timezone) ){
                     itemDateZone = decoded.timezone;
                  }
               }

               var itemDateString = moment().utcOffset(itemDateZone)
               .year(decoded.origTime[0])
               .month(decoded.origTime[1]-1)
               .date(decoded.origTime[2])
               .hour(decoded.origTime[3])
               .minute(decoded.origTime[4])
               .second(decoded.origTime[5])
               .millisecond(0)
               .format('ddd, D MMM YY HH:mm:ss ZZ');

               fidomail.decodeMessage(header, (err, msgText) => {
                  if( err ) return callback(err);

                  var FidoHTMLOptions = {
                     fontColor: true,
                     URLPrefixes: {
                        '*': '', // default
                        fs: IPFSURL => IPFSURL.replace(
                           /^fs:\/*/g, 'https://ipfs.io/'
                        ),
                        ipfs: IPFSURL => IPFSURL.replace(
                           /^ipfs:\/*/g, 'https://ipfs.io/'
                        )
                     }
                  };
                  var itemURLPrefix = '';
                  if( typeof opts.areaPrefixURL !== 'undefined' ){
                     itemURLPrefix = opts.areaPrefixURL;
                     FidoHTMLOptions.URLPrefixes.area = opts.areaPrefixURL;
                     FidoHTMLOptions.fileURLParts = [
                        opts.areaPrefixURL,
                        itemURLFilters
                     ];
                  }

                  messageImgUUE2IPFS(msgText, opts.IPFS, (err, msgIPFS) => {
                     if( err ) return callback(err);

                     FGHIURL2IPFSURL(
                        itemURLPrefix + itemURL,
                        opts.IPFS,
                        opts.IPFSURL,
                        (err, resultURL) => {
                           if( err ) return callback(err);

                           feed.item({
                              'title': fiunis.decode(
                                 decoded.subj
                              ) || '(no title)',
                              'description': FidoHTML(
                                 FidoHTMLOptions
                              ).fromText(msgIPFS),
                              'url': resultURL,
                              'guid': itemURL,
                              'author': decoded.from,
                              'date': itemDateString
                           });
                           mailCounter++;
                           setImmediate(renderNextItem);
                        }
                     );
                  });
               });
            });
         }
      };

      if(
         typeof opts.type === 'string' &&
         opts.type.toLowerCase() === 'squish'
      ){
         fidomail.readSQI(err => {
            if( err ) return callback(err);

            setImmediate(renderNextItem);
         });
      } else {
         fidomail.readJDX(err => {
            if( err ) return callback(err);

            setImmediate(renderNextItem);
         });
      }
   });
};<commit_msg>[skip ci] also bring error messages from my `fidomail2ipfs` package<commit_after>var FidoHTML = require('fidohtml');
var FidoMail2IPFS = require('fidomail2ipfs');
var fiunis = require('fiunis');
var escape = require('lodash.escape');
var IPFSAPI = require('ipfs-api');
var JAM = require('fidonet-jam');
var moment = require('moment');
var RSS = require('rss');
var Squish = require('fidonet-squish');
var UUE2IPFS = require('uue2ipfs');

// Error processing:
var findErrorsInOptions = (opts, callback) => {
   /* jshint bitwise: false */

   if( typeof opts.msg !== 'string' || opts.msg.length < 1 ){
      opts.msg = 23;
   } else {
      opts.msg = opts.msg |0;
   }

   if(
      typeof opts.base !== 'string' || opts.base.length < 1
   ) return callback(new Error('The base path is not given.'));

   if(
      typeof opts.area !== 'string' || opts.area.length < 1
   ) return callback(new Error('The area name is not given.'));

   if( typeof opts.IPFS === 'undefined' ){
      opts.IPFS = null;
   } else {
      if( opts.IPFS === true ){
         opts.IPFS = {
            host: 'localhost',
            port: 5001
         };
      } else {
         var matchesIPFS = /^(.+):(\d+)$/.exec(opts.IPFS);
         if( matchesIPFS === null ) return callback(
            new Error('The IPFS host:port is invalid.')
         );
         opts.IPFS = {
            host: matchesIPFS[1],
            port: matchesIPFS[2]
         };
      }
   }

   callback(null, opts);
};

var hashCache = { redirector: false };
var dirToHashIPFS = (IPFS, dirPath, dirName, hashName, cbErr) => {
   if( hashCache[hashName] ) return cbErr(null); // already cached

   var errors = {
      notArrDir: 'Not an Array received putting a directory to IPFS.',
      notFoundDir: 'Directory not found in an Array of content put to IPFS.',
      undefinedDirHash: 'Undefined hash after putting a directory to IPFS.'
   };

   IPFS.util.addFromFs(
      dirPath,
      { recursive: true },
      (err, arrIPFS) => {
         if( err ) return cbErr(err);
         if(!( Array.isArray(arrIPFS) )) return cbErr(
            new Error(`[${dirName}] ${errors.notArrDir}`)
         );
         var arrDirIPFS = arrIPFS.filter(
            nextIPFS => (nextIPFS.path || '').endsWith(dirName)
         );
         if( arrDirIPFS.length < 1 ) return cbErr(
            new Error(`[${dirName}] ${errors.notFoundDir}`)
         );
         var hashIPFS = arrDirIPFS[ arrDirIPFS.length - 1 ].hash;
         // if the hash is fine, put to cache and quit
         if( hashIPFS ){
            hashCache[hashName] = hashIPFS;
            return cbErr(null);
         }
         // otherwise invalidate cache
         hashCache[hashName] = false;
         return cbErr(
            new Error(`[${dirName}] ${errors.undefinedDirHash}`)
         );
      }
   );
};

var messageImgUUE2IPFS = (msgText, optsIPFS, doneImgUUE2IPFS) => {
   if( optsIPFS === null ) return doneImgUUE2IPFS(null, msgText);

   UUE2IPFS.UUE2IPFS(
      msgText,
      (fileData, fileDone) => fileDone(null,
         [
            '![(',
            fileData.name.replace(/]/g, '\\]'),
            ')](fs:/ipfs/', fileData.hash, ')'
         ].join('')
      ),
      {
         API: IPFSAPI(optsIPFS.host, optsIPFS.port),
         filterMIME: UUE2IPFS.imgMIME()
      },
      doneImgUUE2IPFS
   );
};

var FGHIURL2IPFSURL = (FGHIURL, optsIPFS, optsIPFSURL, callback) => {
   if( optsIPFS === null ) return callback(null, FGHIURL);
   if(! optsIPFSURL ) return callback(null, FGHIURL);

   var escapedURL = escape(FGHIURL);

   var bufFGHIHTML = Buffer(`<meta charset="utf-8">${ ''
      }<title>FGHI URL</title>FGHI URL: ${escapedURL}`);

   IPFSAPI(
      optsIPFS.host, optsIPFS.port
   ).add(bufFGHIHTML, (err, resultIPFS) => {
      if( err ) return callback(err);
      if( !resultIPFS ) return callback(new Error(
         'Error putting a FGHI URL to IPFS.'
      ));
      if(!( Array.isArray(resultIPFS) )) return callback(new Error(
         'Not an Array received while putting a FGHI URL to IPFS.'
      ));
      if( resultIPFS.length !== 1 ) return callback(new Error(
         'Weird array received while putting a FGHI URL to IPFS.'
      ));
      var hashIPFS = resultIPFS[0].hash;
      if( typeof hashIPFS === 'undefined' ) return callback(new Error(
         'Undefined hash received while putting a FGHI URL to IPFS.'
      ));
      callback(null, `https://ipfs.io/ipfs/${hashIPFS}`);
   });
};

var MSGID2URL = someMSGID => someMSGID.split(
   /([A-Za-z01-9:/]+)/
).map((nextChunk, IDX) => {
   if( IDX % 2 === 0 ) return encodeURIComponent(nextChunk);
   return nextChunk; // captured by the regular expression
}).join('').replace( /%20/g, '+' );

module.exports = (options, callback) => {
   findErrorsInOptions(options, (err, opts) => {
      if( err ) return callback(err);

      // Access Fidonet mail:
      var fidomail;
      if(
         typeof opts.type === 'string' &&
         opts.type.toLowerCase() === 'squish'
      ){
         fidomail = Squish(opts.base);
      } else {
         fidomail = JAM(opts.base);
      }
      var feed = new RSS({
         title: opts.area,
         author: 'Fidonet authors of ' + opts.area,
         description: opts.area + ' area (Fidonet)',
         generator: 'Fido2RSS ' + require('./package.json').version,
         site_url: 'area://' + opts.area
      });

      var mailCounter = 0;
      var renderNextItem = () => {
         var nextItemNum = fidomail.size() - mailCounter;
         if( nextItemNum < 1 || mailCounter >= opts.msg ){
            // Finish:
            callback(null, feed.xml());
         } else {
            // Render one more mail item:
            fidomail.readHeader(nextItemNum, (err, header) => {
               if( err ) return callback(err);

               var decoded = fidomail.decodeHeader(header);
               var itemURL = 'area://' + opts.area;
               var itemURLFilters = '';

               if( typeof decoded.msgid !== 'undefined' ){
                  itemURLFilters = [
                     '?msgid=', MSGID2URL(decoded.msgid),
                     '&time=', decoded.origTime[0]
                  ].join('');
               } else {
                  itemURLFilters = [
                     '?time=',
                     decoded.origTime[0],
                     '-',
                     decoded.origTime[1],
                     '-',
                     decoded.origTime[2],
                     'T',
                     decoded.origTime[3],
                     ':',
                     decoded.origTime[4],
                     ':',
                     decoded.origTime[5]
                  ].join('');
               }
               itemURL += itemURLFilters;

               var itemDateZone = '+0';
               if( typeof decoded.timezone !== 'undefined' ){
                  if( /^\d+$/.test(decoded.timezone) ){
                     decoded.timezone = '+' + decoded.timezone;
                  }
                  if( /^[+-]\d+$/.test(decoded.timezone) ){
                     itemDateZone = decoded.timezone;
                  }
               }

               var itemDateString = moment().utcOffset(itemDateZone)
               .year(decoded.origTime[0])
               .month(decoded.origTime[1]-1)
               .date(decoded.origTime[2])
               .hour(decoded.origTime[3])
               .minute(decoded.origTime[4])
               .second(decoded.origTime[5])
               .millisecond(0)
               .format('ddd, D MMM YY HH:mm:ss ZZ');

               fidomail.decodeMessage(header, (err, msgText) => {
                  if( err ) return callback(err);

                  var FidoHTMLOptions = {
                     fontColor: true,
                     URLPrefixes: {
                        '*': '', // default
                        fs: IPFSURL => IPFSURL.replace(
                           /^fs:\/*/g, 'https://ipfs.io/'
                        ),
                        ipfs: IPFSURL => IPFSURL.replace(
                           /^ipfs:\/*/g, 'https://ipfs.io/'
                        )
                     }
                  };
                  var itemURLPrefix = '';
                  if( typeof opts.areaPrefixURL !== 'undefined' ){
                     itemURLPrefix = opts.areaPrefixURL;
                     FidoHTMLOptions.URLPrefixes.area = opts.areaPrefixURL;
                     FidoHTMLOptions.fileURLParts = [
                        opts.areaPrefixURL,
                        itemURLFilters
                     ];
                  }

                  messageImgUUE2IPFS(msgText, opts.IPFS, (err, msgIPFS) => {
                     if( err ) return callback(err);

                     FGHIURL2IPFSURL(
                        itemURLPrefix + itemURL,
                        opts.IPFS,
                        opts.IPFSURL,
                        (err, resultURL) => {
                           if( err ) return callback(err);

                           feed.item({
                              'title': fiunis.decode(
                                 decoded.subj
                              ) || '(no title)',
                              'description': FidoHTML(
                                 FidoHTMLOptions
                              ).fromText(msgIPFS),
                              'url': resultURL,
                              'guid': itemURL,
                              'author': decoded.from,
                              'date': itemDateString
                           });
                           mailCounter++;
                           setImmediate(renderNextItem);
                        }
                     );
                  });
               });
            });
         }
      };

      if(
         typeof opts.type === 'string' &&
         opts.type.toLowerCase() === 'squish'
      ){
         fidomail.readSQI(err => {
            if( err ) return callback(err);

            setImmediate(renderNextItem);
         });
      } else {
         fidomail.readJDX(err => {
            if( err ) return callback(err);

            setImmediate(renderNextItem);
         });
      }
   });
};<|endoftext|>


<commit_before>// References to all the element we will need.
var video = document.querySelector('#camera-stream'),
    image = document.querySelector('#snap'),
    start_camera = document.querySelector('#start-camera'),
    controls = document.querySelector('.controls'),
    take_photo_btn = document.querySelector('#take-photo'),
    delete_photo_btn = document.querySelector('#delete-photo'),
    download_photo_btn = document.querySelector('#download-photo'),
    error_message = document.querySelector('#error-message');

// The getUserMedia interface is used for handling camera input.
// Some browsers need a prefix so here we're covering all the options
navigator.getMedia = ( navigator.getUserMedia ||
                      navigator.webkitGetUserMedia ||
                      navigator.mozGetUserMedia ||
                      navigator.msGetUserMedia);

if(!navigator.getMedia){
  displayErrorMessage("Your browser doesn't have support for the navigator.getUserMedia interface.");
}
else{

  // Request the camera.
  navigator.getMedia(
    {
      video: true
    },
    // Success Callback
    function(stream){

      // Create an object URL for the video stream and
      // set it as src of our HTLM video element.
      video.src = window.URL.createObjectURL(stream);

      // Play the video element to start the stream.
      video.play();
      video.onplay = function() {
        showVideo();
      };

    },
    // Error Callback
    function(err){
      displayErrorMessage("There was an error with accessing the camera stream: " + err.name, err);
    }
  );

}

// Mobile browsers cannot play video without user input,
// so here we're using a button to start it manually.
start_camera.addEventListener("click", function(e){

  e.preventDefault();

  // Start video playback manually.
  video.play();
  showVideo();

});

take_photo_btn.addEventListener("click", function(e){

  e.preventDefault();

  var snap = takeSnapshot();

  // Show image.
  image.setAttribute('src', snap);
  image.classList.add("visible");

  // Enable delete and save buttons
  delete_photo_btn.classList.remove("disabled");
  download_photo_btn.classList.remove("disabled");

  // Set the href attribute of the download button to the snap url.
  download_photo_btn.href = snap;

  // Pause video playback of stream.
  video.pause();

});

function storeImg() {
  var snap = takeSnapshot();
  var imageData = snap.toDataURL("img/png");
  imgData = imgData.replace('data:image/png;base64,', '');
  var postData = JSON.stringify({ imageData: imgData });

  $.ajax({
    url:'https://mikelearning91.github.com/private/images',
    type: "Post",
    data: postData,
    contentType: "application/json"
    });
};

delete_photo_btn.addEventListener("click", function(e){

  e.preventDefault();

  // Hide image.
  image.setAttribute('src', "");
  image.classList.remove("visible");

  // Disable delete and save buttons
  delete_photo_btn.classList.add("disabled");
  download_photo_btn.classList.add("disabled");

  // Resume playback of stream.
  video.play();

});

function showVideo(){
  // Display the video stream and the controls.

  hideUI();
  video.classList.add("visible");
  controls.classList.add("visible");
}

function takeSnapshot(){
  // Here we're using a trick that involves a hidden canvas element.

  var hidden_canvas = document.querySelector('canvas'),
      context = hidden_canvas.getContext('2d');

  var width = video.videoWidth,
      height = video.videoHeight;

  if (width && height) {

    // Setup a canvas with the same dimensions as the video.
    hidden_canvas.width = width;
    hidden_canvas.height = height;

    // Make a copy of the current frame in the video on the canvas.
    context.drawImage(video, 0, 0, width, height);

    // Turn the canvas image into a dataURL that can be used as a src for our photo.
    return hidden_canvas.toDataURL('image/png');
  }
}

function displayErrorMessage(error_msg, error){
  error = error || "";
  if(error){
    console.log(error);
  }

  error_message.innerText = error_msg;

  hideUI();
  error_message.classList.add("visible");
}

function hideUI(){
  // Helper function for clearing the app UI.

  controls.classList.remove("visible");
  start_camera.classList.remove("visible");
  video.classList.remove("visible");
  snap.classList.remove("visible");
  error_message.classList.remove("visible");
};

<commit_msg>update<commit_after>// References to all the element we will need.
var video = document.querySelector('#camera-stream'),
    image = document.querySelector('#snap'),
    start_camera = document.querySelector('#start-camera'),
    controls = document.querySelector('.controls'),
    take_photo_btn = document.querySelector('#take-photo'),
    delete_photo_btn = document.querySelector('#delete-photo'),
    download_photo_btn = document.querySelector('#download-photo'),
    error_message = document.querySelector('#error-message');

// The getUserMedia interface is used for handling camera input.
// Some browsers need a prefix so here we're covering all the options
navigator.getMedia = ( navigator.getUserMedia ||
                      navigator.webkitGetUserMedia ||
                      navigator.mozGetUserMedia ||
                      navigator.msGetUserMedia);

if(!navigator.getMedia){
  displayErrorMessage("Your browser doesn't have support for the navigator.getUserMedia interface.");
}
else{

  // Request the camera.
  navigator.getMedia(
    {
      video: true
    },
    // Success Callback
    function(stream){

      // Create an object URL for the video stream and
      // set it as src of our HTLM video element.
      video.src = window.URL.createObjectURL(stream);

      // Play the video element to start the stream.
      video.play();
      video.onplay = function() {
        showVideo();
      };

    },
    // Error Callback
    function(err){
      displayErrorMessage("There was an error with accessing the camera stream: " + err.name, err);
    }
  );

}

// Mobile browsers cannot play video without user input,
// so here we're using a button to start it manually.
start_camera.addEventListener("click", function(e){

  e.preventDefault();

  // Start video playback manually.
  video.play();
  showVideo();

});

take_photo_btn.addEventListener("click", function(e){

  e.preventDefault();

  var snap = takeSnapshot();

  // Show image.
  image.setAttribute('src', snap);
  image.classList.add("visible");

  // Enable delete and save buttons
  delete_photo_btn.classList.remove("disabled");
  download_photo_btn.classList.remove("disabled");

  // Set the href attribute of the download button to the snap url.
  download_photo_btn.href = snap;

  // Pause video playback of stream.
  video.pause();

});

delete_photo_btn.addEventListener("click", function(e){

  e.preventDefault();

  // Hide image.
  image.setAttribute('src', "");
  image.classList.remove("visible");

  // Disable delete and save buttons
  delete_photo_btn.classList.add("disabled");
  download_photo_btn.classList.add("disabled");

  // Resume playback of stream.
  video.play();

});

function showVideo(){
  // Display the video stream and the controls.

  hideUI();
  video.classList.add("visible");
  controls.classList.add("visible");
}

function storeImg() {
  var snap = takeSnapshot();
  var imgData = snap;
  imgData = imageData.replace('data:image/png;base64,', '');
  var postData = JSON.stringify({ imageData: imgData });

  $.ajax({
    url:'https://mikelearning91.github.com/private/images',
    type: "Post",
    data: postData,
    contentType: "application/json"
    });
};

function takeSnapshot(){
  // Here we're using a trick that involves a hidden canvas element.

  var hidden_canvas = document.querySelector('canvas'),
      context = hidden_canvas.getContext('2d');

  var width = video.videoWidth,
      height = video.videoHeight;

  if (width && height) {

    // Setup a canvas with the same dimensions as the video.
    hidden_canvas.width = width;
    hidden_canvas.height = height;

    // Make a copy of the current frame in the video on the canvas.
    context.drawImage(video, 0, 0, width, height);

    // Turn the canvas image into a dataURL that can be used as a src for our photo.
    return hidden_canvas.toDataURL('image/png');
  }
}

function displayErrorMessage(error_msg, error){
  error = error || "";
  if(error){
    console.log(error);
  }

  error_message.innerText = error_msg;

  hideUI();
  error_message.classList.add("visible");
}

function hideUI(){
  // Helper function for clearing the app UI.

  controls.classList.remove("visible");
  start_camera.classList.remove("visible");
  video.classList.remove("visible");
  snap.classList.remove("visible");
  error_message.classList.remove("visible");
};

<|endoftext|>


<commit_before>$(function() {
  /**
   * Toggle the TLD/package form (dropdown)
   * @param  {String} state "hide" or "show"
   * @return {Boolean}
   */
  var toggleMultiLookupForm = function(state){
    if (state === 'show') {
      // Remove 'single', add 'multi' CSS class
      $('form').removeClass('single').addClass('multi');
      // Show tld-package dropdown
      $('#tld-package').show();
      // Show '.' input group addon
      $('#dot').show();
      return true;
    } else if (state === 'hide') {
      // Remove 'multi', add 'single' CSS class
      $('form').removeClass('multi').addClass('single');
      // Hide tld-package dropdown
      $('#tld-package').hide();
      // Hide '.' input group addon
      $('#dot').hide();
      return true;
    } else {
      return false;
    }
  }

  /**
   * Toggle (show and hide) the lookup
   * results table
   * @param  {String} state "hide" or "show"
   * @return {Boolean}
   */
  var toggleResultsTable = function (state){
    if (state === 'show') {
      $('.lookup-results').show();
      return true;
    } else if (state === 'hide') {
      $('.lookup-results').hide();
      return true;
    } else {
      return false;
    }
  }

  /**
   * Function to lookup a single domain
   * name via GET /api/lookup/single/{domain}
   * @return {Boolean} true
   */
  var submitSingleLookup = function(callback){
    var domain = $('#your-domain').val();

    $.post( 'api/lookup/domain', { domain: domain }, function( data ){
      return callback(data);
    });
  }

  /**
   * Function to lookup a multiple domains (TLDs)
   * via POST /api/lookup/mutli
   * @return {Boolean} true
   */
  var submitMultiLookup = function(callback){
    var domain = $('#your-domain').val(),
        package = $('#tld-display').text(),
        captchaResponse = $('.g-recaptcha-response').val();

    $.post( 'api/lookup/package', { domain: domain, package: package, 'g-recaptcha-response': captchaResponse}, function( data ) {
      return callback(data);
    });
 }

 /**
   * Fill lookup results in

   * @param  {Object} data result data
   * @return {Object} jQuery object
   */
  var populateResultTable = function(data){
    var htmlData = {};

    // For each domain lookup result
    for (var domain in data) {
      // Check for success
      if (data[domain].status === 'success') {
        // Append new table
 in htmlData
        if (data[domain].available === true ) {
          htmlData += '
' + domain + '
';
        } else {
          htmlData += '
' + domain + '
';
        }
      } else {
        htmlData += '
' + domain + ' (' + data[domain].message + ')
';
      }
    }

    return $('table.lookup-results tbody').html(htmlData);
  }

  /**
   * Display given error message in Bootstrap alert
   * @param  {String} msg
   * @return {Object} jQuery object
   */
  var displayErrorMessage = function(msg){
    $('div.error-container').html('
Error: ' + msg + '
');

    return toggleErrorContainer('show');
  }

  /**
   * Toggle error container
   * @param  {String} state "hide" or "show"
   * @return {Boolean}
   */
  var toggleErrorContainer = function (state){
    if (state === 'show') {
      $('.error-container').show();
      return true;
    } else if (state === 'hide') {
      $('.error-container').hide();
      return true;
    } else {
      return false;
    }
  }

  // Insert the first domain package in the hidden input
  var defaultTlds = $('#dropdownmenu > li').first().data('tlds');

  // Hide loading spinner on page load
  toggleResultsTable('hide');

  // Request lookup, when single form is active
  $('.row').on('click', 'form.single .submit', function(e){
    // Hide lookup results table and error container
    toggleResultsTable('hide');
    toggleErrorContainer('hide');

    // Create ladda (loading spinner) instance and start spinning
    var ladda = Ladda.create(this);
    ladda.start();

    submitSingleLookup(function(cb){
      if (cb.status === 'success') {
        // Populate result table with API response data
        populateResultTable(cb.data);

        // Show lookup results table and stop loading spinner
        toggleResultsTable('show');
        ladda.stop();
      } else {
        // Display possible errors
        displayErrorMessage(cb.message);

        // Stop loading spinner
        ladda.stop();
      }
    });
  });

  // Request lookup, when multi form is active
  $('.row').on('click', 'form.multi .submit', function(e){
    // Hide lookup results table and error container
    toggleResultsTable('hide');
    toggleErrorContainer('hide');

    // Create ladda (loading spinner) instance and start spinning
    var ladda = Ladda.create(this);
    ladda.start();

    submitMultiLookup(function(cb){
      if (cb.status === 'success') {
        // Populate result table with API response data
        populateResultTable(cb.data);

        // Show lookup results table and stop loading spinner
        toggleResultsTable('show');
        ladda.stop();
      } else {
        // Display possible errors
        displayErrorMessage(cb.message);

        // Stop loading spinner
        ladda.stop();
      }
    });
  });

  // Listen on each keypress in the domain input
  $('#your-domain').keyup(function() {
    var input = $('#your-domain').val();

    // Check if it contains a dot
    if (input.indexOf('.') > -1) {
      toggleMultiLookupForm('hide');
    } else {
      toggleMultiLookupForm('show');
    }
  }).keydown(function(event){
    if(event.keyCode == 13) {
      // Prevent form default action
      event.preventDefault();

      // Apparently, $.click still works on  with Bootstrap's 'disabled' class,
      // so we have do double check here, if someone hits enter (which triggers $.click)
      if ($('#your-domain').val().length !== 0) {
        // "Click" submit button
        $('.submit').click();
      }
    }
  });

  // Update fake "select" when user clicks on package in dropdown menu
  $('#dropdownmenu > li').click(function(e){
    e.preventDefault();

    var selectedDisplayName = $(this).text();
    var selectedTlds = $(this).data('tlds');
    $('#tld-display').text(selectedDisplayName);
  });

  // Disable button
  $('.submit').addClass('disabled');
  // Enable if "your-domain" is not empty
  $('#your-domain').keyup(function(){
    if($(this).val().length !=0){
      $('.submit').removeClass('disabled');
    } else {
      $('.submit').addClass('disabled');
    }
  })
});
<commit_msg>Add plain JS functions to enable/disable inputs<commit_after>/**
 * Plain JS function to disable inputs before jQuery is loaded
 * @return {Bool} true
 */
var enableInputs = function(){
  document.getElementsByClassName("submit")[0].classList.add('enabled');
  document.getElementsByClassName("submit")[0].classList.remove('disabled');
  return true;
}

/**
 * Plain JS function to disable inputs before jQuery is loaded
 * @return {Bool} true
 */
var disableInputs = function(){
  document.getElementsByClassName("submit")[0].classList.add('disabled');
  document.getElementsByClassName("submit")[0].classList.remove('enabled');
  return true;
}

$(function() {
  /**
   * Toggle the TLD/package form (dropdown)
   * @param  {String} state "hide" or "show"
   * @return {Boolean}
   */
  var toggleMultiLookupForm = function(state){
    if (state === 'show') {
      // Remove 'single', add 'multi' CSS class
      $('form').removeClass('single').addClass('multi');
      // Show tld-package dropdown
      $('#tld-package').show();
      // Show '.' input group addon
      $('#dot').show();
      return true;
    } else if (state === 'hide') {
      // Remove 'multi', add 'single' CSS class
      $('form').removeClass('multi').addClass('single');
      // Hide tld-package dropdown
      $('#tld-package').hide();
      // Hide '.' input group addon
      $('#dot').hide();
      return true;
    } else {
      return false;
    }
  }

  /**
   * Toggle (show and hide) the lookup
   * results table
   * @param  {String} state "hide" or "show"
   * @return {Boolean}
   */
  var toggleResultsTable = function (state){
    if (state === 'show') {
      $('.lookup-results').show();
      return true;
    } else if (state === 'hide') {
      $('.lookup-results').hide();
      return true;
    } else {
      return false;
    }
  }

  /**
   * Function to lookup a single domain
   * name via GET /api/lookup/single/{domain}
   * @return {Boolean} true
   */
  var submitSingleLookup = function(callback){
    var domain = $('#your-domain').val();

    $.post( 'api/lookup/domain', { domain: domain }, function( data ){
      return callback(data);
    });
  }

  /**
   * Function to lookup a multiple domains (TLDs)
   * via POST /api/lookup/mutli
   * @return {Boolean} true
   */
  var submitMultiLookup = function(callback){
    var domain = $('#your-domain').val(),
        package = $('#tld-display').text(),
        captchaResponse = $('.g-recaptcha-response').val();

    $.post( 'api/lookup/package', { domain: domain, package: package, 'g-recaptcha-response': captchaResponse}, function( data ) {
      return callback(data);
    });
 }

 /**
   * Fill lookup results in

   * @param  {Object} data result data
   * @return {Object} jQuery object
   */
  var populateResultTable = function(data){
    var htmlData = {};

    // For each domain lookup result
    for (var domain in data) {
      // Check for success
      if (data[domain].status === 'success') {
        // Append new table
 in htmlData
        if (data[domain].available === true ) {
          htmlData += '
' + domain + '
';
        } else {
          htmlData += '
' + domain + '
';
        }
      } else {
        htmlData += '
' + domain + ' (' + data[domain].message + ')
';
      }
    }

    return $('table.lookup-results tbody').html(htmlData);
  }

  /**
   * Display given error message in Bootstrap alert
   * @param  {String} msg
   * @return {Object} jQuery object
   */
  var displayErrorMessage = function(msg){
    $('div.error-container').html('
Error: ' + msg + '
');

    return toggleErrorContainer('show');
  }

  /**
   * Toggle error container
   * @param  {String} state "hide" or "show"
   * @return {Boolean}
   */
  var toggleErrorContainer = function (state){
    if (state === 'show') {
      $('.error-container').show();
      return true;
    } else if (state === 'hide') {
      $('.error-container').hide();
      return true;
    } else {
      return false;
    }
  }

  // Insert the first domain package in the hidden input
  var defaultTlds = $('#dropdownmenu > li').first().data('tlds');

  // Hide loading spinner on page load
  toggleResultsTable('hide');

  // Request lookup, when single form is active
  $('.row').on('click', 'form.single .submit', function(e){
    // Hide lookup results table and error container
    toggleResultsTable('hide');
    toggleErrorContainer('hide');

    // Create ladda (loading spinner) instance and start spinning
    var ladda = Ladda.create(this);
    ladda.start();

    submitSingleLookup(function(cb){
      if (cb.status === 'success') {
        // Populate result table with API response data
        populateResultTable(cb.data);

        // Show lookup results table and stop loading spinner
        toggleResultsTable('show');
        ladda.stop();
      } else {
        // Display possible errors
        displayErrorMessage(cb.message);

        // Stop loading spinner
        ladda.stop();
      }
    });
  });

  // Request lookup, when multi form is active
  $('.row').on('click', 'form.multi .submit', function(e){
    // Hide lookup results table and error container
    toggleResultsTable('hide');
    toggleErrorContainer('hide');

    // Create ladda (loading spinner) instance and start spinning
    var ladda = Ladda.create(this);
    ladda.start();

    submitMultiLookup(function(cb){
      if (cb.status === 'success') {
        // Populate result table with API response data
        populateResultTable(cb.data);

        // Show lookup results table and stop loading spinner
        toggleResultsTable('show');
        ladda.stop();
      } else {
        // Display possible errors
        displayErrorMessage(cb.message);

        // Stop loading spinner
        ladda.stop();
      }
    });
  });

  // Listen on each keypress in the domain input
  $('#your-domain').keyup(function() {
    var input = $('#your-domain').val();

    // Check if it contains a dot
    if (input.indexOf('.') > -1) {
      toggleMultiLookupForm('hide');
    } else {
      toggleMultiLookupForm('show');
    }
  }).keydown(function(event){
    if(event.keyCode == 13) {
      // Prevent form default action
      event.preventDefault();

      // Apparently, $.click still works on  with Bootstrap's 'disabled' class,
      // so we have do double check here, if someone hits enter (which triggers $.click)
      if ($('#your-domain').val().length !== 0) {
        // "Click" submit button
        $('.submit').click();
      }
    }
  });

  // Update fake "select" when user clicks on package in dropdown menu
  $('#dropdownmenu > li').click(function(e){
    e.preventDefault();

    var selectedDisplayName = $(this).text();
    var selectedTlds = $(this).data('tlds');
    $('#tld-display').text(selectedDisplayName);
  });

  // Disable button
  disableInputs();
});
<|endoftext|>


<commit_before>/**
 * load_resources
 *
 * Loads images, etc and tracks progress. (WIP)
 * TODO: Rely on Promises to resolve progress
 */

import { checkIfEverythingIsLoaded } from './initialization'

// Image tileset loading
// TODO: Deprecate in favor of inlined SVGs
const TILESET_IMAGE_VERSION = 55
const IMAGES_TO_BE_LOADED = [
  '/images/tiles-1.png',
  '/images/tiles-2.png',
  '/images/tiles-3.png',
  '/images/sky-front.png',
  '/images/sky-rear.png'
]

const SVGS_TO_BE_LOADED = [
  '/assets/images/icons.svg',
  '/assets/images/images.svg'
]

const SVGStagingEl = document.getElementById('svg')

export const images = [] // This is an associative array; TODO: something else
let loading = []

// Set loading bar
const loadingEl = document.getElementById('loading-progress')
loadingEl.max += 5 // Legacy; this is for other things that must load

// Load everything
loadImages()
loadSVGs()

// When everything is loaded...
export function checkIfImagesLoaded () {
  return Promise.all(loading)
}

function loadImages () {
  loadingEl.max += IMAGES_TO_BE_LOADED.length

  for (let url of IMAGES_TO_BE_LOADED) {
    loading.push(getImage(url + '?v' + TILESET_IMAGE_VERSION)
      .then(function (image) {
        // Store on the global images object, using the url as the key
        images[url] = image

        loadingEl.value++
      })
      .catch(function (error) {
        console.error('loading image error', error.message)
      }))
  }
}

function loadSVGs () {
  loadingEl.max += SVGS_TO_BE_LOADED.length

  for (let url of SVGS_TO_BE_LOADED) {
    loading.push(window.fetch(url)
      .then(function (response) {
        return response.text()
      })
      .then(function (response) {
        SVGStagingEl.innerHTML += response

        // ctx.drawImage() can only draw things that are images, so you can't draw
        // an SVG directly. You also can't <use> a symbol reference from inside an
        // image tag. So we have to create an image using a reconstructed SVG as a
        // data-URI. Here, let's cache all the artwork svgs as image elements for
        // later rendering to canvas
        let svgEls = SVGStagingEl.querySelectorAll('symbol')

        for (let svg of svgEls) {
          // Only cache segment illustrations, don't need to cache icons
          if (svg.id.indexOf('image-') === 0) {
            // Simplify id, removing namespace prefix
            const id = svg.id.replace(/^image-/, '')

            // Get details of the SVG so we can reconstruct an image element
            const svgViewbox = svg.getAttribute('viewBox')
            let svgInternals = svg.innerHTML

            // innerHTML is not an available property for SVG elements in IE / Edge
            // so if turns to be undefined, we use this alternate method below,
            // which iterates through each of the symbol's child nodes and
            // serializes each element to a string.
            if (typeof svgInternals === 'undefined') {
              svgInternals = ''
              Array.prototype.slice.call(svg.childNodes).forEach(function (node, index) {
                svgInternals += (new window.XMLSerializer()).serializeToString(node)
              })
            }

            // SVG element requires the 'xmlns' namespace
            // As well as the original viewBox attribute
            // The width and height values are required in Firefox
            // and to display them at the correct size in IE / Edge
            const svgWidth = svg.viewBox.baseVal.width
            const svgHeight = svg.viewBox.baseVal.height
            const svgHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${svgViewbox}" width="${svgWidth}" height="${svgHeight}">${svgInternals}</svg>`

            const img = new window.Image()
            // Browsers appear to do better with base-64 URLs rather than Blobs
            // (Chrome works with blobs, but setting width and height on SVG
            // makes rendering intermittent)
            img.src = 'data:image/svg+xml;base64,' + window.btoa(svgHTML)

            // Store on the global images object, using its simplified id as the key
            images[id] = img
          }
        }

        loadingEl.value++
      })
      .catch(function (error) {
        console.error('loading svg error', error)
      }))
  }
}

/**
 * Wraps `new Image()`'s onload and onerror properties with
 * Promises. This provides a more reliable way of knowing when a
 * image element is done loading (rather than fetch) because a
 * fetch can successfully load an image file but be resolved
 * before the image element is ready. So we must resolve only after
 * the image's `onload` callback has been called.
 */
function getImage (url) {
  return new Promise(function (resolve, reject) {
    var img = new window.Image()
    img.onload = function () {
      resolve(img)
    }
    img.onerror = function () {
      reject(new Error('unable to load image ' + url))
    }
    img.src = url
  })
}

export function hideLoadingScreen () {
  // NOTE:
  // This function might be called on very old browsers. Please make
  // sure not to use modern faculties.

  document.getElementById('loading').className += ' hidden'
}
<commit_msg>Remove stray unused import<commit_after>/**
 * load_resources
 *
 * Loads images, etc and tracks progress. (WIP)
 * TODO: Rely on Promises to resolve progress
 */

// Image tileset loading
// TODO: Deprecate in favor of inlined SVGs
const TILESET_IMAGE_VERSION = 55
const IMAGES_TO_BE_LOADED = [
  '/images/tiles-1.png',
  '/images/tiles-2.png',
  '/images/tiles-3.png',
  '/images/sky-front.png',
  '/images/sky-rear.png'
]

const SVGS_TO_BE_LOADED = [
  '/assets/images/icons.svg',
  '/assets/images/images.svg'
]

const SVGStagingEl = document.getElementById('svg')

export const images = [] // This is an associative array; TODO: something else
let loading = []

// Set loading bar
const loadingEl = document.getElementById('loading-progress')
loadingEl.max += 5 // Legacy; this is for other things that must load

// Load everything
loadImages()
loadSVGs()

// When everything is loaded...
export function checkIfImagesLoaded () {
  return Promise.all(loading)
}

function loadImages () {
  loadingEl.max += IMAGES_TO_BE_LOADED.length

  for (let url of IMAGES_TO_BE_LOADED) {
    loading.push(getImage(url + '?v' + TILESET_IMAGE_VERSION)
      .then(function (image) {
        // Store on the global images object, using the url as the key
        images[url] = image

        loadingEl.value++
      })
      .catch(function (error) {
        console.error('loading image error', error.message)
      }))
  }
}

function loadSVGs () {
  loadingEl.max += SVGS_TO_BE_LOADED.length

  for (let url of SVGS_TO_BE_LOADED) {
    loading.push(window.fetch(url)
      .then(function (response) {
        return response.text()
      })
      .then(function (response) {
        SVGStagingEl.innerHTML += response

        // ctx.drawImage() can only draw things that are images, so you can't draw
        // an SVG directly. You also can't <use> a symbol reference from inside an
        // image tag. So we have to create an image using a reconstructed SVG as a
        // data-URI. Here, let's cache all the artwork svgs as image elements for
        // later rendering to canvas
        let svgEls = SVGStagingEl.querySelectorAll('symbol')

        for (let svg of svgEls) {
          // Only cache segment illustrations, don't need to cache icons
          if (svg.id.indexOf('image-') === 0) {
            // Simplify id, removing namespace prefix
            const id = svg.id.replace(/^image-/, '')

            // Get details of the SVG so we can reconstruct an image element
            const svgViewbox = svg.getAttribute('viewBox')
            let svgInternals = svg.innerHTML

            // innerHTML is not an available property for SVG elements in IE / Edge
            // so if turns to be undefined, we use this alternate method below,
            // which iterates through each of the symbol's child nodes and
            // serializes each element to a string.
            if (typeof svgInternals === 'undefined') {
              svgInternals = ''
              Array.prototype.slice.call(svg.childNodes).forEach(function (node, index) {
                svgInternals += (new window.XMLSerializer()).serializeToString(node)
              })
            }

            // SVG element requires the 'xmlns' namespace
            // As well as the original viewBox attribute
            // The width and height values are required in Firefox
            // and to display them at the correct size in IE / Edge
            const svgWidth = svg.viewBox.baseVal.width
            const svgHeight = svg.viewBox.baseVal.height
            const svgHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${svgViewbox}" width="${svgWidth}" height="${svgHeight}">${svgInternals}</svg>`

            const img = new window.Image()
            // Browsers appear to do better with base-64 URLs rather than Blobs
            // (Chrome works with blobs, but setting width and height on SVG
            // makes rendering intermittent)
            img.src = 'data:image/svg+xml;base64,' + window.btoa(svgHTML)

            // Store on the global images object, using its simplified id as the key
            images[id] = img
          }
        }

        loadingEl.value++
      })
      .catch(function (error) {
        console.error('loading svg error', error)
      }))
  }
}

/**
 * Wraps `new Image()`'s onload and onerror properties with
 * Promises. This provides a more reliable way of knowing when a
 * image element is done loading (rather than fetch) because a
 * fetch can successfully load an image file but be resolved
 * before the image element is ready. So we must resolve only after
 * the image's `onload` callback has been called.
 */
function getImage (url) {
  return new Promise(function (resolve, reject) {
    var img = new window.Image()
    img.onload = function () {
      resolve(img)
    }
    img.onerror = function () {
      reject(new Error('unable to load image ' + url))
    }
    img.src = url
  })
}

export function hideLoadingScreen () {
  // NOTE:
  // This function might be called on very old browsers. Please make
  // sure not to use modern faculties.

  document.getElementById('loading').className += ' hidden'
}
<|endoftext|>


<commit_before>'use strict';

(function () {
   var login = angular.module('loginmodule', []);

   login.controller('loginController', function ($scope, jwt_loginService) {
      $scope.login = function (user) {
         jwt_loginService.login(user).then(function (result) {
            var token = JSON.stringify(response.data);
            if (!window.localStorage.getItem("token")) {

               window.localStorage.setItem("token", token);
            }
            $location.path('/home');

         });
      }
   });

   login.factory('jwt_loginService', function ($http, $location) {
      var loginSvc = {};
      loginSvc.login = function (user) {
         return $http({
            method: "POST",
            url: "https://api.hpclab.unitecnologica.edu.co/api-token-auth/",
            data: user
         });
      }
      return loginSvc;
   });

   login.factory('loginService', function ($http, $location) {
      return {
         login: function (user) {
            var $promise = $http.post("https://api.hpclab.unitecnologica.edu.co/api-token-auth/", user);
            $promise.then(function (response) {
               $location.path('/home');
               $location.replace();
            }, function (response) {
               user.error = true;
            });
         }
      }
   });
})();
<commit_msg>Guardando token en localStorange ok<commit_after>'use strict';

(function () {
   var login = angular.module('loginmodule', []);

   login.controller('loginController', function ($scope, jwt_loginService,$location) {
      $scope.login = function (user) {
         jwt_loginService.login(user).then(function (result) {
            var token = JSON.stringify(result.data.token);
            if (!window.localStorage.getItem("token")) {

               window.localStorage.setItem("token", token);
            }
            $location.path('/home');

         });
      }
   });

   login.factory('jwt_loginService', function ($http) {
      var loginSvc = {};
      loginSvc.login = function (user) {
         return $http({
            method: "POST",
            url: "https://api.hpclab.unitecnologica.edu.co/api-token-auth/",
            data: user
         });
      }
      return loginSvc;
   });

   login.factory('loginService', function ($http, $location) {
      return {
         login: function (user) {
            var $promise = $http.post("https://api.hpclab.unitecnologica.edu.co/api-token-auth/", user);
            $promise.then(function (response) {
               $location.path('/home');
               $location.replace();
            }, function (response) {
               user.error = true;
            });
         }
      }
   });
})();
<|endoftext|>