<commit_before>var Calendar = new Class({
	Implements: [Events, Options],
    getOptions: function() {
        var today = new Date;
        return {
            currYear: today.getFullYear(),
            currMonth: today.getMonth() + 1,
            currDay: today.getDate(),
            year: null,
            month: null,
            day: null,
            minYear: 1,
            maxYear: 9999,
            minMonth: 1,
            maxMonth: 12,
            weekdayNames: ['Пн','Вт','Ср','Чт','Пт','Сб','Вс'],
            monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
            onSelect: $empty,
            fieldName: null
        };
    },

    initialize: function(options) {
        Asset.css('calendar.css');
        this.options = this.getOptions();
        this.setOptions(options);

        this.year = $pick(this.options.year, this.options.currYear);
        this.month = $pick(this.options.month, this.options.currMonth);
        this.day = $pick(this.options.month, this.options.currMonth);

        this.element = new Element('table').setProperties({ 'cellSpacing': '1' }).addClass('calendar');
        var thead = new Element('thead').injectInside(this.element);
        var tbody = new Element('tbody').injectInside(this.element);

        new Element('tr').adopt(new Element('th').setProperties({ 'id': 'calendar_prevMonth' }).addEvent('click', this.prevMonth.bind(this)))
            .adopt(this.monthName = new Element('th').setProperties({ 'colSpan': '5' }))
            .adopt(new Element('th').setProperties({ 'id': 'calendar_nextMonth' }).addEvent('click', this.nextMonth.bind(this)))
            .injectInside(thead);

        var weekdays = new Element('tr').addClass('weekdays').injectInside(thead);
        this.options.weekdayNames.each(function(weekdayName) {
            new Element('th').appendText(weekdayName).injectInside(weekdays);
        });

        var selectDateListener = this.selectDate.bindWithEvent(this);
        var toggleHighlightListener = this.toggleHighlight.bindWithEvent(this);

        this.monthGrid = [];
        for (var i = 0; i < 6; i++) {
            var week = [];
            var row = new Element('tr').injectInside(tbody);
            for (var j = 0; j < 7; j++) {
                var day = new Element('td').injectInside(row);
                day.addEvents({
                    'click': selectDateListener,
                    'mouseover': toggleHighlightListener,
                    'mouseout': toggleHighlightListener
                });
                week.push(day);
            }
            this.monthGrid.push(week);
        }
        this.build();
    },

    build: function() {
        this.monthName.set('html', this.options.monthNames[this.month - 1]+' '+this.year);

        var isCurrMonth = (this.year == this.options.currYear && this.month == this.options.currMonth);
        var daysInMonth = this.getDaysInMonth(this.year, this.month);
        var monthFirstWeekday = this.getWeekday(this.year, this.month, 1);
        for (var i = 1; i <= 42; i++) { // 6 weeks * 7 days
            var day = this.monthGrid[(Math.ceil(i / 7) - 1)][((i - 1) % 7)];
            day.set('html', '').className = '';
            var dayNum = i - monthFirstWeekday + 1;
            if (0 < dayNum && dayNum <= daysInMonth) {
                day.set('html', dayNum).addClass('thisMonth');
                if (isCurrMonth && dayNum == this.options.currDay) day.addClass('currDay');
            }
            else day.addClass('otherMonth');
        }
    },

    destroy: function() {
        this.element.dispose();
        delete FormCalendar.calendars[this.options.fieldName];
    },

    selectDate: function(event) {
        if (!event.target.hasClass('thisMonth')) return;
        var day = event.target.innerHTML.toInt();
        this.fireEvent('onSelect', { year: this.year, month: this.month, day: day });
        this.destroy();
    },

    toggleHighlight: function(event) {
        if (event.target.hasClass('thisMonth')) {
            event.target.toggleClass('highlighted');
        }
    },

    changeMonth: function(direction) {
        switch (direction) {
            case 'prev':
                if (this.year == this.options.minYear) {
                    if (this.month == this.options.minMonth) return;
                    this.month--;
                }
                else {
                    if (this.month == 1) {
                        this.month = 12;
                        this.year--;
                    }
                    else this.month--;
                }
                break;
            case 'next':
                if (this.year == this.options.maxYear) {
                    if (this.month == this.options.maxMonth) return;
                    this.month++;
                }
                else {
                    if (this.month == 12) {
                        this.month = 1;
                        this.year++;
                    }
                    else this.month++;
                }
                break;
            default:
                return;
        }
        this.build();
    },

    prevMonth: function() { this.changeMonth('prev'); },
    nextMonth: function() { this.changeMonth('next'); },

    getDaysInMonth: function(year, month) {
        switch (month) {
            case 1: case 3: case 5: case 7: case 8: case 10: case 12:
                return 31; break;
            case 4: case 6: case 9: case 11:
                return 30; break;
            case 2:
                return (this.year % 4 == 0 && (this.year % 100 != 0 || this.year % 400 == 0)) ? 29 : 28; break;
            default: // not reached
        }
    },

    getWeekday: function(year, month, day) {
        var date = new Date(year, month - 1, day);
        return (date.getDay() || 7);
    }
});

var FormCalendar = {
	setDate: function(fieldName){
		var getDateString = function(date, destinationField){
			new Request(
				{
					url: this.singlePath + 'format-date/',
					method: 'post',
					onSuccess: function(responseText){
						$(destinationField).set('value', JSON.decode(responseText));
					}
				}
			).send(new Hash({'date':date}).toQueryString());
		}.bind(this);

		getDateString($(fieldName).get('value'), 'date_'+fieldName);
	},
	showCalendar: function(fieldName, event) {
	    if (FormCalendar.calendars[fieldName]) return;
	    var field = $(fieldName);
	    var calendOptions = {
	        fieldName: fieldName,
	        onSelect: function(date) {
	            field.value = date.year+'-'+date.month+'-'+date.day;
	            this.setDate(fieldName);
	        }.bind(this)
	    };
	    var currDate = field.get('value');
	    if (currDate != '') {
	        currDate = currDate.split('-', 3);
	        calendOptions = $extend(calendOptions, {
	            currYear: parseInt(currDate[0]),
	            currMonth: parseInt(currDate[1]),
	            currDay: parseInt(currDate[2])
	        });
	    }
	    var calend = new Calendar(calendOptions);
	    FormCalendar.calendars[fieldName] = calend;

	    var target = event.target || $(window.event.srcElement);

	    calend.element.setStyles(
	    	{
	    		position: 'absolute',
	    		top: target.getTop((document.body.getElement('.pane'))?[document.body.getElement('.pane')]:[])+'px',
	    		left: target.getLeft((document.body.getElement('.pane'))?[document.body.getElement('.pane')]:[])+'px'
	    	}
	    ).injectInside(document.body);
	},
	calendars:{}
};
<commit_msg>Исправлен глюк с позиционированием календарика  в ИЕ<commit_after>var Calendar = new Class({
	Implements: [Events, Options],
    getOptions: function() {
        var today = new Date;
        return {
            currYear: today.getFullYear(),
            currMonth: today.getMonth() + 1,
            currDay: today.getDate(),
            year: null,
            month: null,
            day: null,
            minYear: 1,
            maxYear: 9999,
            minMonth: 1,
            maxMonth: 12,
            weekdayNames: ['Пн','Вт','Ср','Чт','Пт','Сб','Вс'],
            monthNames: ['Январь','Февраль','Март','Апрель','Май','Июнь','Июль','Август','Сентябрь','Октябрь','Ноябрь','Декабрь'],
            onSelect: $empty,
            fieldName: null
        };
    },

    initialize: function(options) {
        Asset.css('calendar.css');
        this.options = this.getOptions();
        this.setOptions(options);

        this.year = $pick(this.options.year, this.options.currYear);
        this.month = $pick(this.options.month, this.options.currMonth);
        this.day = $pick(this.options.month, this.options.currMonth);

        this.element = new Element('table').setProperties({ 'cellSpacing': '1' }).addClass('calendar');
        var thead = new Element('thead').injectInside(this.element);
        var tbody = new Element('tbody').injectInside(this.element);

        new Element('tr').adopt(new Element('th').setProperties({ 'id': 'calendar_prevMonth' }).addEvent('click', this.prevMonth.bind(this)))
            .adopt(this.monthName = new Element('th').setProperties({ 'colSpan': '5' }))
            .adopt(new Element('th').setProperties({ 'id': 'calendar_nextMonth' }).addEvent('click', this.nextMonth.bind(this)))
            .injectInside(thead);

        var weekdays = new Element('tr').addClass('weekdays').injectInside(thead);
        this.options.weekdayNames.each(function(weekdayName) {
            new Element('th').appendText(weekdayName).injectInside(weekdays);
        });

        var selectDateListener = this.selectDate.bindWithEvent(this);
        var toggleHighlightListener = this.toggleHighlight.bindWithEvent(this);

        this.monthGrid = [];
        for (var i = 0; i < 6; i++) {
            var week = [];
            var row = new Element('tr').injectInside(tbody);
            for (var j = 0; j < 7; j++) {
                var day = new Element('td').injectInside(row);
                day.addEvents({
                    'click': selectDateListener,
                    'mouseover': toggleHighlightListener,
                    'mouseout': toggleHighlightListener
                });
                week.push(day);
            }
            this.monthGrid.push(week);
        }
        this.build();
    },

    build: function() {
        this.monthName.set('html', this.options.monthNames[this.month - 1]+' '+this.year);

        var isCurrMonth = (this.year == this.options.currYear && this.month == this.options.currMonth);
        var daysInMonth = this.getDaysInMonth(this.year, this.month);
        var monthFirstWeekday = this.getWeekday(this.year, this.month, 1);
        for (var i = 1; i <= 42; i++) { // 6 weeks * 7 days
            var day = this.monthGrid[(Math.ceil(i / 7) - 1)][((i - 1) % 7)];
            day.set('html', '').className = '';
            var dayNum = i - monthFirstWeekday + 1;
            if (0 < dayNum && dayNum <= daysInMonth) {
                day.set('html', dayNum).addClass('thisMonth');
                if (isCurrMonth && dayNum == this.options.currDay) day.addClass('currDay');
            }
            else day.addClass('otherMonth');
        }
    },

    destroy: function() {
        this.element.dispose();
        delete FormCalendar.calendars[this.options.fieldName];
    },

    selectDate: function(event) {
        if (!event.target.hasClass('thisMonth')) return;
        var day = event.target.innerHTML.toInt();
        this.fireEvent('onSelect', { year: this.year, month: this.month, day: day });
        this.destroy();
    },

    toggleHighlight: function(event) {
        if (event.target.hasClass('thisMonth')) {
            event.target.toggleClass('highlighted');
        }
    },

    changeMonth: function(direction) {
        switch (direction) {
            case 'prev':
                if (this.year == this.options.minYear) {
                    if (this.month == this.options.minMonth) return;
                    this.month--;
                }
                else {
                    if (this.month == 1) {
                        this.month = 12;
                        this.year--;
                    }
                    else this.month--;
                }
                break;
            case 'next':
                if (this.year == this.options.maxYear) {
                    if (this.month == this.options.maxMonth) return;
                    this.month++;
                }
                else {
                    if (this.month == 12) {
                        this.month = 1;
                        this.year++;
                    }
                    else this.month++;
                }
                break;
            default:
                return;
        }
        this.build();
    },

    prevMonth: function() { this.changeMonth('prev'); },
    nextMonth: function() { this.changeMonth('next'); },

    getDaysInMonth: function(year, month) {
        switch (month) {
            case 1: case 3: case 5: case 7: case 8: case 10: case 12:
                return 31; break;
            case 4: case 6: case 9: case 11:
                return 30; break;
            case 2:
                return (this.year % 4 == 0 && (this.year % 100 != 0 || this.year % 400 == 0)) ? 29 : 28; break;
            default: // not reached
        }
    },

    getWeekday: function(year, month, day) {
        var date = new Date(year, month - 1, day);
        return (date.getDay() || 7);
    }
});

var FormCalendar = {
	setDate: function(fieldName){
		var getDateString = function(date, destinationField){
			new Request(
				{
					url: this.singlePath + 'format-date/',
					method: 'post',
					onSuccess: function(responseText){
						$(destinationField).set('value', JSON.decode(responseText));
					}
				}
			).send(new Hash({'date':date}).toQueryString());
		}.bind(this);

		getDateString($(fieldName).get('value'), 'date_'+fieldName);
	},
	showCalendar: function(fieldName, event) {
	    if (FormCalendar.calendars[fieldName]) return;
	    var field = $(fieldName);
	    var calendOptions = {
	        fieldName: fieldName,
	        onSelect: function(date) {
	            field.value = date.year+'-'+date.month+'-'+date.day;
	            this.setDate(fieldName);
	        }.bind(this)
	    };
	    var currDate = field.get('value');
	    if (currDate != '') {
	        currDate = currDate.split('-', 3);
	        calendOptions = $extend(calendOptions, {
	            currYear: parseInt(currDate[0]),
	            currMonth: parseInt(currDate[1]),
	            currDay: parseInt(currDate[2])
	        });
	    }
	    var calend = new Calendar(calendOptions);
	    FormCalendar.calendars[fieldName] = calend;

	    var target = $(event.target || window.event.srcElement);
        calend.element.inject(target, 'before').position({relativeTo:target, 'position':'upperleft'});
	},
	calendars:{}
};
<|endoftext|>


<commit_before>jQuery.githubContent = function(username, repo, callback) {
   jQuery.getJSON('https://api.github.com/repos/'+username+'/'+repo+'/contents?callback=?',callback)
}

function loadContent() {
    $.get("folders.JSON",function(data){
        $.each(data, function() {
            var node = $(".sample").clone();
            node.removeClass("sample");
            node.find("A").attr("href",(this.name) + "/");
            node.find("STRONG").text(this.name.substring(0,8));
            $("#list").append(node);
        });
    });
}

        <commit_msg>attempted background script fix<commit_after>jQuery.githubContent = function(username, repo, callback) {
   jQuery.getJSON('https://api.github.com/repos/'+username+'/'+repo+'/contents?callback=?',callback)
}

function loadContent() {
    $.get("folders.JSON",function(data){
        $.each(data.data, function() {
            var node = $(".sample").clone();
            node.removeClass("sample");
            node.find("A").attr("href",(this.name) + "/");
            node.find("STRONG").text(this.name.substring(0,8));
            $("#list").append(node);
        });
    });
}

        <|endoftext|>


<commit_before>var constants = {
    canvasWidth : 1000,
    canvasHeight : 200,

    numberOfSpaces : 20,

    colors : [
        0x6F3A19,
        0x88C8F3
    ]
}

function SimpleView(game_state) {
    this.game = game_state;
    this.tileViews = [];
    this.tokenViews = [];

    this.renderer = PIXI.autoDetectRenderer(constants.canvasWidth, constants.canvasHeight,
            {backgroundColor : 0x1099bb});

    document.body.appendChild(this.renderer.view);

    // create the root of the scene graph
    this.stage = new PIXI.Container();
};

SimpleView.prototype.drawBoard = function() {
    x_pos = 0;
    y_pos = 0;
    for (i = 0; i < this.game.board.spaces.length; i++) {
        tile = new PIXI.Graphics();
        tile.lineStyle(1, 0, 1);
        tile.drawRect(x_pos, y_pos, constants.canvasWidth / this.game.board.spaces.length, constants.canvasHeight);
        x_pos += constants.canvasWidth / this.game.board.spaces.length

        this.tileViews.push(tile);
        this.stage.addChild(tile);

    }

    this.drawTokens();

    this.drawMessage();
    this.animate();
}

SimpleView.prototype.drawToken = function(position, index, color) {
    var token = new PIXI.Graphics();
    token.lineStyle(1, 0, 1);
    token.beginFill(color, 1);
    var tile = this.tileViews[position];
    token.drawRect(5, 50 * (index + 1), 20, 20);
    tile.addChild(token);
    this.tokenViews.push({token: token, tile: tile});
}

SimpleView.prototype.drawTokens = function() {
    for (i = 0; i < this.game.players.length; i++) {
        this.drawToken(this.game.players[i].position, i, constants.colors[i]);
    }
}

SimpleView.prototype.updateToken = function(position, index, color) {
    var playerView = this.tokenViews[index];
    var token = playerView.token;

    // remove the token from the previous tile
    var previousTile = playerView.tile;
    previousTile.removeChild(token);

    // add the token as a child to the new tile
    var currentTile = this.tileViews[position];
    currentTile.addChild(token);
    this.tokenViews[index] = {token: token, tile: currentTile};

    // calculate an offset for the token if there are multiple

    token.x = ((constants.canvasWidth / this.game.board.spaces.length) * position);
}

SimpleView.prototype.updateTokens = function() {
    for (i = 0; i < this.game.players.length; i++) {
        this.updateToken(this.game.players[i].position, i, constants.colors[i]);
    }
}

SimpleView.prototype.drawMessage = function() {
    var container = new PIXI.Container();

    button1 = new PIXI.Graphics();
    button1.y = 160;
    button1.beginFill(0x00FF00, 1);
    button1.drawRect(0, 0, 200, 40);
    container.addChild(button1);

    button1.interactive = true;
    var context = this;
    button1.click = function(mouseData){
       console.log("CLICK!");
       context.game.updateState(true);
    };

    this.button1Text = new PIXI.Text("Roll", {font: '30px Arial',
                                                align : 'center',
                                                wordWrap : true,
                                                strokeThickness : .25,
                                                //wordWrapWidth : (constants.tileLongSide - constants.tileColorLength),
                                                wordWrapWidth : 150,
                                                });
    this.button1Text.x = 50;
    button1.addChild(this.button1Text);
    this.stage.addChild(container);
};

SimpleView.prototype.animate = function() {
    this.updateTokens();
    requestAnimationFrame(this.animate.bind(this));
    this.renderer.render(this.stage);
}

module.exports = SimpleView;

<commit_msg>some syntax fixes in simple view<commit_after>var constants = {
    canvasWidth : 1000,
    canvasHeight : 200,
    numberOfSpaces : 20,
    colors : [
        0x6F3A19,
        0x88C8F3
    ]
};

function SimpleView(game_state) {
    this.game = game_state;
    this.tileViews = [];
    this.tokenViews = [];

    this.renderer = PIXI.autoDetectRenderer(constants.canvasWidth, constants.canvasHeight,
            {backgroundColor : 0x1099bb});

    document.body.appendChild(this.renderer.view);

    // create the root of the scene graph
    this.stage = new PIXI.Container();
};

SimpleView.prototype.drawBoard = function() {
    x_pos = 0;
    y_pos = 0;
    for (i = 0; i < this.game.board.spaces.length; i++) {
        tile = new PIXI.Graphics();
        tile.lineStyle(1, 0, 1);
        tile.drawRect(x_pos, y_pos, constants.canvasWidth / this.game.board.spaces.length, constants.canvasHeight);
        x_pos += constants.canvasWidth / this.game.board.spaces.length;

        this.tileViews.push(tile);
        this.stage.addChild(tile);

    }

    this.drawTokens();

    this.drawMessage();
    this.animate();
};

SimpleView.prototype.drawToken = function(position, index, color) {
    var token = new PIXI.Graphics();
    token.lineStyle(1, 0, 1);
    token.beginFill(color, 1);
    var tile = this.tileViews[position];
    token.drawRect(5, 50 * (index + 1), 20, 20);
    tile.addChild(token);
    this.tokenViews.push({token: token, tile: tile});
}

SimpleView.prototype.drawTokens = function() {
    for (i = 0; i < this.game.players.length; i++) {
        this.drawToken(this.game.players[i].position, i, constants.colors[i]);
    }
};

SimpleView.prototype.updateToken = function(position, index, color) {
    var playerView = this.tokenViews[index];
    var token = playerView.token;

    // remove the token from the previous tile
    var previousTile = playerView.tile;
    previousTile.removeChild(token);

    // add the token as a child to the new tile
    var currentTile = this.tileViews[position];
    currentTile.addChild(token);
    this.tokenViews[index] = {token: token, tile: currentTile};

    // calculate an offset for the token if there are multiple

    token.x = ((constants.canvasWidth / this.game.board.spaces.length) * position);
}

SimpleView.prototype.updateTokens = function() {
    for (i = 0; i < this.game.players.length; i++) {
        this.updateToken(this.game.players[i].position, i, constants.colors[i]);
    }
}

SimpleView.prototype.drawMessage = function() {
    var container = new PIXI.Container();

    button1 = new PIXI.Graphics();
    button1.y = 160;
    button1.beginFill(0x00FF00, 1);
    button1.drawRect(0, 0, 200, 40);
    container.addChild(button1);

    button1.interactive = true;
    var context = this;
    button1.click = function(mouseData){
       console.log("CLICK!");
       context.game.updateState(true);
    };

    this.button1Text = new PIXI.Text("Roll", {font: '30px Arial',
                                                align : 'center',
                                                wordWrap : true,
                                                strokeThickness : .25,
                                                //wordWrapWidth : (constants.tileLongSide - constants.tileColorLength),
                                                wordWrapWidth : 150,
                                                });
    this.button1Text.x = 50;
    button1.addChild(this.button1Text);
    this.stage.addChild(container);
};

SimpleView.prototype.animate = function() {
    this.updateTokens();
    requestAnimationFrame(this.animate.bind(this));
    this.renderer.render(this.stage);
}

module.exports = SimpleView;

<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp'),
  gutil = require('gulp-util'),
  fs = require('fs'),
  $ = require('gulp-load-plugins')(),
  to5 = require('gulp-6to5'),
  del = require('del'),
  opn = require('opn'),
  pagespeed = require('psi'),

  Htmlbars = require('ember-cli-htmlbars'),
  compiler = new Htmlbars();

// https://github.com/ai/autoprefixer. Default: > 1%, last 2 versions, Firefox ESR, Opera 12.1
// Android, BlackBerry or bb, iOS
// Chrome, Firefox or ff, Explorer or ie, Opera, Safari
//
// last 2 versions, last 2 Chrome versions, > 5%, ff > 20, ff >= 20, Firefox ESR, none
// Blackberry and stock Android browsers will not be used in last n versions. Add them by name:
// autoprefixer("last 1 version", "BlackBerry 10", "Android 4")
var AutoPrefixerConfig = [
    'ie >= 9',
    'ie_mob >= 10',
    'ff >= 30',
    'chrome >= 34',
    'safari >= 7',
    'opera >= 23',
    'ios >= 7',
    'android >= 4.4',
    'bb >= 10'
  ],
  clientFolder = 'client',
  path = require('path'),
  server = require('tiny-lr')(),
  compileAllSrc, // Compile all src if filename start with _, or single without leading _
  sassFilePath, // Used to dynamicially set sass path, default to all sass
  // Local Variable
  options = {
    hostname: 'localhost',
    port: 3001
  };

// task: jshint
// @describe need to be passed to be able to build the project
gulp.task('lint', function() {
  var src = [
    'gulpfile.js',
    'client/app/**/*.js',
    '!client/app/utils/register-components.js',
    'server/**/*.js'
  ];

  return gulp.src( src )
      .pipe($.jshint())
      .pipe($.jshint.reporter('jshint-stylish'));
});

// task: stripLRScript
// @describe  Strip out the LiveReload Script tag in HTML
gulp.task('stripLRScript', function() {
  return gulp.src([ clientFolder + '/index.html' ])
  .pipe(
    $.replace(/\n')
  )
  .pipe(gulp.dest(path.join(__dirname, clientFolder)));
});

// Smart compile: if filename start with _, when save it will compile the whole project.
// if filename is all text without _, when save it will only compile changed file
gulp.task('sass', function() {
  var allSrc = clientFolder + '/assets/styles/sass/**/*.{scss,sass}',
      compileFiles = ( compileAllSrc ) ? allSrc : ( sassFilePath ) ? sassFilePath : allSrc,
      nestedFolder = void 0;

  // When it is single file for compiling, it needs to render it in the right folder path.
  // default it is   appName +'/resources/css',
  // If it is nested folder inside sass/path/to/compileFilename, it will alert the dest folder path
  if ( !compileAllSrc ) {
    var basepathArr = path.dirname(sassFilePath).split('/'),
      len = basepathArr.length,
      lastPos = len -1,
      sassPos = basepathArr.indexOf('sass');

    if ( len > sassPos ) {
      nestedFolder = '';
      var diff = lastPos - sassPos;
      for ( var i = 0 ; i < diff; i++ ) {
        var foldername = '/' + basepathArr[ lastPos - i ];
        nestedFolder = foldername.concat(nestedFolder);
      }
    }
  }

  var destPath = clientFolder + '/assets/styles' + ( ( nestedFolder ) ? nestedFolder : '' );

  // return gulp.src( compileFiles, { base: 'client/assets/styles/sass' } )
  //   .pipe($.rubySass({
  //     // compass: false,  // default value
  //     // debugInfo: false,  // default value
  //     // lineNumbers: false,  // default value
  //     sourcemapPath: './sass',
  //     style: 'expanded',
  //     precision: 3,
  //     loadPath: ['/assets/styles/sass']
  //   }))
    return $.rubySass('client/assets/styles/sass', {
      sourcemap: true,
      style: 'expanded',
      loadPath: ['/assets/styles/sass']
    })
    .on('error', function (err) { console.log(err.message); })
    .pipe($.autoprefixer({
      browsers: AutoPrefixerConfig
    }))
    .pipe($.sourcemaps.write('maps', {
      includeContent: false,
      sourceRoot: destPath
    }))
    .pipe(gulp.dest( destPath ))
    .pipe($.size({title: 'compiled css'}))
    .pipe($.notify({ message: 'Compiled <%= file.relative %>' }));
});

// https://github.com/sindresorhus/gulp-imagemin
// @describe remove extra pixels out of images
gulp.task('imagemin', function() {
  var imgSrc = clientFolder + '/assets/images/**/*',
    imgDst = 'build/client/assets/images/';

  return gulp.src(imgSrc)
    .pipe(
      $.imagemin({
        progressive: true,
        interlaced: true
      })
    )
    .pipe(gulp.dest(imgDst))
    .pipe($.size({title: '[-log:] images folder'}));
});

// @describe compile es6 modules into amd modules
gulp.task('buildjs', function () {
  return gulp.src(clientFolder + '/app/**/*.js')
    .pipe($.sourcemaps.init())
    .pipe(to5({
      modules: 'amd',
      sourceRoot: __dirname + '/client/app',
      moduleRoot: 'rocks',
      amdModuleIds: true,
      sourceMap: true
    }))
    .pipe($.concat('application.js'))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest(clientFolder + '/assets/build/'));
});

// @describe pre-compile handlebars templates
gulp.task('buildhbs', function () {
  return gulp.src(clientFolder + '/app/templates/**/*.hbs')
    .pipe($.handlebars({
      handlebars: require('ember-handlebars'),
      compiler: compiler.processString
    }))
    .pipe($.wrapAmd({
      deps: ['exports'],          // dependency array
      params: ['__exports__'],        // params for callback
      moduleRoot: 'client/app/',
      modulePrefix: 'rocks/'
    }))
    .pipe( $.replace(
        /return export default/, 'return __exports__["default"] ='
    ))
    .pipe($.concat('templates.js'))
    .pipe(gulp.dest(clientFolder + '/assets/build/'));
});

// @describe build front end code base
gulp.task('build', ['buildjs', 'buildhbs'], function(){
  gutil.log(
    gutil.colors.green('[-done:] application.js and templates.js has been generated!')
  );
});

// @describe Remove the 'build/' folder, start from a clean slate
gulp.task('clean', del.bind(null, ['build'], {force : true} ));

// @describe In release step, use production ready libraries
gulp.task('envProd', function(){
  var src = 'client/index.html',
    dest = 'client';

  return gulp.src(src)
  //.pipe( $.replace( /\/vendors\/jquery\/dist\/jquery.js/, '/vendors/jquery/dist/jquery.min.js'))
      .pipe( $.replace(
          /\/vendors\/handlebars\/handlebars.js/, '/vendors/handlebars/handlebars.min.js'
      ))
      .pipe( $.replace( /\/vendors\/ember\/ember.js/, '/vendors/ember/ember.prod.js'))
      .pipe(gulp.dest(dest));
});

// @describe In development step, use development libraries
gulp.task('envDev', function(){
  var src = 'client/index.html',
    dest = 'client';

  return gulp.src(src)
  //.pipe( $.replace( /\/vendors\/jquery\/dist\/jquery.min.js/, '/vendors/jquery/dist/jquery.js'))
      .pipe( $.replace(
          /\/vendors\/handlebars\/handlebars.min.js/, '/vendors/handlebars/handlebars.js'
      ))
      .pipe( $.replace( /\/vendors\/ember\/ember.prod.js/, '/vendors/ember/ember.js'))
      .pipe(gulp.dest(dest));
});

function wireUpMobile(callback) {
  var appPath = 'build/cordova/www/',
    indexPath = appPath+ 'index.html',
    mainAppPath = appPath + 'assets/scripts/main.min.js',
    scriptPath = appPath + 'assets/scripts/',
    serverAppPath = 'build/server/app.js',
    serverPath = 'build/server';

  gulp.src(indexPath)
    .pipe($.replace(/base(?:\s+)?href=\"\/\"/, 'base href=""'))
    .pipe(gulp.dest(appPath));

  gulp.src(mainAppPath)
    .pipe($.replace(/\{(?:\s+)?location:(\s+)?[\'\"]auto[\'\"](?:\s+)?\}/, '{location:"hash"}'))
    .pipe(gulp.dest(scriptPath));

  gulp.src(serverAppPath)
    .pipe($.replace(/emberApp(?:\s+)?=(?:\s+)?\'client\'/, 'emberApp = \'cordova/www\''))
    .pipe(gulp.dest(serverPath));

  del(['build/client'], {force : true}, function() {
    callback();
  });
}

// copy all the core files and release to production
gulp.task('releaseMobile', [ 'release' ],
  function(callback){
    var cordovaPath = 'node_modules/ember-rocks/src/skeletons/cordova/**/*',
      clientPath = 'build/client/**/*',
      cordovaAppPath = 'build/cordova/www',
      dest = 'build/cordova/';

    gulp.src(cordovaPath)
      .pipe(gulp.dest(dest));

    gulp.src(clientPath)
      .on('end', function(){
        wireUpMobile(callback);
      })
      .pipe(gulp.dest(cordovaAppPath));
  });

// copy all the core files and release to production
gulp.task('releaseClient',
  [ 'clean', 'sass', 'lint', 'build', 'envProd'],
  function(){
    var src = 'client/index.html',
      dest = 'build/client',
      assets = $.useref.assets({searchPath: 'client'});

  // clean task has to be done
  // imagemin will minify all images and copy into build
  gulp.start('imagemin');

  return gulp.src(src)
    .pipe(
    $.replace(/\n')
  )
  .pipe(gulp.dest(path.join(__dirname, clientFolder)));
});

// Smart compile: if filename start with _, when save it will compile the whole project.
// if filename is all text without _, when save it will only compile changed file
gulp.task('sass', function() {
  var allSrc = clientFolder + '/assets/styles/sass/**/*.{scss,sass}',
      compileFiles = ( compileAllSrc ) ? allSrc : ( sassFilePath ) ? sassFilePath : allSrc,
      nestedFolder = void 0;

  // When it is single file for compiling, it needs to render it in the right folder path.
  // default it is   appName +'/resources/css',
  // If it is nested folder inside sass/path/to/compileFilename, it will alert the dest folder path
  if ( !compileAllSrc ) {
    var basepathArr = path.dirname(sassFilePath).split('/'),
      len = basepathArr.length,
      lastPos = len -1,
      sassPos = basepathArr.indexOf('sass');

    if ( len > sassPos ) {
      nestedFolder = '';
      var diff = lastPos - sassPos;
      for ( var i = 0 ; i < diff; i++ ) {
        var foldername = '/' + basepathArr[ lastPos - i ];
        nestedFolder = foldername.concat(nestedFolder);
      }
    }
  }

  var destPath = clientFolder + '/assets/styles' + ( ( nestedFolder ) ? nestedFolder : '' );

  // return gulp.src( compileFiles, { base: 'client/assets/styles/sass' } )
  //   .pipe($.rubySass({
  //     // compass: false,  // default value
  //     // debugInfo: false,  // default value
  //     // lineNumbers: false,  // default value
  //     sourcemapPath: './sass',
  //     style: 'expanded',
  //     precision: 3,
  //     loadPath: ['/assets/styles/sass']
  //   }))
    return $.rubySass(compileFiles, {
      sourcemap: true,
      style: 'expanded',
      loadPath: ['/assets/styles/sass']
    })
    .on('error', function (err) { console.log(err.message); })
    .pipe($.autoprefixer({
      browsers: AutoPrefixerConfig
    }))
    .pipe($.sourcemaps.write('maps', {
      includeContent: false,
      sourceRoot: destPath
    }))
    .pipe(gulp.dest( destPath ))
    .pipe($.size({title: 'compiled css'}))
    .pipe($.notify({ message: 'Compiled <%= file.relative %>' }));
});

// https://github.com/sindresorhus/gulp-imagemin
// @describe remove extra pixels out of images
gulp.task('imagemin', function() {
  var imgSrc = clientFolder + '/assets/images/**/*',
    imgDst = 'build/client/assets/images/';

  return gulp.src(imgSrc)
    .pipe(
      $.imagemin({
        progressive: true,
        interlaced: true
      })
    )
    .pipe(gulp.dest(imgDst))
    .pipe($.size({title: '[-log:] images folder'}));
});

// @describe compile es6 modules into amd modules
gulp.task('buildjs', function () {
  return gulp.src(clientFolder + '/app/**/*.js')
    .pipe($.sourcemaps.init())
    .pipe(to5({
      modules: 'amd',
      sourceRoot: __dirname + '/client/app',
      moduleRoot: 'rocks',
      amdModuleIds: true,
      sourceMap: true
    }))
    .pipe($.concat('application.js'))
    .pipe($.sourcemaps.write())
    .pipe(gulp.dest(clientFolder + '/assets/build/'));
});

// @describe pre-compile handlebars templates
gulp.task('buildhbs', function () {
  return gulp.src(clientFolder + '/app/templates/**/*.hbs')
    .pipe($.handlebars({
      handlebars: require('ember-handlebars'),
      compiler: compiler.processString
    }))
    .pipe($.wrapAmd({
      deps: ['exports'],          // dependency array
      params: ['__exports__'],        // params for callback
      moduleRoot: 'client/app/',
      modulePrefix: 'rocks/'
    }))
    .pipe( $.replace(
        /return export default/, 'return __exports__["default"] ='
    ))
    .pipe($.concat('templates.js'))
    .pipe(gulp.dest(clientFolder + '/assets/build/'));
});

// @describe build front end code base
gulp.task('build', ['buildjs', 'buildhbs'], function(){
  gutil.log(
    gutil.colors.green('[-done:] application.js and templates.js has been generated!')
  );
});

// @describe Remove the 'build/' folder, start from a clean slate
gulp.task('clean', del.bind(null, ['build'], {force : true} ));

// @describe In release step, use production ready libraries
gulp.task('envProd', function(){
  var src = 'client/index.html',
    dest = 'client';

  return gulp.src(src)
  //.pipe( $.replace( /\/vendors\/jquery\/dist\/jquery.js/, '/vendors/jquery/dist/jquery.min.js'))
      .pipe( $.replace(
          /\/vendors\/handlebars\/handlebars.js/, '/vendors/handlebars/handlebars.min.js'
      ))
      .pipe( $.replace( /\/vendors\/ember\/ember.js/, '/vendors/ember/ember.prod.js'))
      .pipe(gulp.dest(dest));
});

// @describe In development step, use development libraries
gulp.task('envDev', function(){
  var src = 'client/index.html',
    dest = 'client';

  return gulp.src(src)
  //.pipe( $.replace( /\/vendors\/jquery\/dist\/jquery.min.js/, '/vendors/jquery/dist/jquery.js'))
      .pipe( $.replace(
          /\/vendors\/handlebars\/handlebars.min.js/, '/vendors/handlebars/handlebars.js'
      ))
      .pipe( $.replace( /\/vendors\/ember\/ember.prod.js/, '/vendors/ember/ember.js'))
      .pipe(gulp.dest(dest));
});

function wireUpMobile(callback) {
  var appPath = 'build/cordova/www/',
    indexPath = appPath+ 'index.html',
    mainAppPath = appPath + 'assets/scripts/main.min.js',
    scriptPath = appPath + 'assets/scripts/',
    serverAppPath = 'build/server/app.js',
    serverPath = 'build/server';

  gulp.src(indexPath)
    .pipe($.replace(/base(?:\s+)?href=\"\/\"/, 'base href=""'))
    .pipe(gulp.dest(appPath));

  gulp.src(mainAppPath)
    .pipe($.replace(/\{(?:\s+)?location:(\s+)?[\'\"]auto[\'\"](?:\s+)?\}/, '{location:"hash"}'))
    .pipe(gulp.dest(scriptPath));

  gulp.src(serverAppPath)
    .pipe($.replace(/emberApp(?:\s+)?=(?:\s+)?\'client\'/, 'emberApp = \'cordova/www\''))
    .pipe(gulp.dest(serverPath));

  del(['build/client'], {force : true}, function() {
    callback();
  });
}

// copy all the core files and release to production
gulp.task('releaseMobile', [ 'release' ],
  function(callback){
    var cordovaPath = 'node_modules/ember-rocks/src/skeletons/cordova/**/*',
      clientPath = 'build/client/**/*',
      cordovaAppPath = 'build/cordova/www',
      dest = 'build/cordova/';

    gulp.src(cordovaPath)
      .pipe(gulp.dest(dest));

    gulp.src(clientPath)
      .on('end', function(){
        wireUpMobile(callback);
      })
      .pipe(gulp.dest(cordovaAppPath));
  });

// copy all the core files and release to production
gulp.task('releaseClient',
  [ 'clean', 'sass', 'lint', 'build', 'envProd'],
  function(){
    var src = 'client/index.html',
      dest = 'build/client',
      assets = $.useref.assets({searchPath: 'client'});

  // clean task has to be done
  // imagemin will minify all images and copy into build
  gulp.start('imagemin');

  return gulp.src(src)
    .pipe(
    $.replace(/


<commit_before>
(function($){
	'use strict';

	var lastClick = 0, oldon = $.fn.on, oldoff = $.fn.off;

	$.fn.off = function(event, fn) {
		return event !== 'tap' ? oldoff.call(this, event, fn) : this.each(function(item){ item._tap = fn; }).off('touchstart', onTouchStart).off('touchmove', onTouchMove).off('touchend', onTouchEnd).off('click', onClick).each(function(item){ delete item._tap; delete item._x; delete item._y });
	}

	$.fn.on = function(event, fn) {
		return event !== 'tap' ? oldon.call(this, event, fn) : this.each(function(item){ item._tap = fn; }).on('touchstart', onTouchStart).on('click', onClick);
	}

	function onTouchStart(e) {
		e.stopPropagation();

		var touch = e.touches[0];

		this._x = touch.clientX;
		this._y = touch.clientY;

		this.addEventListener('touchmove', onTouchMove, false);
		this.addEventListener('touchend', onTouchEnd, false);
	}

	function onTouchMove(e) {
		var touch = e.targetTouches[0];
		if (!touch || Math.sqrt((this._x-touch.clientX)*(this._x-touch.clientX)+(this._y-touch.clientY)*(this._y-touch.clientY)) > 5) {
			$(this).off('touchmove', onTouchMove, false).off('touchend', onTouchEnd, false);
		}
	}

	function onTouchEnd(e) {
		onClick.call(this, e);
		$(this).off('touchmove', onTouchMove).off('touchend', onTouchEnd);
	}

	function onClick(e) {
		e.stopPropagation();
		// avoid ghostclicks
		if (new Date() - lastClick > 500) {
			lastClick = new Date();
			this._tap && this._tap.call(this, e);
		}
	}

}(window.$));<commit_msg>Replaced 'new Date()' with 'Date.now()'<commit_after>
(function($){
	'use strict';

	var lastClick = 0, oldon = $.fn.on, oldoff = $.fn.off;

	$.fn.off = function(event, fn) {
		return event !== 'tap' ? oldoff.call(this, event, fn) : this.each(function(item){ item._tap = fn; }).off('touchstart', onTouchStart).off('touchmove', onTouchMove).off('touchend', onTouchEnd).off('click', onClick).each(function(item){ delete item._tap; delete item._x; delete item._y });
	}

	$.fn.on = function(event, fn) {
		return event !== 'tap' ? oldon.call(this, event, fn) : this.each(function(item){ item._tap = fn; }).on('touchstart', onTouchStart).on('click', onClick);
	}

	function onTouchStart(e) {
		e.stopPropagation();

		var touch = e.touches[0];

		this._x = touch.clientX;
		this._y = touch.clientY;

		this.addEventListener('touchmove', onTouchMove, false);
		this.addEventListener('touchend', onTouchEnd, false);
	}

	function onTouchMove(e) {
		var touch = e.targetTouches[0];
		if (!touch || Math.sqrt((this._x-touch.clientX)*(this._x-touch.clientX)+(this._y-touch.clientY)*(this._y-touch.clientY)) > 5) {
			$(this).off('touchmove', onTouchMove, false).off('touchend', onTouchEnd, false);
		}
	}

	function onTouchEnd(e) {
		onClick.call(this, e);
		$(this).off('touchmove', onTouchMove).off('touchend', onTouchEnd);
	}

	function onClick(e) {
		e.stopPropagation();
		// avoid ghostclicks
		if (Date.now() - lastClick > 500) {
			lastClick = Date.now();
			this._tap && this._tap.call(this, e);
		}
	}

}(window.$));<|endoftext|>


<commit_before>'use strict';
var os    = require('os');
var spawn = require('cross-spawn');
var when  = require('when');
var path  = require('path');
var utilSwitches = require('./switches');

/**
 * @promise Run
 * @param {string} command The command to run.
 * @param {Array} switches Options for 7-Zip as an array.
 * @progress {string} stdout message.
 * @reject {Error} The error issued by 7-Zip.
 * @reject {number} Exit code issued by 7-Zip.
 */
module.exports = function (command, switches) {
  return when.promise(function (fulfill, reject, progress) {

    // Parse the command variable. If the command is not a string reject the
    // Promise. Otherwise transform the command into two variables: the command
    // name and the arguments.
    if (typeof command !== 'string') {
      return reject(new Error('Command must be a string'));
    }
    var cmd  = command.split(' ')[0];
    var args = [ command.split(' ')[1] ];

    // Parse and add command (non-switches parameters) to `args`.
    var regexpCommands = /"((?:\\.|[^"\\])*)"/g;
    var commands       = command.match(regexpCommands);
    if (commands) {
      commands.forEach(function (c) {
        c = c.replace(/\//, path.sep);
        c = c.replace(/\\/, path.sep);
        c = path.normalize(c);
        args.push(c);
      });
    }

    // Special treatment for the output switch because it is exposed as a
    // parameter in the API and not as a option. Plus wilcards can be passed.
    var regexpOutput = /-o"((?:\\.|[^"\\])*)"/g;
    var output       = command.match(regexpOutput);
    if (output) {
      args.pop();
      var o = output[0];
      o = o.replace(/\//, path.sep);
      o = o.replace(/\\/, path.sep);
      o = o.replace(/"/g, '');
      o = path.normalize(o);
      args.push(o);
    }

    // Add switches to the `args` array.
    var switchesArray = utilSwitches(switches);
    switchesArray.forEach(function (s) { args.push(s); });

    // Remove now double quotes. If present in the spawned process 7-Zip will
    // read them as part of the paths (e.g.: create a `"archive.7z"` with
    // quotes in the file-name);
    args.forEach(function (e, i) {
      if (typeof e !== 'string') {
        return;
      }
      if (e.substr(0, 1) !== '-') {
        e = e.replace(/^"/, '');
        e = e.replace(/"$/, '');
        args[i] = e;
      }
    });

    // When an stdout is emitted, parse it. If an error is detected in the body
    // of the stdout create an new error with the 7-Zip error message as the
    // error's message. Otherwise progress with stdout message.
    var err;
    var reg = new RegExp('Error:' + os.EOL + '?(.*)', 'g');
    var res = {
      cmd: cmd,
      args: args,
      options: { stdio: 'pipe' } };

    var run = spawn(res.cmd, res.args, res.options);
    run.stdout.on('data', function (data) {
      var res = reg.exec(data.toString());
      if (res) {
        err = new Error(res[1]);
      }
      return progress(data.toString());
    });
    run.stderr.on('data', function (data) {
      //throw errors
		  err = data.toString();
    });
    run.on('error', function (err) {
      reject(err)
    });
    run.on('close', function (code) {
      if (code === 0) {
        return fulfill(args);
      }
      return reject(err, code);
    });

  });
};
<commit_msg>Fix extracting to UNC paths<commit_after>'use strict';
var os    = require('os');
var spawn = require('cross-spawn');
var when  = require('when');
var path  = require('path');
var utilSwitches = require('./switches');

/**
 * @promise Run
 * @param {string} command The command to run.
 * @param {Array} switches Options for 7-Zip as an array.
 * @progress {string} stdout message.
 * @reject {Error} The error issued by 7-Zip.
 * @reject {number} Exit code issued by 7-Zip.
 */
module.exports = function (command, switches) {
  return when.promise(function (fulfill, reject, progress) {

    // Parse the command variable. If the command is not a string reject the
    // Promise. Otherwise transform the command into two variables: the command
    // name and the arguments.
    if (typeof command !== 'string') {
      return reject(new Error('Command must be a string'));
    }
    var cmd  = command.split(' ')[0];
    var args = [ command.split(' ')[1] ];

    // Parse and add command (non-switches parameters) to `args`.
    var regexpCommands = /"((?:\\.|[^"\\])*)"/g;
    var commands       = command.match(regexpCommands);
    if (commands) {
      commands.forEach(function (c) {
        c = c.replace(/\//, path.sep);
        c = c.replace(/\\/, path.sep);
        c = path.normalize(c);
        args.push(c);
      });
    }

    // Special treatment for the output switch because it is exposed as a
    // parameter in the API and not as a option. Plus wilcards can be passed.
    var regexpOutput = /-o"((?:\\.|[^"\\])*)"/g;
    var output       = command.match(regexpOutput);
    if (output) {
      args.pop();
      var o = output[0];
      o = o.replace(/\//, path.sep);
      o = o.replace(/\\/, path.sep);
      o = o.replace(/"/g, '');
      o = "-o" + path.normalize(o.slice(2));
      args.push(o);
    }

    // Add switches to the `args` array.
    var switchesArray = utilSwitches(switches);
    switchesArray.forEach(function (s) { args.push(s); });

    // Remove now double quotes. If present in the spawned process 7-Zip will
    // read them as part of the paths (e.g.: create a `"archive.7z"` with
    // quotes in the file-name);
    args.forEach(function (e, i) {
      if (typeof e !== 'string') {
        return;
      }
      if (e.substr(0, 1) !== '-') {
        e = e.replace(/^"/, '');
        e = e.replace(/"$/, '');
        args[i] = e;
      }
    });

    // When an stdout is emitted, parse it. If an error is detected in the body
    // of the stdout create an new error with the 7-Zip error message as the
    // error's message. Otherwise progress with stdout message.
    var err;
    var reg = new RegExp('Error:' + os.EOL + '?(.*)', 'g');
    var res = {
      cmd: cmd,
      args: args,
      options: { stdio: 'pipe' } };

    var run = spawn(res.cmd, res.args, res.options);
    run.stdout.on('data', function (data) {
      var res = reg.exec(data.toString());
      if (res) {
        err = new Error(res[1]);
      }
      return progress(data.toString());
    });
    run.stderr.on('data', function (data) {
      //throw errors
		  err = data.toString();
    });
    run.on('error', function (err) {
      reject(err)
    });
    run.on('close', function (code) {
      if (code === 0) {
        return fulfill(args);
      }
      return reject(err, code);
    });

  });
};
<|endoftext|>


<commit_before>function fillExample(login, pass) {
    document.querySelector('#login').value = login;
    document.querySelector('#pass').value = pass;
}

/**
 * @brief Save a jid in the local storage
 * @param The jid to remember
 */
function rememberSession(jid) {
    if(localStorage['previousSessions'] == null) {
        localStorage.setObject('previousSessions', new Array());
    }

    var s = localStorage.getObject('previousSessions');
    if(s.indexOf(jid) == -1) {
        s.push(jid);
        localStorage.setObject('previousSessions', s);
    }
}

/**
 * @brief Choose a session to connect and show the login form
 * @param The jid to choose
 */
function chooseSession(jid) {
    movim_remove_class('#loginpage', 'choose');
    document.querySelector('#login').value = jid;

    if(jid != '') {
        document.querySelector('#pass').focus();
    } else {
        document.querySelector('#login').focus();
    }
}

/**
 * @brief Remove a remembered session
 * @param The jid to choose
 */
function removeSession(jid) {
    var s = localStorage.getObject('previousSessions');
    s.splice(s.indexOf(jid), 1);

    if(s.length == 0) {
        localStorage.removeItem('previousSessions');
        movim_remove_class('#loginpage', 'choose');
    } else {
        localStorage.setObject('previousSessions', s);
    }

    Login_ajaxGetRememberedSession(localStorage.getItem('previousSessions'));
}

/**
 * @brief Back to the choosing panel
 */
function backToChoose() {
    movim_add_class('#loginpage', 'choose');
}

/**
 * @brief Post login requests
 */
function postLogin(jid, url) {
    rememberSession(jid);
    localStorage.postStart = 1;
    movim_reload(url);
}

MovimWebsocket.attach(function()
{
    if(localStorage.username != null)
        document.querySelector('#login').value = localStorage.username;

    // The form submission event
    form = document.querySelector('form[name="login"]');
    form.onsubmit = function(e) {
        e.preventDefault();

        var button = this.querySelector('input[type=submit]');
        button.className = 'button color orange icon yes';
        button.value = button.dataset.loading;

        eval(this.dataset.action);

        localStorage.username = document.querySelector('#login').value;
        rememberSession(localStorage.username);

        // A fallback security
        setTimeout("MovimWebsocket.unregister()", 15000);
    };

    // We hide the Websocket error
    document.querySelector('#loginpage #warning .websocket').style.display = 'none';

    // We enable the form
    var inputs = document.querySelectorAll('#loginpage input[disabled]');
    for (var i = 0; i < inputs.length; i++)
    {
        inputs[i].disabled = false;
    }

    // We get the previous sessions
    Login_ajaxGetRememberedSession(localStorage.getItem('previousSessions'));

    if(localStorage.getItem('previousSessions') != null) {
        movim_add_class('#loginpage', 'choose');
    }
});

movim_add_onload(function() {
    //MovimWebsocket.unregister();
});
<commit_msg>- Dump cache variables  in localStorage on login page<commit_after>function fillExample(login, pass) {
    document.querySelector('#login').value = login;
    document.querySelector('#pass').value = pass;
}

/**
 * @brief Save a jid in the local storage
 * @param The jid to remember
 */
function rememberSession(jid) {
    if(localStorage['previousSessions'] == null) {
        localStorage.setObject('previousSessions', new Array());
    }

    var s = localStorage.getObject('previousSessions');
    if(s.indexOf(jid) == -1) {
        s.push(jid);
        localStorage.setObject('previousSessions', s);
    }
}

/**
 * @brief Choose a session to connect and show the login form
 * @param The jid to choose
 */
function chooseSession(jid) {
    movim_remove_class('#loginpage', 'choose');
    document.querySelector('#login').value = jid;

    if(jid != '') {
        document.querySelector('#pass').focus();
    } else {
        document.querySelector('#login').focus();
    }
}

/**
 * @brief Remove a remembered session
 * @param The jid to choose
 */
function removeSession(jid) {
    var s = localStorage.getObject('previousSessions');
    s.splice(s.indexOf(jid), 1);

    if(s.length == 0) {
        localStorage.removeItem('previousSessions');
        movim_remove_class('#loginpage', 'choose');
    } else {
        localStorage.setObject('previousSessions', s);
    }

    Login_ajaxGetRememberedSession(localStorage.getItem('previousSessions'));
}

/**
 * @brief Back to the choosing panel
 */
function backToChoose() {
    movim_add_class('#loginpage', 'choose');
}

/**
 * @brief Post login requests
 */
function postLogin(jid, url) {
    rememberSession(jid);
    localStorage.postStart = 1;
    movim_reload(url);
}

MovimWebsocket.attach(function()
{
    if(localStorage.username != null)
        document.querySelector('#login').value = localStorage.username;

    // The form submission event
    form = document.querySelector('form[name="login"]');
    form.onsubmit = function(e) {
        e.preventDefault();

        var button = this.querySelector('input[type=submit]');
        button.className = 'button color orange icon yes';
        button.value = button.dataset.loading;

        eval(this.dataset.action);

        localStorage.username = document.querySelector('#login').value;
        rememberSession(localStorage.username);

        // A fallback security
        setTimeout("MovimWebsocket.unregister()", 15000);
    }

    // We hide the Websocket error
    document.querySelector('#loginpage #warning .websocket').style.display = 'none';

    // We enable the form
    var inputs = document.querySelectorAll('#loginpage input[disabled]');
    for (var i = 0; i < inputs.length; i++)
    {
        inputs[i].disabled = false;
    }

    // We get the previous sessions
    Login_ajaxGetRememberedSession(localStorage.getItem('previousSessions'));

    if(localStorage.getItem('previousSessions') != null) {
        movim_add_class('#loginpage', 'choose');
    }
});

movim_add_onload(function() {
    //MovimWebsocket.unregister();

    /* Dump cache variables  in localStorage */
    for ( var i = 0, len = localStorage.length; i < len; ++i ) {
        var cache = localStorage.key(i);
        if(cache.indexOf("_cache", 6) !== -1)
            localStorage.removeItem(cache);
    }
});
<|endoftext|>


<commit_before>var xmldom = require('xmldom');

var Variable = function(id, name, type) {
    this.id = id;
    this.name = name;
    this.type = type;
    this.value = '0';
    this.ts = new Date();
}

Variable.prototype.setValue = function(value) {
    this.value = value;
    this.ts = new Date();
}

Variable.prototype.getValue = function() {
    return this.value;
}

Variable.prototype.getId = function() {
    return this.id;
}

Variable.prototype.getType = function() {
    return this.type;
}

Variable.prototype.getTs = function() {
    return this.ts;
}

Variable.prototype.getName = function() {
    return this.name;
}

Variable.prototype.getStateXml = function(doc) {
    var varNode = doc.createElement('var');
    varNode.setAttribute('type', this.getType());
    varNode.setAttribute('id', this.getId());

    var initNode = doc.createElement('init');
    initNode.appendChild(doc.createTextNode(this.getValue()));
    varNode.appendChild(initNode);

    var valNode = doc.createElement('var');
    valNode.appendChild(doc.createTextNode(this.getValue()));
    varNode.appendChild(valNode);

    var tsNode = doc.createElement('ts');
    tsNode.appendChild(doc.createTextNode(this.getTs().toString()));
    varNode.appendChild(tsNode);

    return varNode;
}

exports.Variable = Variable;<commit_msg>Fixed bug in variable xml generation.<commit_after>var xmldom = require('xmldom');

var Variable = function(id, name, type) {
    this.id = id;
    this.name = name;
    this.type = type;
    this.value = '0';
    this.ts = new Date();
}

Variable.prototype.setValue = function(value) {
    this.value = value;
    this.ts = new Date();
}

Variable.prototype.getValue = function() {
    return this.value;
}

Variable.prototype.getId = function() {
    return this.id;
}

Variable.prototype.getType = function() {
    return this.type;
}

Variable.prototype.getTs = function() {
    return this.ts;
}

Variable.prototype.getName = function() {
    return this.name;
}

Variable.prototype.getStateXml = function(doc) {
    var varNode = doc.createElement('var');
    varNode.setAttribute('type', this.getType());
    varNode.setAttribute('id', this.getId());

    var initNode = doc.createElement('init');
    initNode.appendChild(doc.createTextNode(this.getValue()));
    varNode.appendChild(initNode);

    var valNode = doc.createElement('val');
    valNode.appendChild(doc.createTextNode(this.getValue()));
    varNode.appendChild(valNode);

    var tsNode = doc.createElement('ts');
    tsNode.appendChild(doc.createTextNode(this.getTs().toString()));
    varNode.appendChild(tsNode);

    return varNode;
}

exports.Variable = Variable;<|endoftext|>


<commit_before>export default [
  {
    "stopName": "HAMPTON & PRINCESS ANNE",
    "stopId": "0209",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": [
      {
        "route_id": 800,
        "busId": 1606,
        "arrival_time": {
          "date": 1454680680000
        },
        "route": "2",
        "destination": "HAMMOND & ADMIRAL TAUSSIG (Naval Exchange)",
        "scheduled_time_of_arrival": 1447353480807,
        "time_to_arrival": "1",
        "bus_number": "1249",
        "last_known_position": {
          "lat": "-78.234",
          "lon": "32.000",
          "adherence": 3000
        }
      },
      {
        "route_id": 800,
        "busId": 1605,
        "arrival_time": {
          "date": 1454680680000
        },
        "route": "2",
        "destination": "HAMMOND & ADMIRAL TAUSSIG (Naval Exchange)",
        "scheduled_time_of_arrival": 144735380000,
        "time_to_arrival": "29",
        "bus_number": "0123",
        "last_known_position": {
          "lat": "-78.234",
          "lon": "32.000",
          "adherence": 2342
        }
      }
    ]
  },
  {
    "stopName": "COLLEY & GRAYDON",
    "stopId": "0430",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": []
  },
  {
    "stopName": "CodeforVA 995 & Lorem",
    "stopId": "0995",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": [
      {
        "route_id": 800,
        "busId": 1608,
        "arrival_time": {
          "date": 1454680680000
        },
        "route": "2",
        "destination": "Code for 995 & Code for other direction",
        "scheduled_time_of_arrival": 144735380000,
        "time_to_arrival": "29",
        "bus_number": "0123",
        "last_known_position": {
          "lat": "-78.234",
          "lon": "32.000",
          "adherence": 2342
        }
      }
    ]
  },
  {
    "stopName": "CodeforVA 996 & Lorem",
    "stopId": "0996",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": [
      {
        "route_id": 800,
        "busId": 1606,
        "arrival_time": {
          "date": 1454680680000
        },
        "route": "2",
        "destination": "996 & Coding (Naval Exchange)",
        "scheduled_time_of_arrival": 1447353480807,
        "time_to_arrival": "1",
        "bus_number": "1249",
        "last_known_position": {
          "lat": "-78.234",
          "lon": "32.000",
          "adherence": 3000
        }
      }
    ]
  },
  {
    "stopName": "CodeforVA 997 & Lorem",
    "stopId": "0997",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": []
  },
  {
    "stopName": "CodeforVA 998 & Lorem",
    "stopId": "0998",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": []
  },
  {
    "stopName": "CodeforVA 999 & Lorem",
    "stopId": "0999",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": [
      {
        "route_id": 800,
        "busId": 1606,
        "arrival_time": {
          "date": 1454680680000
        },
        "route": "23",
        "destination": "CodeforVA HWY STATION (CURLEW & )",
        "scheduled_time_of_arrival": 1447353485807,
        "time_to_arrival": "6",
        "bus_number": "1713",
        "last_known_position": {
          "lat": "-78.234",
          "lon": "32.000",
          "adherence": 2342
        }
      }
    ]
  },
  {
    "stopName": "CodeforVA ooo & Lorem",
    "stopId": "1000",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": []
  },
  {
    "stopName": "HAMPTON & SPOTSWOOD",
    "stopId": "0281",
    "stop_position": {
      "lat": "-78.000",
      "lon": "32"
    },
    "buses": [
      {
        "route_id": 800,
        "busId": 1606,
        "arrival_time": {
          "date": 1454680680000
        },
        "route": "23",
        "destination": "MILITARY HWY STATION (CURLEW & CORPORATE)",
        "scheduled_time_of_arrival": 1447353485807,
        "time_to_arrival": "6",
        "bus_number": "1713",
        "last_known_position": {
          "lat": "-78.234",
          "lon": "32.000",
          "adherence": 2342
        }
      }
    ]
  }
]
<commit_msg>removed fave-stops.js<commit_after><|endoftext|>


<commit_before>// @flow weak
import { Component } from 'react';
import PropTypes from 'prop-types';
import { create } from 'jss';
import { createStyleManager } from 'jss-theme-reactor/styleManager';
import jssPreset from 'jss-preset-default';
import { createMuiTheme } from './theme';

export const MUI_SHEET_ORDER = [
  'MuiLayout',
  'MuiCollapse',
  'MuiFade',
  'MuiSlide',

  'MuiBackdrop',
  'MuiModal',

  'MuiRipple',
  'MuiTouchRipple',

  'MuiButtonBase',

  'MuiFormLabel',
  'MuiFormGroup',

  'MuiText',
  'MuiPaper',
  'MuiDivider',

  'MuiPopover',

  'MuiButton',
  'MuiIconButton',

  'MuiSvgIcon',
  'MuiIcon',

  'MuiSwitchBase',
  'MuiSwitch',
  'MuiCheckbox',
  'MuiRadio',
  'MuiRadioGroup',
  'MuiSwitchLabel',

  'MuiDialog',
  'MuiDialogActions',
  'MuiDialogContent',
  'MuiDialogContentText',
  'MuiDialogTitle',

  'MuiTabIndicator',
  'MuiTab',
  'MuiTabs',

  'MuiBottomNavigationButton',
  'MuiBottomNavigation',

  'MuiCircularProgress',
  'MuiLinearProgress',

  'MuiAppBar',
  'MuiDrawer',

  'MuiAvatar',

  'MuiListItem',
  'MuiListItemText',
  'MuiListItemSecondaryAction',
  'MuiListItemAvatar',
  'MuiListItemIcon',
  'MuiListSubheader',
  'MuiList',

  'MuiMenu',
  'MuiMenuItem',

  'MuiCardContent',
  'MuiCardMedia',
  'MuiCardActions',
  'MuiCardHeader',
  'MuiCard',

  'MuiTextFieldLabel',
  'MuiTextFieldInput',
  'MuiTextField',

  'MuiTable',
  'MuiTableHead',
  'MuiTableRow',
  'MuiTableCell',
  'MuiTableBody',
  'MuiTableSortLabel',
  'MuiToolbar',

  'MuiBadge',
];

export default class MuiThemeProvider extends Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
    styleManager: PropTypes.object,
    theme: PropTypes.object,
  };

  static childContextTypes = {
    styleManager: PropTypes.object.isRequired,
    theme: PropTypes.object.isRequired,
  };

  static createDefaultContext(props = {}) {
    const theme = props.theme || createMuiTheme();
    const styleManager = props.styleManager || createStyleManager({
      theme,
      jss: create(jssPreset()),
    });

    if (!styleManager.sheetOrder) {
      styleManager.setSheetOrder(MUI_SHEET_ORDER);
    }

    return { theme, styleManager };
  }

  getChildContext() {
    const { theme, styleManager } = this;
    return {
      theme,
      styleManager,
    };
  }

  componentWillMount() {
    const { theme, styleManager } = MuiThemeProvider.createDefaultContext(this.props);
    this.theme = theme;
    this.styleManager = styleManager;
  }

  componentWillUpdate(nextProps) {
    if (this.styleManager !== nextProps.styleManager) {
      const { theme, styleManager } = MuiThemeProvider.createDefaultContext(nextProps);
      this.theme = theme;
      this.styleManager = styleManager;
    } else if (this.theme && nextProps.theme && nextProps.theme !== this.theme) {
      this.theme = nextProps.theme;
      this.styleManager.updateTheme(this.theme);
    }
  }

  theme = undefined;
  styleManager = undefined;

  render() {
    return this.props.children;
  }
}
<commit_msg>[Chip] Add MuiChip to MUI_SHEET_ORDER (#6595)<commit_after>// @flow weak
import { Component } from 'react';
import PropTypes from 'prop-types';
import { create } from 'jss';
import { createStyleManager } from 'jss-theme-reactor/styleManager';
import jssPreset from 'jss-preset-default';
import { createMuiTheme } from './theme';

export const MUI_SHEET_ORDER = [
  'MuiLayout',
  'MuiCollapse',
  'MuiFade',
  'MuiSlide',

  'MuiBackdrop',
  'MuiModal',

  'MuiRipple',
  'MuiTouchRipple',

  'MuiButtonBase',

  'MuiFormLabel',
  'MuiFormGroup',

  'MuiText',
  'MuiPaper',
  'MuiDivider',

  'MuiPopover',

  'MuiButton',
  'MuiIconButton',

  'MuiSvgIcon',
  'MuiIcon',

  'MuiSwitchBase',
  'MuiSwitch',
  'MuiCheckbox',
  'MuiRadio',
  'MuiRadioGroup',
  'MuiSwitchLabel',

  'MuiDialog',
  'MuiDialogActions',
  'MuiDialogContent',
  'MuiDialogContentText',
  'MuiDialogTitle',

  'MuiTabIndicator',
  'MuiTab',
  'MuiTabs',

  'MuiBottomNavigationButton',
  'MuiBottomNavigation',

  'MuiCircularProgress',
  'MuiLinearProgress',

  'MuiAppBar',
  'MuiDrawer',

  'MuiAvatar',

  'MuiChip',

  'MuiListItem',
  'MuiListItemText',
  'MuiListItemSecondaryAction',
  'MuiListItemAvatar',
  'MuiListItemIcon',
  'MuiListSubheader',
  'MuiList',

  'MuiMenu',
  'MuiMenuItem',

  'MuiCardContent',
  'MuiCardMedia',
  'MuiCardActions',
  'MuiCardHeader',
  'MuiCard',

  'MuiTextFieldLabel',
  'MuiTextFieldInput',
  'MuiTextField',

  'MuiTable',
  'MuiTableHead',
  'MuiTableRow',
  'MuiTableCell',
  'MuiTableBody',
  'MuiTableSortLabel',
  'MuiToolbar',

  'MuiBadge',
];

export default class MuiThemeProvider extends Component {
  static propTypes = {
    children: PropTypes.node.isRequired,
    styleManager: PropTypes.object,
    theme: PropTypes.object,
  };

  static childContextTypes = {
    styleManager: PropTypes.object.isRequired,
    theme: PropTypes.object.isRequired,
  };

  static createDefaultContext(props = {}) {
    const theme = props.theme || createMuiTheme();
    const styleManager = props.styleManager || createStyleManager({
      theme,
      jss: create(jssPreset()),
    });

    if (!styleManager.sheetOrder) {
      styleManager.setSheetOrder(MUI_SHEET_ORDER);
    }

    return { theme, styleManager };
  }

  getChildContext() {
    const { theme, styleManager } = this;
    return {
      theme,
      styleManager,
    };
  }

  componentWillMount() {
    const { theme, styleManager } = MuiThemeProvider.createDefaultContext(this.props);
    this.theme = theme;
    this.styleManager = styleManager;
  }

  componentWillUpdate(nextProps) {
    if (this.styleManager !== nextProps.styleManager) {
      const { theme, styleManager } = MuiThemeProvider.createDefaultContext(nextProps);
      this.theme = theme;
      this.styleManager = styleManager;
    } else if (this.theme && nextProps.theme && nextProps.theme !== this.theme) {
      this.theme = nextProps.theme;
      this.styleManager.updateTheme(this.theme);
    }
  }

  theme = undefined;
  styleManager = undefined;

  render() {
    return this.props.children;
  }
}
<|endoftext|>


<commit_before>import Utils from '../../utils/utils';
import Texture from '../../gl/texture';

export default class CanvasText {

    constructor () {
        this.canvas = document.createElement('canvas');
        this.canvas.style.backgroundColor = 'transparent'; // render text on transparent background
        this.context = this.canvas.getContext('2d');
    }

    resize (width, height) {
        this.canvas.width = width;
        this.canvas.height = height;
        this.context.clearRect(0, 0, width, height);
    }

    // Set font style params for canvas drawing
    setFont ({ font_css, fill, stroke, stroke_width, px_size }) {
        this.px_size = px_size;
        this.text_buffer = 8; // pixel padding around text
        let ctx = this.context;

        ctx.font = font_css;
        if (stroke) {
            ctx.strokeStyle = stroke;
            ctx.lineWidth = stroke_width;
        }
        else {
            ctx.strokeStyle = null;
            ctx.lineWidth = 0;
        }
        ctx.fillStyle = fill;
        ctx.miterLimit = 2;
    }

    textSizes (texts) {
        for (let style in texts) {
            let text_infos = texts[style];
            let first = true;

            for (let text in text_infos) {
                // Use cached size, or compute via canvas
                if (!CanvasText.text_cache[style] || !CanvasText.text_cache[style][text]) {
                    let text_settings = text_infos[text].text_settings;
                    if (first) {
                        this.setFont(text_settings);
                        first = false;
                    }

                    CanvasText.text_cache[style] = CanvasText.text_cache[style] || {};
                    CanvasText.text_cache[style][text] =
                        this.textSize(text, text_settings.transform, text_settings.text_wrap);
                    CanvasText.cache_stats.misses++;
                }
                else {
                    CanvasText.cache_stats.hits++;
                }

                // Only send text sizes back to worker (keep computed text line info
                // on main thread, for future rendering)
                text_infos[text].size = CanvasText.text_cache[style][text].size;
            }
        }

        return texts;
    }

    // Computes width and height of text based on current font style
    // Includes word wrapping, returns size info for whole text block and individual lines
    textSize (text, transform, text_wrap) {
        let str = this.applyTextTransform(text, transform);
        let ctx = this.context;
        let buffer = this.text_buffer * Utils.device_pixel_ratio;
        let leading = 2 * Utils.device_pixel_ratio; // make configurable and/or use Canvas TextMetrics when available
        let line_height = this.px_size + leading; // px_size already in device pixels

        // Word wrapping
        // Line breaks can be caused by:
        //  - implicit line break when a maximum character threshold is exceeded per line (text_wrap)
        //  - explicit line break in the label text (\n)
        let words;
        if (typeof text_wrap === 'number') {
            words = str.split(' '); // split words on spaces
        }
        else {
            words = [str]; // no max line word wrapping (but new lines will still be in effect)
        }
        let new_line_template = { width: 0, chars: 0, text: '' };
        let line = Object.assign({}, new_line_template); // current line
        let lines = []; // completed lines
        let max_width = 0; // max width to fit all lines

        // add current line buffer to completed lines, optionally start new line
        function addLine (new_line) {
            line.text = line.text.trim();
            if (line.text.length > 0) {
                line.width = ctx.measureText(line.text).width;
                max_width = Math.max(max_width, Math.ceil(line.width));
                lines.push(line);
            }
            if (new_line) {
                line = Object.assign({}, new_line_template);
            }
        }

        // First iterate on space-break groups (will be one if max line length off), then iterate on line-break groups
        for (let w=0; w < words.length; w++) {
            let breaks = words[w].split('\n'); // split on line breaks

            for (let n=0; n < breaks.length; n++) {
                let word = breaks[n];

                // if adding current word would overflow, add a new line instead
                if (line.chars + word.length > text_wrap && line.chars > 0) {
                    addLine(true);
                }

                // add current word (plus space)
                line.chars += word.length + 1;
                line.text += word + ' ';

                // if line breaks present, add new line (unless on last line)
                if (breaks.length > 1 && n < breaks.length - 1) {
                    addLine(true);
                }
            }
        }
        addLine(false);

        // Final dimensions of text
        let height = lines.length * line_height;

        let collision_size = [
            max_width / Utils.device_pixel_ratio,
            height / Utils.device_pixel_ratio
        ];

        let texture_size = [
            max_width + buffer * 2,
            height + buffer * 2
        ];

        let logical_size = texture_size.map(v => v / Utils.device_pixel_ratio);

        // Returns lines (w/per-line info for drawing) and text's overall bounding box + canvas size
        return {
            lines,
            size: { collision_size, texture_size, logical_size, line_height }
        };
    }

    // Draw one or more lines of text at specified location, adjusting for buffer and baseline
    drawText (lines, [x, y], size, { stroke, transform, align }) {
        align = align || 'center';

        for (let line_num=0; line_num < lines.length; line_num++) {
            let line = lines[line_num];
            let str = this.applyTextTransform(line.text, transform);
            let buffer = this.text_buffer * Utils.device_pixel_ratio;
            let texture_size = size.texture_size;
            let line_height = size.line_height;

            // Text alignment
            let tx;
            if (align === 'left') {
                tx = x + buffer;
            }
            else if (align === 'center') {
                tx = x + texture_size[0]/2 - line.width/2;
            }
            else if (align === 'right') {
                tx = x + texture_size[0] - line.width - buffer;
            }

            // In the absence of better Canvas TextMetrics (not supported by browsers yet),
            // 0.75 buffer produces a better approximate vertical centering of text
            let ty = y + buffer * 0.75 + (line_num + 1) * line_height;

            if (stroke) {
                this.context.strokeText(str, tx, ty);
            }
            this.context.fillText(str, tx, ty);
        }
    }

    rasterize (texts, texture_size) {
        for (let style in texts) {
            let text_infos = texts[style];
            let first = true;

            for (let text in text_infos) {
                let info = text_infos[text];
                let text_settings = info.text_settings;
                let lines = CanvasText.text_cache[style][text].lines; // get previously computed lines of text

                if (first) {
                    this.setFont(text_settings);
                    first = false;
                }

                this.drawText(lines, info.position, info.size, {
                    stroke: text_settings.stroke,
                    transform: text_settings.transform,
                    align: text_settings.align
                });

                info.texcoords = Texture.getTexcoordsForSprite(
                    info.position,
                    info.size.texture_size,
                    texture_size
                );
            }
        }
    }

    // Place text labels within an atlas of the given max size
    setTextureTextPositions (texts, max_texture_size) {
        // Find widest label
        let widest = 0;
        for (let style in texts) {
            let text_infos = texts[style];
            for (let text in text_infos) {
                let size = text_infos[text].size.texture_size;
                if (size[0] > widest) {
                    widest = size[0];
                }
            }
        }

        // Layout labels, stacked in columns
        let cx = 0, cy = 0; // current x/y position in atlas
        let height = 0;     // overall atlas height
        for (let style in texts) {
            let text_infos = texts[style];
            for (let text in text_infos) {
                let text_info = text_infos[text];
                let size = text_info.size.texture_size;
                if (cy + size[1] < max_texture_size) {
                    text_info.position = [cx, cy]; // add label to current column
                    cy += size[1];
                    if (cy > height) {
                        height = cy;
                    }
                }
                else { // start new column if taller than texture
                    cx += widest;
                    cy = 0;
                    text_info.position = [cx, cy];
                }
            }
        }

        return [cx + widest, height]; // overall atlas size
    }

    // Called before rasterization
    applyTextTransform (text, transform) {
        if (transform === 'capitalize') {
            return text.replace(/\w\S*/g, function (txt) {
                return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
            });
        }
        else if (transform === 'uppercase') {
            return text.toUpperCase();
        }
        else if (transform === 'lowercase') {
            return text.toLowerCase();
        }
        return text;
    }

    // Convert font CSS-style size ('12px', '14pt', '1.5em', etc.) to pixel size (adjusted for device pixel ratio)
    // Defaults units to pixels if not specified
    static fontPixelSize (size) {
        if (size == null) {
            return;
        }
        size = (typeof size === 'string') ? size : String(size); // need a string for regex

        let [, px_size, units] = size.match(CanvasText.font_size_re) || [];
        units = units || 'px';

        if (units === "em") {
            px_size *= 16;
        } else if (units === "pt") {
            px_size /= 0.75;
        } else if (units === "%") {
            px_size /= 6.25;
        }

        px_size = parseFloat(px_size);
        px_size *= Utils.device_pixel_ratio;
        return px_size;
    }

}

// Extract font size and units
CanvasText.font_size_re = /((?:[0-9]*\.)?[0-9]+)\s*(px|pt|em|%)?/;

// Cache sizes of rendered text
CanvasText.text_cache = {}; // by text style, then text string
CanvasText.cache_stats = { hits: 0, misses: 0 };
<commit_msg>Add segments calculation<commit_after>import Utils from '../../utils/utils';
import Texture from '../../gl/texture';

export default class CanvasText {

    constructor () {
        this.canvas = document.createElement('canvas');
        this.canvas.style.backgroundColor = 'transparent'; // render text on transparent background
        this.context = this.canvas.getContext('2d');
    }

    resize (width, height) {
        this.canvas.width = width;
        this.canvas.height = height;
        this.context.clearRect(0, 0, width, height);
    }

    // Set font style params for canvas drawing
    setFont ({ font_css, fill, stroke, stroke_width, px_size }) {
        this.px_size = px_size;
        this.text_buffer = 8; // pixel padding around text
        let ctx = this.context;

        ctx.font = font_css;
        if (stroke) {
            ctx.strokeStyle = stroke;
            ctx.lineWidth = stroke_width;
        }
        else {
            ctx.strokeStyle = null;
            ctx.lineWidth = 0;
        }
        ctx.fillStyle = fill;
        ctx.miterLimit = 2;
    }

    textSizes (texts) {
        // debugger
        for (let style in texts) {
            let text_infos = texts[style];
            let first = true;

            for (let text in text_infos) {
                // Use cached size, or compute via canvas
                if (!CanvasText.text_cache[style] || !CanvasText.text_cache[style][text]) {
                    let text_settings = text_infos[text].text_settings;
                    if (first) {
                        this.setFont(text_settings);
                        first = false;
                    }

                    CanvasText.text_cache[style] = CanvasText.text_cache[style] || {};
                    CanvasText.text_cache[style][text] =
                        this.textSize(text, text_settings.transform, text_settings.text_wrap);
                    CanvasText.cache_stats.misses++;
                }
                else {
                    CanvasText.cache_stats.hits++;
                }

                // Only send text sizes back to worker (keep computed text line info
                // on main thread, for future rendering)
                text_infos[text].size = CanvasText.text_cache[style][text].size;
            }
        }

        return texts;
    }

    // Computes width and height of text based on current font style
    // Includes word wrapping, returns size info for whole text block and individual lines
    textSize (text, transform, text_wrap) {
        let str = this.applyTextTransform(text, transform);
        let ctx = this.context;
        let buffer = this.text_buffer * Utils.device_pixel_ratio;
        let leading = 2 * Utils.device_pixel_ratio; // make configurable and/or use Canvas TextMetrics when available
        let line_height = this.px_size + leading; // px_size already in device pixels

        // Word wrapping
        // Line breaks can be caused by:
        //  - implicit line break when a maximum character threshold is exceeded per line (text_wrap)
        //  - explicit line break in the label text (\n)
        let words;
        if (typeof text_wrap === 'number') {
            words = str.split(' '); // split words on spaces
        }
        else {
            words = [str]; // no max line word wrapping (but new lines will still be in effect)
        }
        let new_line_template = { width: 0, chars: 0, text: '' };
        let line = Object.assign({}, new_line_template); // current line
        let lines = []; // completed lines
        let max_width = 0; // max width to fit all lines

        // add current line buffer to completed lines, optionally start new line
        function addLine (new_line) {
            line.text = line.text.trim();
            if (line.text.length > 0) {
                line.width = ctx.measureText(line.text).width;
                max_width = Math.max(max_width, Math.ceil(line.width));

                var segments = line.text.split(' ');
                line.segments = [];
                for (var i = 0; i < segments.length; i++){
                    var str = segments[i];
                    if (i > 0 && i < segments.length) str += ' ';
                    line.segments.push(ctx.measureText(str).width);
                }

                lines.push(line);
            }
            if (new_line) {
                line = Object.assign({}, new_line_template);
            }
        }

        // First iterate on space-break groups (will be one if max line length off), then iterate on line-break groups
        for (let w=0; w < words.length; w++) {
            let breaks = words[w].split('\n'); // split on line breaks

            for (let n=0; n < breaks.length; n++) {
                let word = breaks[n];

                // if adding current word would overflow, add a new line instead
                if (line.chars + word.length > text_wrap && line.chars > 0) {
                    addLine(true);
                }

                // add current word (plus space)
                line.chars += word.length + 1;
                line.text += word + ' ';

                // if line breaks present, add new line (unless on last line)
                if (breaks.length > 1 && n < breaks.length - 1) {
                    addLine(true);
                }
            }
        }
        addLine(false);

        // Final dimensions of text
        let height = lines.length * line_height;

        let collision_size = [
            max_width / Utils.device_pixel_ratio,
            height / Utils.device_pixel_ratio
        ];

        let texture_size = [
            max_width + buffer * 2,
            height + buffer * 2
        ];

        let logical_size = texture_size.map(v => v / Utils.device_pixel_ratio);

        // Returns lines (w/per-line info for drawing) and text's overall bounding box + canvas size
        return {
            lines,
            size: { collision_size, texture_size, logical_size, line_height }
        };
    }

    // Draw one or more lines of text at specified location, adjusting for buffer and baseline
    drawText (lines, [x, y], size, { stroke, transform, align }) {
        align = align || 'center';

        for (let line_num=0; line_num < lines.length; line_num++) {
            let line = lines[line_num];
            let str = this.applyTextTransform(line.text, transform);
            let buffer = this.text_buffer * Utils.device_pixel_ratio;
            let texture_size = size.texture_size;
            let line_height = size.line_height;

            // Text alignment
            let tx;
            if (align === 'left') {
                tx = x + buffer;
            }
            else if (align === 'center') {
                tx = x + texture_size[0]/2 - line.width/2;
            }
            else if (align === 'right') {
                tx = x + texture_size[0] - line.width - buffer;
            }

            // In the absence of better Canvas TextMetrics (not supported by browsers yet),
            // 0.75 buffer produces a better approximate vertical centering of text
            let ty = y + buffer * 0.75 + (line_num + 1) * line_height;

            if (stroke) {
                this.context.strokeText(str, tx, ty);
            }
            this.context.fillText(str, tx, ty);
        }
    }

    rasterize (texts, texture_size) {
        for (let style in texts) {
            let text_infos = texts[style];
            let first = true;

            for (let text in text_infos) {
                let info = text_infos[text];
                let text_settings = info.text_settings;
                let lines = CanvasText.text_cache[style][text].lines; // get previously computed lines of text

                if (first) {
                    this.setFont(text_settings);
                    first = false;
                }

                this.drawText(lines, info.position, info.size, {
                    stroke: text_settings.stroke,
                    transform: text_settings.transform,
                    align: text_settings.align
                });

                info.texcoords = Texture.getTexcoordsForSprite(
                    info.position,
                    info.size.texture_size,
                    texture_size
                );
            }
        }
    }

    // Place text labels within an atlas of the given max size
    setTextureTextPositions (texts, max_texture_size) {
        // Find widest label
        let widest = 0;
        for (let style in texts) {
            let text_infos = texts[style];
            for (let text in text_infos) {
                let size = text_infos[text].size.texture_size;
                if (size[0] > widest) {
                    widest = size[0];
                }
            }
        }

        // Layout labels, stacked in columns
        let cx = 0, cy = 0; // current x/y position in atlas
        let height = 0;     // overall atlas height
        for (let style in texts) {
            let text_infos = texts[style];
            for (let text in text_infos) {
                let text_info = text_infos[text];
                let size = text_info.size.texture_size;
                if (cy + size[1] < max_texture_size) {
                    text_info.position = [cx, cy]; // add label to current column
                    cy += size[1];
                    if (cy > height) {
                        height = cy;
                    }
                }
                else { // start new column if taller than texture
                    cx += widest;
                    cy = 0;
                    text_info.position = [cx, cy];
                }
            }
        }

        return [cx + widest, height]; // overall atlas size
    }

    // Called before rasterization
    applyTextTransform (text, transform) {
        if (transform === 'capitalize') {
            return text.replace(/\w\S*/g, function (txt) {
                return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
            });
        }
        else if (transform === 'uppercase') {
            return text.toUpperCase();
        }
        else if (transform === 'lowercase') {
            return text.toLowerCase();
        }
        return text;
    }

    // Convert font CSS-style size ('12px', '14pt', '1.5em', etc.) to pixel size (adjusted for device pixel ratio)
    // Defaults units to pixels if not specified
    static fontPixelSize (size) {
        if (size == null) {
            return;
        }
        size = (typeof size === 'string') ? size : String(size); // need a string for regex

        let [, px_size, units] = size.match(CanvasText.font_size_re) || [];
        units = units || 'px';

        if (units === "em") {
            px_size *= 16;
        } else if (units === "pt") {
            px_size /= 0.75;
        } else if (units === "%") {
            px_size /= 6.25;
        }

        px_size = parseFloat(px_size);
        px_size *= Utils.device_pixel_ratio;
        return px_size;
    }

}

// Extract font size and units
CanvasText.font_size_re = /((?:[0-9]*\.)?[0-9]+)\s*(px|pt|em|%)?/;

// Cache sizes of rendered text
CanvasText.text_cache = {}; // by text style, then text string
CanvasText.cache_stats = { hits: 0, misses: 0 };
<|endoftext|>