<commit_before>/* eslint-disable no-unused-vars */
var Issue = require('../utils').issues.Issue;
var files = require('../utils/files');
var utils  = require('../utils');

/**
 * TSV
 *
 * Takes a TSV file as a string and a callback
 * as arguments. And callsback with any issues
 * it finds while validating against the BIDS
 * specification.
 */
var TSV = function TSV (file, contents, fileList, callback) {

    var issues = [];
    var rows = contents.split('\n');
    var headers = rows[0].split('\t');

// generic checks -----------------------------------------------------------

    var columnMismatch = false;
    var emptyCells     = false;
    var NACells        = false;
    // iterate rows
    for (var i = 0; i < rows.length; i++) {
        var row = rows[i];
        if (columnMismatch && emptyCells && NACells) {break;}

        // skip empty rows
        if (!row || /^\s*$/.test(row)) {continue;}

        var values = row.split('\t');

        // check for different length rows
        if (values.length !== headers.length && !columnMismatch) {
            columnMismatch = true;
            issues.push(new Issue({
                file: file,
                evidence: row,
                line: i + 1,
                code: 22
            }));
        }

        // iterate values
        for (var j = 0; j < values.length; j++) {
            var value = values[j];
            if (columnMismatch && emptyCells && NACells) {break;}

            if (value === "" && !emptyCells) {
                emptyCells = true;
                // empty cell should raise an error
                issues.push(new Issue({
                    file: file,
                    evidence: row,
                    line: i + 1,
                    character: "at column # " + (j+1),
                    code: 23
                }));
            } else if ((value === "NA" || value === "na" || value === "nan") && !NACells) {
                NACells = true;
                // check if missing value is properly labeled as 'n/a'
                issues.push(new Issue({
                    file: file,
                    evidence: row,
                    line: i + 1,
                    character: "at column # " + (j+1),
                    code: 24
                }));
            }
        }
    }

// specific file checks -----------------------------------------------------

    // events.tsv
    if (file.name.endsWith('_events.tsv')) {
        if ((headers.length == 0) || (headers[0] !== "onset")){
            issues.push(new Issue({
                file: file,
                evidence: headers,
                line: 1,
                character: rows[0].indexOf(headers[0]),
                code: 20
            }));
        }
        if ((headers.length <= 1) || (headers[1].trim() !== "duration")){
            issues.push(new Issue({
                file: file,
                evidence: headers,
                line: 1,
                character: rows[0].indexOf(headers[1]),
                code: 21
            }));
        }

        // create full dataset path list
        var pathList = [];
        for (var f in fileList) {
            pathList.push(fileList[f].relativePath);
        }

        // check for stimuli file presence
        var stimFiles = [];
        if (headers.indexOf('stim_file') > -1) {
            for (var k = 0; k < rows.length; k++) {
                var stimFile = rows[k].split('\t')[headers.indexOf('stim_file')];
                if (stimFile && stimFile !== 'n/a' && stimFile !== 'stim_file' && stimFiles.indexOf(stimFile) == -1) {
                    stimFiles.push(stimFile);
                    if (pathList.indexOf('/stimuli/' + stimFile) == -1) {
                        issues.push(new Issue({
                            file: file,
                            evidence: stimFile,
                            reason: 'A stimulus file (' + stimFile + ') was declared but not found in /stimuli.',
                            line: k + 1,
                            character: rows[k].indexOf(stimFile),
                            code: 52
                        }));
                    }
                }
            }
        }
    }

    // participants.tsv
    var participants = null;
    if (file.name === 'participants.tsv' || file.relativePath.includes('phenotype/')) {
        var participantIdColumn = headers.indexOf('participant_id');
        if (participantIdColumn === -1) {
            issues.push(new Issue({
                file: file,
                evidence: headers.join('\t'),
                line: 1,
                code: 48
            }));
        } else {
            participants = [];
            for (var l = 1; l < rows.length; l++) {
                row = rows[l].split('\t');
                // skip empty rows
                if (!row || /^\s*$/.test(row)) {continue;}
                participants.push(row[participantIdColumn].replace('sub-', ''));
            }
        }

    }
  // check partcipants.tsv for age 89+

    if (file.name === 'participants.tsv'){
        checkage89_plus(rows, file, issues);
    }

  // check _scans.tsv for column filename

    if(file.name.endsWith('_scans.tsv')){
      if(!(headers.indexOf('filename') > -1)){
        issues.push(new Issue({
            line: 1,
            file: file,
            evidence: headers.join('\t'),
            code: 68
        }));
      }
    }

    callback(issues, participants);
};
var checkphenotype = function (phenotypeParticipants, summary, issues) {
    for (var j=0; j < phenotypeParticipants.length; j++){
        var fileParticpants = phenotypeParticipants[j];
        if (phenotypeParticipants && phenotypeParticipants.length > 0 && (!utils.array.equals(fileParticpants.list, summary.subjects.sort(), true))) {
            issues.push(new Issue({
                code: 51,
                evidence: fileParticpants.file + "- " + fileParticpants.list + "  Subjects -" + fileParticpants,
                file: fileParticpants.file
            }));
        }
    }
};

var checkage89_plus = function(rows, file, issues){
    var header = rows[0].trim().split('\t');
    var ageIdColumn = header.indexOf("age");
    for (var a = 0; a < rows.length; a++) {
        var line = rows[a];
        var line_values = line.trim().split('\t');
        var age = line_values[ageIdColumn];
        if (age >= 89) {
            issues.push(new Issue({
                file: file,
                evidence: line,
                line: a + 1,
                character: "age of partcipant is above 89 ",
                code: 56
            }));
        }
    }
};
module.exports = {
    TSV: TSV,
    checkphenotype : checkphenotype
};
<commit_msg>better handling of missing headers<commit_after>/* eslint-disable no-unused-vars */
var Issue = require('../utils').issues.Issue;
var files = require('../utils/files');
var utils  = require('../utils');

/**
 * TSV
 *
 * Takes a TSV file as a string and a callback
 * as arguments. And callsback with any issues
 * it finds while validating against the BIDS
 * specification.
 */
var TSV = function TSV (file, contents, fileList, callback) {

    var issues = [];
    var rows = contents.split('\n');
    var headers = rows[0].split('\t');

// generic checks -----------------------------------------------------------

    var columnMismatch = false;
    var emptyCells     = false;
    var NACells        = false;
    // iterate rows
    for (var i = 0; i < rows.length; i++) {
        var row = rows[i];
        if (columnMismatch && emptyCells && NACells) {break;}

        // skip empty rows
        if (!row || /^\s*$/.test(row)) {continue;}

        var values = row.split('\t');

        // check for different length rows
        if (values.length !== headers.length && !columnMismatch) {
            columnMismatch = true;
            issues.push(new Issue({
                file: file,
                evidence: row,
                line: i + 1,
                code: 22
            }));
        }

        // iterate values
        for (var j = 0; j < values.length; j++) {
            var value = values[j];
            if (columnMismatch && emptyCells && NACells) {break;}

            if (value === "" && !emptyCells) {
                emptyCells = true;
                // empty cell should raise an error
                issues.push(new Issue({
                    file: file,
                    evidence: row,
                    line: i + 1,
                    character: "at column # " + (j+1),
                    code: 23
                }));
            } else if ((value === "NA" || value === "na" || value === "nan") && !NACells) {
                NACells = true;
                // check if missing value is properly labeled as 'n/a'
                issues.push(new Issue({
                    file: file,
                    evidence: row,
                    line: i + 1,
                    character: "at column # " + (j+1),
                    code: 24
                }));
            }
        }
    }

// specific file checks -----------------------------------------------------

    // events.tsv
    if (file.name.endsWith('_events.tsv')) {
        if ((headers.length == 0) || (headers[0] !== "onset")){
            issues.push(new Issue({
                file: file,
                evidence: headers,
                line: 1,
                code: 20
            }));
        }
        if ((headers.length == 1) || (headers[1].trim() !== "duration")){
            issues.push(new Issue({
                file: file,
                evidence: headers,
                line: 1,
                code: 21
            }));
        }

        // create full dataset path list
        var pathList = [];
        for (var f in fileList) {
            pathList.push(fileList[f].relativePath);
        }

        // check for stimuli file presence
        var stimFiles = [];
        if (headers.indexOf('stim_file') > -1) {
            for (var k = 0; k < rows.length; k++) {
                var stimFile = rows[k].split('\t')[headers.indexOf('stim_file')];
                if (stimFile && stimFile !== 'n/a' && stimFile !== 'stim_file' && stimFiles.indexOf(stimFile) == -1) {
                    stimFiles.push(stimFile);
                    if (pathList.indexOf('/stimuli/' + stimFile) == -1) {
                        issues.push(new Issue({
                            file: file,
                            evidence: stimFile,
                            reason: 'A stimulus file (' + stimFile + ') was declared but not found in /stimuli.',
                            line: k + 1,
                            character: rows[k].indexOf(stimFile),
                            code: 52
                        }));
                    }
                }
            }
        }
    }

    // participants.tsv
    var participants = null;
    if (file.name === 'participants.tsv' || file.relativePath.includes('phenotype/')) {
        var participantIdColumn = headers.indexOf('participant_id');
        if (participantIdColumn === -1) {
            issues.push(new Issue({
                file: file,
                evidence: headers.join('\t'),
                line: 1,
                code: 48
            }));
        } else {
            participants = [];
            for (var l = 1; l < rows.length; l++) {
                row = rows[l].split('\t');
                // skip empty rows
                if (!row || /^\s*$/.test(row)) {continue;}
                participants.push(row[participantIdColumn].replace('sub-', ''));
            }
        }

    }
  // check partcipants.tsv for age 89+

    if (file.name === 'participants.tsv'){
        checkage89_plus(rows, file, issues);
    }

  // check _scans.tsv for column filename

    if(file.name.endsWith('_scans.tsv')){
      if(!(headers.indexOf('filename') > -1)){
        issues.push(new Issue({
            line: 1,
            file: file,
            evidence: headers.join('\t'),
            code: 68
        }));
      }
    }

    callback(issues, participants);
};
var checkphenotype = function (phenotypeParticipants, summary, issues) {
    for (var j=0; j < phenotypeParticipants.length; j++){
        var fileParticpants = phenotypeParticipants[j];
        if (phenotypeParticipants && phenotypeParticipants.length > 0 && (!utils.array.equals(fileParticpants.list, summary.subjects.sort(), true))) {
            issues.push(new Issue({
                code: 51,
                evidence: fileParticpants.file + "- " + fileParticpants.list + "  Subjects -" + fileParticpants,
                file: fileParticpants.file
            }));
        }
    }
};

var checkage89_plus = function(rows, file, issues){
    var header = rows[0].trim().split('\t');
    var ageIdColumn = header.indexOf("age");
    for (var a = 0; a < rows.length; a++) {
        var line = rows[a];
        var line_values = line.trim().split('\t');
        var age = line_values[ageIdColumn];
        if (age >= 89) {
            issues.push(new Issue({
                file: file,
                evidence: line,
                line: a + 1,
                character: "age of partcipant is above 89 ",
                code: 56
            }));
        }
    }
};
module.exports = {
    TSV: TSV,
    checkphenotype : checkphenotype
};
<|endoftext|>


<commit_before>function sensordata_chart(title, subtitle, units, short_units, dataArray1, rendor_to, line_color) {
    //Its getting confusing to just keep putting variables in in order. Should we refactor to use a JSON or Dict? - CM
    console.log('about to crate chart to put in ' + rendor_to);
    // Get the graph extremes
    var startDate =new Date(window.starttime);
    var startUTC = startDate.getTime() + startDate.getTimezoneOffset() * 60000;
    var endDate = new Date(window.endtime);
    var endUTC = endDate.getTime() + endDate.getTimezoneOffset() * 60000;

    var chart = new Highcharts.Chart({
        chart: {
	    renderTo: rendor_to,
            type: 'spline'
        },
        title: {
            text: null
        },
        subtitle: {
            text: null
        },
        xAxis: {
	    min: startUTC,
	    max: endUTC,
	    title: {
		text: null
	    }
        },
        yAxis: {
            title: {
                text: null
            }
        },
        tooltip: {
            formatter: function() {
		return ''+ this.series.name +'
'+
		    Highcharts.dateFormat('%Y/%m/%d %H:%M', this.x) +': '+ this.y +' ' + short_units;
            }
        },
        series: [{
	    name: title,
	    color: line_color,
	    data: dataArray1
	}]
    });
    return chart;
}

function ajax_make_chart(sensorid, starttime, endtime) {
    console.log('GetJSON for ' + sensorid + ' starttime: ' +starttime);
    $.getJSON('/explorer/get_data_ajax/',{'sensorid': sensorid, 'starttime': starttime, 'endtime': endtime})
	.done(function(data) {
	    //make the div use chart-row template
	    var chart_source = $('#chart-row').html();
	    var chart_template = Handlebars.compile(chart_source); //I wonder if I really need to be doing this compile over and over again like this?
	    var legend_data = {
		sensorid: sensorid,
		title: data.plot_short_name,
		subtitle: data.plot_source_id,
		units: data.plot_units_short+' '+data.plot_units_long
	    };
	    $('#charts').append(chart_template(legend_data));
	    var chart_id = sensorid + "-chart";
	    if (data.goodPlotData) {
		var chart = sensordata_chart(data.plot_short_name, data.plot_source_id, data.plot_units_long, data.plot_units_short, data.data_array1, chart_id, data.line_color);
		chartList[sensorid] = chart;

//		console.log(chartList);
//		syncronizeCrossHairs(chart);
		$('.'+sensorid).button('reset');  //Reset the loading on the button
	    } else {
		var errorClass = 'alert alert-warning';
		$('#'+chart_id).html('
'+data.plotError+'
');
		$('.'+sensorid).button('reset');  //Reset the loading on the button
	    }
	})
	.fail(function(jqxhr, textStatus, error) {
	    var err = textStatus + ", " + error;
	    console.log( "Request Failed: " + err );
	});
	$('body').animate({"scrollTop": $(document).height()}, "slow");
};

function syncronizeCrossHairs(chart) {
    var container = $(chart.container),
    offset = container.offset(),
    x, y, isInside, report;

    container.mousemove(function (evt) {

        x = evt.clientX - chart.plotLeft - offset.left;
        y = evt.clientY - chart.plotTop - offset.top;
        var xAxis = chart.xAxis[0];
        //remove old plot line and draw new plot line (crosshair) for this chart
        var xAxis1 = chart.xAxis[0];
        xAxis1.removePlotLine("myPlotLineId");
        xAxis1.addPlotLine({
            value: chart.xAxis[0].translate(x, true),
            width: 1,
            color: 'red',
            //dashStyle: 'dash',
            id: "myPlotLineId"
        });
    });
}

function syncZoom(zoomEvent) {

    var min = zoomEvent.min;
    console.log('syncZoom Ran!' + min);
}
<commit_msg>zoom sync works!<commit_after>function sensordata_chart(title, subtitle, units, short_units, dataArray1, rendor_to, line_color) {
    //Its getting confusing to just keep putting variables in in order. Should we refactor to use a JSON or Dict? - CM
    console.log('about to crate chart to put in ' + rendor_to);
    // Get the graph extremes
    var startDate =new Date(window.starttime);
    var startUTC = startDate.getTime() + startDate.getTimezoneOffset() * 60000;
    var endDate = new Date(window.endtime);
    var endUTC = endDate.getTime() + endDate.getTimezoneOffset() * 60000;

    var chart = new Highcharts.Chart({
        chart: {
	    renderTo: rendor_to,
            type: 'spline'
        },
        title: {
            text: null
        },
        subtitle: {
            text: null
        },
        xAxis: {
	    min: startUTC,
	    max: endUTC,
	    title: {
		text: null
	    }
        },
        yAxis: {
            title: {
                text: null
            }
        },
        tooltip: {
            formatter: function() {
		return ''+ this.series.name +'
'+
		    Highcharts.dateFormat('%Y/%m/%d %H:%M', this.x) +': '+ this.y +' ' + short_units;
            }
        },
        series: [{
	    name: title,
	    color: line_color,
	    data: dataArray1
	}]
    });
    return chart;
}

function ajax_make_chart(sensorid, starttime, endtime) {
    console.log('GetJSON for ' + sensorid + ' starttime: ' +starttime);
    $.getJSON('/explorer/get_data_ajax/',{'sensorid': sensorid, 'starttime': starttime, 'endtime': endtime})
	.done(function(data) {
	    //make the div use chart-row template
	    var chart_source = $('#chart-row').html();
	    var chart_template = Handlebars.compile(chart_source); //I wonder if I really need to be doing this compile over and over again like this?
	    var legend_data = {
		sensorid: sensorid,
		title: data.plot_short_name,
		subtitle: data.plot_source_id,
		units: data.plot_units_short+' '+data.plot_units_long
	    };
	    $('#charts').append(chart_template(legend_data));
	    var chart_id = sensorid + "-chart";
	    if (data.goodPlotData) {
		var chart = sensordata_chart(data.plot_short_name, data.plot_source_id, data.plot_units_long, data.plot_units_short, data.data_array1, chart_id, data.line_color);
		chartList[sensorid] = chart;

//		console.log(chartList);
//		syncronizeCrossHairs(chart);
		$('.'+sensorid).button('reset');  //Reset the loading on the button
	    } else {
		var errorClass = 'alert alert-warning';
		$('#'+chart_id).html('
'+data.plotError+'
');
		$('.'+sensorid).button('reset');  //Reset the loading on the button
	    }
	})
	.fail(function(jqxhr, textStatus, error) {
	    var err = textStatus + ", " + error;
	    console.log( "Request Failed: " + err );
	});
	$('body').animate({"scrollTop": $(document).height()}, "slow");
};

function syncronizeCrossHairs(chart) {
    var container = $(chart.container),
    offset = container.offset(),
    x, y, isInside, report;

    container.mousemove(function (evt) {

        x = evt.clientX - chart.plotLeft - offset.left;
        y = evt.clientY - chart.plotTop - offset.top;
        var xAxis = chart.xAxis[0];
        //remove old plot line and draw new plot line (crosshair) for this chart
        var xAxis1 = chart.xAxis[0];
        xAxis1.removePlotLine("myPlotLineId");
        xAxis1.addPlotLine({
            value: chart.xAxis[0].translate(x, true),
            width: 1,
            color: 'red',
            //dashStyle: 'dash',
            id: "myPlotLineId"
        });
    });
}

function syncZoom(zoomEvent) {

    var min = zoomEvent.min;
    var max = zoomEvent.max;

    //let run through all the charts and set them all to this min/max
    $('div#charts > div').each(function() {
	s_id = $(this).attr('data-sensorid');
	    var chartIndex = $("#"+s_id+"-chart").data('highchartsChart');
	    console.log('chartindex is' + chartIndex);
	    if (typeof chartIndex === 'number') {    //error messages will have undefined chartIndex
		var thisChart = Highcharts.charts[chartIndex];
		var thisXAxis = thisChart.xAxis[0].getExtremes();
		console.log(s_id + ' max is ' + thisXAxis.max + ' max is ' + max);
		if (thisXAxis.min != min || thisXAxis.max != max) {
		    thisChart.xAxis[0].setExtremes(min, max, true);
		}
	    }
    });
}
<|endoftext|>


<commit_before>module.exports = {
  "apps": [
    {
      "name": "cleaner",
      "script": "./server/cleaner/index.js",
      // "watch": true
      // "env": {
      //   "NODE_ENV": "development"
      // },
      // "env_production": {
      //   "NODE_ENV": "production"
      // }
    },
    {
      "name": "app",
      "script": "./server/app.js"
    }
  ]
}
<commit_msg>updated simple.config<commit_after>module.exports = {
  "apps": [
    {
      "name": "cleaner",
      "script": "./server/core/cleaner/index.js",
      // "watch": true
      // "env": {
      //   "NODE_ENV": "development"
      // },
      // "env_production": {
      //   "NODE_ENV": "production"
      // }
    },
    {
      "name": "app",
      "script": "./server/app.js"
    }
  ]
}
<|endoftext|>


<commit_before>import client from './client';
import debug from 'debug';
import Signal from '../../utils/Signal';
import SignalAll from '../../utils/SignalAll';

const log = debug('soundworks:serviceManager');

const _instances = {};
const _ctors = {};

/**
 * Factory and initialisation manager for the services.
 * Lazy instanciate an instance of the given type and retrieve it on each call.
 */
const serviceManager = {
  _serviceInstanciationHook: null,

  /**
   * Initialize the manager.
   */
  init() {
    log('init');
    this._requiredSignals = new SignalAll();
    this._requiredSignals.addObserver(() => this.ready());

    this.signals = {};
    this.signals.start = new Signal();
    this.signals.ready = new Signal();
  },

  /**
   * Sends the signal required by all services to start.
   */
  start() {
    log('start');

    const networkedServices = [];

    this.signals.start.set(true);

    if (!this._requiredSignals.length)
      this.ready();
  },

  /**
   * Mark the services as ready. This signal is observed by {@link Experience}
   * instances and trigger their `start`.
   */
  ready() {
    log('ready');
    this.signals.ready.set(true);
  },

  /**
   * Returns an instance of a service with options to be applied to its constructor.
   * @param {String} id - The id of the service.
   * @param {Object} options - Options to pass to the service constructor.
   */
  require(id, options = {}) {
    id = 'service:' + id;

    if (!_ctors[id])
      throw new Error(`Service "${id}" is not defined`);

    let instance = _instances[id];

    if (!instance) {
      // throw an error if manager already started
      if (this.signals.start.get() === true)
        throw new Error(`Service "${id}" required after application start`);

      instance = new _ctors[id]();

      if (this._serviceInstanciationHook !== null)
        this._serviceInstanciationHook(id, instance);

      // add the instance ready signal as required for the manager
      this._requiredSignals.add(instance.signals.ready);
      // store instance
      _instances[id] = instance;
    }

    instance.configure(options);
    return instance;
  },

  /**
   * Register a function to be executed when a service is instanciated.
   *
   * @param {serviceManager~serviceInstanciationHook} func - Function to
   *  register has a hook to be execute when a service is created.
   */
  /**
   * @callback serviceManager~serviceInstanciationHook
   * @param {String} id - id of the instanciated service.
   * @param {Service} instance - instance of the service.
   */
  setServiceInstanciationHook(func) {
    this._serviceInstanciationHook = func;
  },

  /**
   * Register a service with a given id.
   * @param {String} id - The id of the service.
   * @param {Function} ctor - The constructor of the service.
   */
  register(id, ctor) {
    _ctors[id] = ctor;
  },

  getRequiredServices() {
    return Object.keys(_instances);
  },
};

export default serviceManager;

<commit_msg>modified error message if service is required too late<commit_after>import client from './client';
import debug from 'debug';
import Signal from '../../utils/Signal';
import SignalAll from '../../utils/SignalAll';

const log = debug('soundworks:serviceManager');

const _instances = {};
const _ctors = {};

/**
 * Factory and initialisation manager for the services.
 * Lazy instanciate an instance of the given type and retrieve it on each call.
 */
const serviceManager = {
  _serviceInstanciationHook: null,

  /**
   * Initialize the manager.
   */
  init() {
    log('init');
    this._requiredSignals = new SignalAll();
    this._requiredSignals.addObserver(() => this.ready());

    this.signals = {};
    this.signals.start = new Signal();
    this.signals.ready = new Signal();
  },

  /**
   * Sends the signal required by all services to start.
   */
  start() {
    log('start');

    const networkedServices = [];

    this.signals.start.set(true);

    if (!this._requiredSignals.length)
      this.ready();
  },

  /**
   * Mark the services as ready. This signal is observed by {@link Experience}
   * instances and trigger their `start`.
   */
  ready() {
    log('ready');
    this.signals.ready.set(true);
  },

  /**
   * Returns an instance of a service with options to be applied to its constructor.
   * @param {String} id - The id of the service.
   * @param {Object} options - Options to pass to the service constructor.
   */
  require(id, options = {}) {
    id = 'service:' + id;

    if (!_ctors[id])
      throw new Error(`Service "${id}" is not defined`);

    let instance = _instances[id];

    if (!instance) {
      // throw an error if manager already started
      if (this.signals.start.get() === true)
        throw new Error(`Service "${id}" required after serviceManager start`);

      instance = new _ctors[id]();

      if (this._serviceInstanciationHook !== null)
        this._serviceInstanciationHook(id, instance);

      // add the instance ready signal as required for the manager
      this._requiredSignals.add(instance.signals.ready);
      // store instance
      _instances[id] = instance;
    }

    instance.configure(options);
    return instance;
  },

  /**
   * Register a function to be executed when a service is instanciated.
   *
   * @param {serviceManager~serviceInstanciationHook} func - Function to
   *  register has a hook to be execute when a service is created.
   */
  /**
   * @callback serviceManager~serviceInstanciationHook
   * @param {String} id - id of the instanciated service.
   * @param {Service} instance - instance of the service.
   */
  setServiceInstanciationHook(func) {
    this._serviceInstanciationHook = func;
  },

  /**
   * Register a service with a given id.
   * @param {String} id - The id of the service.
   * @param {Function} ctor - The constructor of the service.
   */
  register(id, ctor) {
    _ctors[id] = ctor;
  },

  getRequiredServices() {
    return Object.keys(_instances);
  },
};

export default serviceManager;

<|endoftext|>


<commit_before>import autobahn from 'autobahn';
import emitter from './emitter';

class Transport extends emitter {

  constructor(url = 'ws://localhost:8080/ws', realm = 'com.weareadaptive.reactivetrader'){
    super();
    this.connection = new autobahn.Connection({
      url,
      realm,
      use_es6_promises: true
    });

    this.session = {
      subscriptions: []
    };

    this.connection.onopen = (ws) => {
      this.session = ws;
      this.trigger('open');
    };

    this.connection.onclose = () => {
      this.trigger('close');
    };

     this.connection.open();
  }

  subscribe(event, callback, options = {}){
    const reply = _.uniqueId(event);

    this.session.subscribe(reply, (a) => {
      callback(a[0]);
    }, options).then(()=> this.session.call(event, [{
      ReplyTo: reply,
      Payload: options
    }]));
  }

  unsubscribe(...args){
    return this.session.unsubscribe(...args);
  }

  publish(...args){
    return this.session.publish(...args);
  }

  open(){
    return this.session.open();
  }

  close(){
    return this.session.close();
  }

  // connection getters
  get isConnected(){
    return this.connection.isConnected;
  }

  get isOpen(){
    return this.connection.isOpen;
  }

  get isRetrying(){
    return this.connection.isRetrying;
  }

  get info(){
    return this.connection.info;
  }

  // session getters
  get subscriptions(){
    return this.session.subscriptions;
  }

  get features(){
    return this.session.features;
  }

  log(...args){
    this.session.log(...args);
  }

  prefix(...args){
    this.session.prefix(...args);
  }

}

export default new Transport;
<commit_msg>split rpc call from subscription<commit_after>import autobahn from 'autobahn';
import emitter from './emitter';
import _ from 'lodash';

class Transport extends emitter {

  constructor(url = 'ws://localhost:8080/ws', realm = 'com.weareadaptive.reactivetrader'){
    super();
    this.connection = new autobahn.Connection({
      url,
      realm,
      use_es6_promises: true
    });

    this.session = {
      subscriptions: []
    };

    this.connection.onopen = (ws) => {
      this.session = ws;
      this.trigger('open');
    };

    this.connection.onclose = () => {
      this.trigger('close');
    };

    this.services = {};

    this.monitor = _.debounce(this.monitor, 5000);
    this.connection.open();
  }

  subscribe(event, callback, options = {}){
    const reply = _.uniqueId(event);

    this.session.subscribe(reply, (a) => {
      callback(a[0]);
    }, options).then(() => this.sessionRPC({
        ReplyTo: reply,
        Payload: options,
        event
      }));
  }

  sessionRPC(obj){
    // console.log(response);
    const { event } = obj;
    delete obj.event;

    this.session.call(event, [obj]).then((rpcResponse) => {
      rpcResponse.InstanceID in this.services || (this.services[rpcResponse.InstanceID] = []);
      this.services[rpcResponse.InstanceID] = obj;
      this.services[rpcResponse.InstanceID].event = event;
    });
  }

  unsubscribe(...args){
    return this.session.unsubscribe(...args);
  }

  monitor(){
    this.log('Connection has gone down');
  }

  publish(...args){
    return this.session.publish(...args);
  }

  open(){
    return this.session.open();
  }

  close(){
    return this.session.close();
  }

  // connection getters
  get isConnected(){
    return this.connection.isConnected;
  }

  get isOpen(){
    return this.connection.isOpen;
  }

  get isRetrying(){
    return this.connection.isRetrying;
  }

  get info(){
    return this.connection.info;
  }

  // session getters
  get subscriptions(){
    return this.session.subscriptions;
  }

  get features(){
    return this.session.features;
  }

  log(...args){
    this.session.log(...args);
  }

  prefix(...args){
    this.session.prefix(...args);
  }

}

export default new Transport;
<|endoftext|>


<commit_before>// borrow the slice method
const toArray = Function.prototype.call.bind(Array.prototype.slice)

export default function _updateTags (options = {}) {
  const { attribute } = options

  /**
   * Updates meta tags inside <head> on the client. Borrowed from `react-helmet`:
   * https://github.com/nfl/react-helmet/blob/004d448f8de5f823d10f838b02317521180f34da/src/Helmet.js#L195-L245
   *
   * @param  {('meta'|'base'|'link'|'style'|'script'|'noscript')} type - the name of the tag
   * @param  {(Array<Object>|Object)} tags - an array of tag objects or a single object in case of base
   * @return {Object} - a representation of what tags changed
   */
  return function updateTags (type, tags, headTag) {
    const nodes = headTag.querySelectorAll(`${type}[${attribute}]`)
    const oldTags = toArray(nodes)
    const newTags = []
    let indexToDelete

    if (tags.length > 1) {
      // remove duplicates that could have been found by merging tags
      // which include a mixin with metaInfo and that mixin is used
      // by multiple components on the same page
      const found = []
      tags = tags.map(x => {
        const k = JSON.stringify(x)
        if (found.indexOf(k) < 0) {
          found.push(k)
          return x
        }
      }).filter(x => x)
    }

    if (tags && tags.length) {
      tags.forEach((tag) => {
        const newElement = document.createElement(type)

        for (const attr in tag) {
          if (tag.hasOwnProperty(attr)) {
            if (attr === 'innerHTML') {
              newElement.innerHTML = tag.innerHTML
            } else if (attr === 'cssText') {
              if (newElement.styleSheet) {
                newElement.styleSheet.cssText = tag.cssText
              } else {
                newElement.appendChild(document.createTextNode(tag.cssText))
              }
            } else {
              const value = (typeof tag[attr] === 'undefined') ? '' : tag[attr]
              newElement.setAttribute(attr, value)
            }
          }
        }

        newElement.setAttribute(attribute, 'true')

        // Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
        if (oldTags.some((existingTag, index) => {
          indexToDelete = index
          return newElement.isEqualNode(existingTag)
        })) {
          oldTags.splice(indexToDelete, 1)
        } else {
          newTags.push(newElement)
        }
      })
    }

    oldTags.forEach((tag) => tag.parentNode.removeChild(tag))
    newTags.forEach((tag) => headTag.appendChild(tag))

    return { oldTags, newTags }
  }
}
<commit_msg>Use data- for vmid to generate valid HTML<commit_after>// borrow the slice method
const toArray = Function.prototype.call.bind(Array.prototype.slice)

export default function _updateTags (options = {}) {
  const { attribute } = options

  /**
   * Updates meta tags inside <head> on the client. Borrowed from `react-helmet`:
   * https://github.com/nfl/react-helmet/blob/004d448f8de5f823d10f838b02317521180f34da/src/Helmet.js#L195-L245
   *
   * @param  {('meta'|'base'|'link'|'style'|'script'|'noscript')} type - the name of the tag
   * @param  {(Array<Object>|Object)} tags - an array of tag objects or a single object in case of base
   * @return {Object} - a representation of what tags changed
   */
  return function updateTags (type, tags, headTag) {
    const nodes = headTag.querySelectorAll(`${type}[${attribute}]`)
    const oldTags = toArray(nodes)
    const newTags = []
    let indexToDelete

    if (tags.length > 1) {
      // remove duplicates that could have been found by merging tags
      // which include a mixin with metaInfo and that mixin is used
      // by multiple components on the same page
      const found = []
      tags = tags.map(x => {
        const k = JSON.stringify(x)
        if (found.indexOf(k) < 0) {
          found.push(k)
          return x
        }
      }).filter(x => x)
    }

    if (tags && tags.length) {
      tags.forEach((tag) => {
        const newElement = document.createElement(type)

        for (const attr in tag) {
          console.log(type, attribute, attr)
          if (tag.hasOwnProperty(attr)) {
            if (attr === 'innerHTML') {
              newElement.innerHTML = tag.innerHTML
            } else if (attr === 'cssText') {
              if (newElement.styleSheet) {
                newElement.styleSheet.cssText = tag.cssText
              } else {
                newElement.appendChild(document.createTextNode(tag.cssText))
              }
            } else if (attr === options.tagIDKeyName) {
              const _attr = `data-${attr}`
              const value = (typeof tag[attr] === 'undefined') ? '' : tag[attr]
              newElement.setAttribute(_attr, value)
            } else {
              const value = (typeof tag[attr] === 'undefined') ? '' : tag[attr]
              newElement.setAttribute(attr, value)
            }
          }
        }

        newElement.setAttribute(attribute, 'true')

        // Remove a duplicate tag from domTagstoRemove, so it isn't cleared.
        if (oldTags.some((existingTag, index) => {
          indexToDelete = index
          return newElement.isEqualNode(existingTag)
        })) {
          oldTags.splice(indexToDelete, 1)
        } else {
          newTags.push(newElement)
        }
      })
    }

    oldTags.forEach((tag) => tag.parentNode.removeChild(tag))
    newTags.forEach((tag) => headTag.appendChild(tag))

    return { oldTags, newTags }
  }
}
<|endoftext|>


<commit_before>/**
@module @ember/engine
*/

import { guidFor } from '@ember/-internals/utils';
import {
  Object as EmberObject,
  ContainerProxyMixin,
  RegistryProxyMixin,
  RSVP,
} from '@ember/-internals/runtime';
import { OWNER_MAP } from '@ember/-internals/owner';
import { assert } from '@ember/debug';
import EmberError from '@ember/error';
import { Registry, privatize as P } from '@ember/-internals/container';
import { getEngineParent, setEngineParent } from './lib/engine-parent';

/**
  The `EngineInstance` encapsulates all of the stateful aspects of a
  running `Engine`.

  @public
  @class EngineInstance
  @extends EmberObject
  @uses RegistryProxyMixin
  @uses ContainerProxyMixin
*/

const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixin, {
  /**
    The base `Engine` for which this is an instance.

    @property {Engine} engine
    @private
  */
  base: null,

  init() {
    this._super(...arguments);

    let base = this.base;

    if (!base) {
      base = this.application;
      this.base = base;
    }

    // Create a per-instance registry that will use the application's registry
    // as a fallback for resolving registrations.
    let registry = (this.__registry__ = new Registry({
      fallback: base.__registry__,
    }));

    // Create a per-instance container from the instance's registry
    this.__container__ = registry.container({ owner: this });

    this._booted = false;
  },

  /**
    Initialize the `EngineInstance` and return a promise that resolves
    with the instance itself when the boot process is complete.

    The primary task here is to run any registered instance initializers.

    See the documentation on `BootOptions` for the options it takes.

    @public
    @method boot
    @param options {Object}
    @return {Promise<EngineInstance,Error>}
  */
  boot(options) {
    if (this._bootPromise) {
      return this._bootPromise;
    }

    this._bootPromise = new RSVP.Promise(resolve => resolve(this._bootSync(options)));

    return this._bootPromise;
  },

  /**
    Unfortunately, a lot of existing code assumes booting an instance is
    synchronous – specifically, a lot of tests assume the last call to
    `app.advanceReadiness()` or `app.reset()` will result in a new instance
    being fully-booted when the current runloop completes.

    We would like new code (like the `visit` API) to stop making this
    assumption, so we created the asynchronous version above that returns a
    promise. But until we have migrated all the code, we would have to expose
    this method for use *internally* in places where we need to boot an instance
    synchronously.

    @private
  */
  _bootSync(options) {
    if (this._booted) {
      return this;
    }

    assert(
      "An engine instance's parent must be set via `setEngineParent(engine, parent)` prior to calling `engine.boot()`.",
      getEngineParent(this)
    );

    this.cloneParentDependencies();

    this.setupRegistry(options);

    this.base.runInstanceInitializers(this);

    this._booted = true;

    return this;
  },

  setupRegistry(options = this.__container__.lookup('-environment:main')) {
    this.constructor.setupRegistry(this.__registry__, options);
  },

  /**
   Unregister a factory.

   Overrides `RegistryProxy#unregister` in order to clear any cached instances
   of the unregistered factory.

   @public
   @method unregister
   @param {String} fullName
   */
  unregister(fullName) {
    this.__container__.reset(fullName);
    this._super(...arguments);
  },

  /**
    Build a new `EngineInstance` that's a child of this instance.

    Engines must be registered by name with their parent engine
    (or application).

    @private
    @method buildChildEngineInstance
    @param name {String} the registered name of the engine.
    @param options {Object} options provided to the engine instance.
    @return {EngineInstance,Error}
  */
  buildChildEngineInstance(name, options = {}) {
    let Engine = this.lookup(`engine:${name}`);

    if (!Engine) {
      throw new EmberError(
        `You attempted to mount the engine '${name}', but it is not registered with its parent.`
      );
    }

    let engineInstance = Engine.buildInstance(options);

    setEngineParent(engineInstance, this);

    return engineInstance;
  },

  /**
    Clone dependencies shared between an engine instance and its parent.

    @private
    @method cloneParentDependencies
  */
  cloneParentDependencies() {
    let parent = getEngineParent(this);

    let registrations = ['route:basic', 'service:-routing'];

    registrations.forEach(key => this.register(key, parent.resolveRegistration(key)));

    let env = parent.lookup('-environment:main');
    this.register('-environment:main', env, { instantiate: false });

    let singletons = [
      'router:main',
      P`-bucket-cache:main`,
      '-view-registry:main',
      `renderer:-${env.isInteractive ? 'dom' : 'inert'}`,
      'service:-document',
    ];

    if (env.isInteractive) {
      singletons.push('event_dispatcher:main');
    }

    singletons.forEach(key => this.register(key, parent.lookup(key), { instantiate: false }));

    this.inject('view', '_environment', '-environment:main');
    this.inject('route', '_environment', '-environment:main');
  },
});

EngineInstance.reopenClass({
  /**
   @private
   @method setupRegistry
   @param {Registry} registry
   @param {BootOptions} options
   */
  setupRegistry(registry, options) {
    // when no options/environment is present, do nothing
    if (!options) {
      return;
    }

    registry.injection('view', '_environment', '-environment:main');
    registry.injection('route', '_environment', '-environment:main');

    if (options.isInteractive) {
      registry.injection('view', 'renderer', 'renderer:-dom');
      registry.injection('component', 'renderer', 'renderer:-dom');
    } else {
      registry.injection('view', 'renderer', 'renderer:-inert');
      registry.injection('component', 'renderer', 'renderer:-inert');
    }
  },
});

export default EngineInstance;
<commit_msg>fix lint<commit_after>/**
@module @ember/engine
*/

import {
  Object as EmberObject,
  ContainerProxyMixin,
  RegistryProxyMixin,
  RSVP,
} from '@ember/-internals/runtime';
import { assert } from '@ember/debug';
import EmberError from '@ember/error';
import { Registry, privatize as P } from '@ember/-internals/container';
import { getEngineParent, setEngineParent } from './lib/engine-parent';

/**
  The `EngineInstance` encapsulates all of the stateful aspects of a
  running `Engine`.

  @public
  @class EngineInstance
  @extends EmberObject
  @uses RegistryProxyMixin
  @uses ContainerProxyMixin
*/

const EngineInstance = EmberObject.extend(RegistryProxyMixin, ContainerProxyMixin, {
  /**
    The base `Engine` for which this is an instance.

    @property {Engine} engine
    @private
  */
  base: null,

  init() {
    this._super(...arguments);

    let base = this.base;

    if (!base) {
      base = this.application;
      this.base = base;
    }

    // Create a per-instance registry that will use the application's registry
    // as a fallback for resolving registrations.
    let registry = (this.__registry__ = new Registry({
      fallback: base.__registry__,
    }));

    // Create a per-instance container from the instance's registry
    this.__container__ = registry.container({ owner: this });

    this._booted = false;
  },

  /**
    Initialize the `EngineInstance` and return a promise that resolves
    with the instance itself when the boot process is complete.

    The primary task here is to run any registered instance initializers.

    See the documentation on `BootOptions` for the options it takes.

    @public
    @method boot
    @param options {Object}
    @return {Promise<EngineInstance,Error>}
  */
  boot(options) {
    if (this._bootPromise) {
      return this._bootPromise;
    }

    this._bootPromise = new RSVP.Promise(resolve => resolve(this._bootSync(options)));

    return this._bootPromise;
  },

  /**
    Unfortunately, a lot of existing code assumes booting an instance is
    synchronous – specifically, a lot of tests assume the last call to
    `app.advanceReadiness()` or `app.reset()` will result in a new instance
    being fully-booted when the current runloop completes.

    We would like new code (like the `visit` API) to stop making this
    assumption, so we created the asynchronous version above that returns a
    promise. But until we have migrated all the code, we would have to expose
    this method for use *internally* in places where we need to boot an instance
    synchronously.

    @private
  */
  _bootSync(options) {
    if (this._booted) {
      return this;
    }

    assert(
      "An engine instance's parent must be set via `setEngineParent(engine, parent)` prior to calling `engine.boot()`.",
      getEngineParent(this)
    );

    this.cloneParentDependencies();

    this.setupRegistry(options);

    this.base.runInstanceInitializers(this);

    this._booted = true;

    return this;
  },

  setupRegistry(options = this.__container__.lookup('-environment:main')) {
    this.constructor.setupRegistry(this.__registry__, options);
  },

  /**
   Unregister a factory.

   Overrides `RegistryProxy#unregister` in order to clear any cached instances
   of the unregistered factory.

   @public
   @method unregister
   @param {String} fullName
   */
  unregister(fullName) {
    this.__container__.reset(fullName);
    this._super(...arguments);
  },

  /**
    Build a new `EngineInstance` that's a child of this instance.

    Engines must be registered by name with their parent engine
    (or application).

    @private
    @method buildChildEngineInstance
    @param name {String} the registered name of the engine.
    @param options {Object} options provided to the engine instance.
    @return {EngineInstance,Error}
  */
  buildChildEngineInstance(name, options = {}) {
    let Engine = this.lookup(`engine:${name}`);

    if (!Engine) {
      throw new EmberError(
        `You attempted to mount the engine '${name}', but it is not registered with its parent.`
      );
    }

    let engineInstance = Engine.buildInstance(options);

    setEngineParent(engineInstance, this);

    return engineInstance;
  },

  /**
    Clone dependencies shared between an engine instance and its parent.

    @private
    @method cloneParentDependencies
  */
  cloneParentDependencies() {
    let parent = getEngineParent(this);

    let registrations = ['route:basic', 'service:-routing'];

    registrations.forEach(key => this.register(key, parent.resolveRegistration(key)));

    let env = parent.lookup('-environment:main');
    this.register('-environment:main', env, { instantiate: false });

    let singletons = [
      'router:main',
      P`-bucket-cache:main`,
      '-view-registry:main',
      `renderer:-${env.isInteractive ? 'dom' : 'inert'}`,
      'service:-document',
    ];

    if (env.isInteractive) {
      singletons.push('event_dispatcher:main');
    }

    singletons.forEach(key => this.register(key, parent.lookup(key), { instantiate: false }));

    this.inject('view', '_environment', '-environment:main');
    this.inject('route', '_environment', '-environment:main');
  },
});

EngineInstance.reopenClass({
  /**
   @private
   @method setupRegistry
   @param {Registry} registry
   @param {BootOptions} options
   */
  setupRegistry(registry, options) {
    // when no options/environment is present, do nothing
    if (!options) {
      return;
    }

    registry.injection('view', '_environment', '-environment:main');
    registry.injection('route', '_environment', '-environment:main');

    if (options.isInteractive) {
      registry.injection('view', 'renderer', 'renderer:-dom');
      registry.injection('component', 'renderer', 'renderer:-dom');
    } else {
      registry.injection('view', 'renderer', 'renderer:-inert');
      registry.injection('component', 'renderer', 'renderer:-inert');
    }
  },
});

export default EngineInstance;
<|endoftext|>


<commit_before>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
define([
        'addons/documents/resources',
        'testUtils'
], function (Models, testUtils) {
  var assert = testUtils.assert;

  describe('IndexCollection', function () {
    var collection;
    beforeEach(function () {
      collection = new Models.IndexCollection([{
        id:'myId1',
        doc: 'num1'
      },
      {
        id:'myId2',
        doc: 'num2'
      }], {
        database: {id: 'databaseId', safeID: function () { return this.id; }},
        design: '_design/myDoc'
      });
    });

    it('does not remove an id attribute', function () {

      assert.ok(/file:/.test(collection.urlRef('')));
    });

  });

  describe('Document', function () {
    var doc;
    beforeEach(function () {
      doc = new Models.Doc({}, {});
    });

    it('does not remove an id attribute', function () {
      var res = doc.parse({
        _id: "be31e531fe131bdf416b479ac1000484",
        _rev: "4-3a1b9f4b988b413e9245cd250769da72",
        id: "foo"
      });
      assert.equal(res.id, 'foo');
    });

    it('removes the id, if we create a document and get back an "id" instead of "_id"', function () {
      // if we take the document {"_id": "mycustomid", "_rev": "18-9cdeb1b121137233e3466b06a1780c29", id: "foo"}
      // and do a PUT request for an update, CouchDB will return:
      // {"ok":true,"id":"mycustomid","rev":"18-9cdeb1b121137233e3466b06a1780c29"}
      // and our Model will think it has the id "mycustomid" instead of "foo"
      var res = doc.parse({
        id: "be31e531fe131bdf416b479ac1000484",
        _rev: "4-3a1b9f4b988b413e9245cd250769da72",
        ok: true
      });
      assert.notOk(res.id);
    });
  });

  describe('AllDocs', function () {
    var collection;
    beforeEach(function () {
      collection = new Models.AllDocs([{
        _id:'myId1',
        doc: 'num1'
      },
      {
        _id:'myId2',
        doc: 'num2'
      }], {
        database: {id: 'databaseId', safeID: function () { return this.id; }},
        params: {limit: 20}
      });

    });
  });

  describe('QueryParams', function() {
    describe('parse', function() {
      it('should not parse arbitrary parameters', function() {
        var params = {"foo":"[1]]"};
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(result, params);
      });

      it('parses startkey, endkey', function() {
        var params = {
          "startkey":"[\"a\",\"b\"]",
          "endkey":"[\"c\",\"d\"]"
        };
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(result, {
          "startkey":["a","b"],
          "endkey":["c","d"]
        });
      });

      it('parses key', function() {
        var params = {
          "key":"[1,2]"
        };
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(result, {"key":[1,2]});
      });

      it('does not modify input', function() {
        var params = {
          "key":"[\"a\",\"b\"]"
        };
        var clone = _.clone(params);
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(params, clone);
      });
    });

    describe('stringify', function() {
      it('should not stringify arbitrary parameters', function() {
        var params = {"foo":[1,2,3]};
        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(result, params);
      });

      it('stringifies startkey, endkey', function() {
        var params = {
          "startkey":["a","b"],
          "endkey":["c","d"]
        };

        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(result, {
          "startkey":"[\"a\",\"b\"]",
          "endkey":"[\"c\",\"d\"]"
        });
      });

      it('stringifies key', function() {
        var params = {"key":["a","b"]};
        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(result, { "key":"[\"a\",\"b\"]" });
      });

      it('does not modify input', function() {
        var params = {"key":["a","b"]};
        var clone = _.clone(params);
        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(params, clone);
      });

      it('is symmetrical with parse', function() {
        var params = {
          "startkey":["a","b"],
          "endkey":["c","d"],
          "foo": "[1,2]",
          "bar": "abc"
        };

        var clone = _.clone(params);
        var json = Models.QueryParams.stringify(params);
        var result = Models.QueryParams.parse(json);

        assert.deepEqual(result, clone);
      });
    });
  });

  describe('Bulk Delete', function () {
    var databaseId = 'ente',
        collection,
        values;

    values = [{
      _id: '1',
      _rev: '1234561',
      _deleted: true
    },
    {
      _id: '2',
      _rev: '1234562',
      _deleted: true
    },
    {
      _id: '3',
      _rev: '1234563',
      _deleted: true
    }];

    beforeEach(function () {
      collection = new Models.BulkDeleteDocCollection(values, {
        databaseId: databaseId
      });
    });

    it("contains the models", function () {
      collection = new Models.BulkDeleteDocCollection(values, {
        databaseId: databaseId
      });

      assert.equal(collection.length, 3);
    });

    it("clears the memory if no errors happened", function () {
      collection.handleResponse([
        {"ok":true,"id":"1","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"2","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);

      assert.equal(collection.length, 1);
    });

    it("triggers a removed event with all ids", function () {
      collection.listenToOnce(collection, 'removed', function (ids) {
        assert.deepEqual(ids, ['Deferred', 'DeskSet']);
      });

      collection.handleResponse([
        {"ok":true,"id":"Deferred","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"DeskSet","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);
    });

    it("triggers a error event with all errored ids", function () {
      collection.listenToOnce(collection, 'error', function (ids) {
        assert.deepEqual(ids, ['Deferred']);
      });
      collection.handleResponse([
        {"error":"confclict","id":"Deferred","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"DeskSet","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);
    });

    it("removes successfull deleted from the collection but keeps one with errors", function () {
      collection.handleResponse([
        {"error":"confclict","id":"1","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"2","rev":"6-da537822b9672a4b2f42adb1be04a5b1"},
        {"error":"conflict","id":"3","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);
      assert.ok(collection.get('1'));
      assert.ok(collection.get('3'));
      assert.notOk(collection.get('2'));
    });
  });
});
<commit_msg>tests: fix description for test<commit_after>// Licensed under the Apache License, Version 2.0 (the "License"); you may not
// use this file except in compliance with the License. You may obtain a copy of
// the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations under
// the License.
define([
        'addons/documents/resources',
        'testUtils'
], function (Models, testUtils) {
  var assert = testUtils.assert;

  describe('IndexCollection', function () {
    var collection;
    beforeEach(function () {
      collection = new Models.IndexCollection([{
        id:'myId1',
        doc: 'num1'
      },
      {
        id:'myId2',
        doc: 'num2'
      }], {
        database: {id: 'databaseId', safeID: function () { return this.id; }},
        design: '_design/myDoc'
      });
    });

    it('creates the right api-url with an absolute url', function () {

      assert.ok(/file:/.test(collection.urlRef()));
    });

  });

  describe('Document', function () {
    var doc;
    beforeEach(function () {
      doc = new Models.Doc({}, {});
    });

    it('does not remove an id attribute', function () {
      var res = doc.parse({
        _id: "be31e531fe131bdf416b479ac1000484",
        _rev: "4-3a1b9f4b988b413e9245cd250769da72",
        id: "foo"
      });
      assert.equal(res.id, 'foo');
    });

    it('removes the id, if we create a document and get back an "id" instead of "_id"', function () {
      // if we take the document {"_id": "mycustomid", "_rev": "18-9cdeb1b121137233e3466b06a1780c29", id: "foo"}
      // and do a PUT request for an update, CouchDB will return:
      // {"ok":true,"id":"mycustomid","rev":"18-9cdeb1b121137233e3466b06a1780c29"}
      // and our Model will think it has the id "mycustomid" instead of "foo"
      var res = doc.parse({
        id: "be31e531fe131bdf416b479ac1000484",
        _rev: "4-3a1b9f4b988b413e9245cd250769da72",
        ok: true
      });
      assert.notOk(res.id);
    });
  });

  describe('AllDocs', function () {
    var collection;
    beforeEach(function () {
      collection = new Models.AllDocs([{
        _id:'myId1',
        doc: 'num1'
      },
      {
        _id:'myId2',
        doc: 'num2'
      }], {
        database: {id: 'databaseId', safeID: function () { return this.id; }},
        params: {limit: 20}
      });

    });
  });

  describe('QueryParams', function() {
    describe('parse', function() {
      it('should not parse arbitrary parameters', function() {
        var params = {"foo":"[1]]"};
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(result, params);
      });

      it('parses startkey, endkey', function() {
        var params = {
          "startkey":"[\"a\",\"b\"]",
          "endkey":"[\"c\",\"d\"]"
        };
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(result, {
          "startkey":["a","b"],
          "endkey":["c","d"]
        });
      });

      it('parses key', function() {
        var params = {
          "key":"[1,2]"
        };
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(result, {"key":[1,2]});
      });

      it('does not modify input', function() {
        var params = {
          "key":"[\"a\",\"b\"]"
        };
        var clone = _.clone(params);
        var result = Models.QueryParams.parse(params);

        assert.deepEqual(params, clone);
      });
    });

    describe('stringify', function() {
      it('should not stringify arbitrary parameters', function() {
        var params = {"foo":[1,2,3]};
        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(result, params);
      });

      it('stringifies startkey, endkey', function() {
        var params = {
          "startkey":["a","b"],
          "endkey":["c","d"]
        };

        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(result, {
          "startkey":"[\"a\",\"b\"]",
          "endkey":"[\"c\",\"d\"]"
        });
      });

      it('stringifies key', function() {
        var params = {"key":["a","b"]};
        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(result, { "key":"[\"a\",\"b\"]" });
      });

      it('does not modify input', function() {
        var params = {"key":["a","b"]};
        var clone = _.clone(params);
        var result = Models.QueryParams.stringify(params);

        assert.deepEqual(params, clone);
      });

      it('is symmetrical with parse', function() {
        var params = {
          "startkey":["a","b"],
          "endkey":["c","d"],
          "foo": "[1,2]",
          "bar": "abc"
        };

        var clone = _.clone(params);
        var json = Models.QueryParams.stringify(params);
        var result = Models.QueryParams.parse(json);

        assert.deepEqual(result, clone);
      });
    });
  });

  describe('Bulk Delete', function () {
    var databaseId = 'ente',
        collection,
        values;

    values = [{
      _id: '1',
      _rev: '1234561',
      _deleted: true
    },
    {
      _id: '2',
      _rev: '1234562',
      _deleted: true
    },
    {
      _id: '3',
      _rev: '1234563',
      _deleted: true
    }];

    beforeEach(function () {
      collection = new Models.BulkDeleteDocCollection(values, {
        databaseId: databaseId
      });
    });

    it("contains the models", function () {
      collection = new Models.BulkDeleteDocCollection(values, {
        databaseId: databaseId
      });

      assert.equal(collection.length, 3);
    });

    it("clears the memory if no errors happened", function () {
      collection.handleResponse([
        {"ok":true,"id":"1","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"2","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);

      assert.equal(collection.length, 1);
    });

    it("triggers a removed event with all ids", function () {
      collection.listenToOnce(collection, 'removed', function (ids) {
        assert.deepEqual(ids, ['Deferred', 'DeskSet']);
      });

      collection.handleResponse([
        {"ok":true,"id":"Deferred","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"DeskSet","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);
    });

    it("triggers a error event with all errored ids", function () {
      collection.listenToOnce(collection, 'error', function (ids) {
        assert.deepEqual(ids, ['Deferred']);
      });
      collection.handleResponse([
        {"error":"confclict","id":"Deferred","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"DeskSet","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);
    });

    it("removes successfull deleted from the collection but keeps one with errors", function () {
      collection.handleResponse([
        {"error":"confclict","id":"1","rev":"10-72cd2edbcc0d197ce96188a229a7af01"},
        {"ok":true,"id":"2","rev":"6-da537822b9672a4b2f42adb1be04a5b1"},
        {"error":"conflict","id":"3","rev":"6-da537822b9672a4b2f42adb1be04a5b1"}
      ]);
      assert.ok(collection.get('1'));
      assert.ok(collection.get('3'));
      assert.notOk(collection.get('2'));
    });
  });
});
<|endoftext|>


<commit_before>'use strict';

module.exports = function(app) {
  app.controller('GamesController', ['$rootScope', '$http', '$location', '$route', 'AuthService', 'UserService', 'GameService', function($rs, $http, $location, $route, AuthService, UserService, GameService) {

    AuthService.checkSessionExists();

    this.user = $rs.user;
    this.gameData = $rs.gameData;
    this.games = [];
    this.publicIds = [];
    this.friendsList = [];
    this.game = {
      players: [],
    };
    this.game.players[0] = $rs.user;

    $rs.user.gameIds.forEach((game) => {
      this.publicIds.push(game.publicId);
    });

    this.createGame = function(gameData) {
      $http.post('/games/create', gameData)
        .then((game) => {
          let playersArray = game.data.players;
          playersArray.forEach((player) => {
            this.updatePlayer(player)
              .then((playerData) => {
                if (playerData.data.email === $rs.user.email) {
                  $rs.user = playerData.data;
                  window.sessionStorage.setItem('currentUser', JSON.stringify($rs.user));
                }
                $route.reload();
              })
              .catch((err) => {
                alert('error creating game');
              });
          });
        })
        .catch((err) => {
          alert('error creating game');
        });
    };

    this.getById = GameService.getById;
    GameService.getAllByPublicId(this.publicIds)
      .then((games) => {
        this.games = games.data;
      })
      .catch(() => {
        alert('error getting all games');
      });

    this.getFriendsList = function() {
      $http.get('/friends/list')
        .then((friendsList) => {
          this.friendsList = friendsList.data;
        })
        .catch((err) => {
          alert('error getting friends list');
        });
    };

    this.addPlayer = function(user) {
      if (user === undefined || user === null) return;
      user = JSON.parse(user);
      this.game.players.push(user);
      this.friendsList = this.friendsList.filter((friend) => {
        return friend._id !== user._id;
      });
    };

    this.removePlayer = function(user) {
      let playersArray = this.game.players;
      let userIndex = playersArray.indexOf(user);
      this.friendsList.push(playersArray[userIndex]);
      playersArray.splice(userIndex, 1);
    };

    this.updatePlayer = function(player) {
      return new Promise((resolve, reject) => {
        let playerData = {
          emailOrUsername: player.email,
        };
        $http.post('/users', playerData)
          .then((user) => {
            UserService.calcHandicap(user.data)
              .then((handicap) => {
                let handicapData = {
                  handicap: handicap,
                };
                UserService.updateUser(playerData, handicapData)
                  .then((user) => {
                    resolve(user);
                  })
                  .catch(reject);
              })
              .catch(reject);
          })
          .catch(reject);
      });
    };

  }]);
};
<commit_msg>when controller is loaded get all game data and save to this.games<commit_after>'use strict';

module.exports = function(app) {
  app.controller('GamesController', ['$rootScope', '$scope', '$http', '$location', '$route', 'AuthService', 'UserService', 'GameService', function($rs, $scope, $http, $location, $route, AuthService, UserService, GameService) {

    AuthService.checkSessionExists();

    this.user = $rs.user;
    this.gameData = $rs.gameData;
    this.games = [];
    this.publicIds = [];
    this.friendsList = [];
    this.game = {
      players: [],
    };
    this.game.players[0] = $rs.user;

    $rs.user.gameIds.forEach((game) => {
      this.publicIds.push(game.publicId);
    });

    this.getAllByPublicId = GameService.getAllByPublicId;
    this.getAllByPublicId(this.publicIds)
      .then((games) => {
        this.games = games;
      })
      .catch(() => {
        alert('error getting games');
      });

    this.createGame = function(gameData) {
      $http.post('/games/create', gameData)
        .then((game) => {
          let playersArray = game.data.players;
          playersArray.forEach((player) => {
            this.updatePlayer(player)
              .then((playerData) => {
                if (playerData.data.email === $rs.user.email) {
                  $rs.user = playerData.data;
                  window.sessionStorage.setItem('currentUser', JSON.stringify($rs.user));
                }
                $route.reload();
              })
              .catch((err) => {
                alert('error creating game');
              });
          });
        })
        .catch((err) => {
          alert('error creating game');
        });
    };

    this.getById = GameService.getById;

    this.getFriendsList = function() {
      $http.get('/friends/list')
        .then((friendsList) => {
          this.friendsList = friendsList.data;
        })
        .catch((err) => {
          alert('error getting friends list');
        });
    };

    this.addPlayer = function(user) {
      if (user === undefined || user === null) return;
      user = JSON.parse(user);
      this.game.players.push(user);
      this.friendsList = this.friendsList.filter((friend) => {
        return friend._id !== user._id;
      });
    };

    this.removePlayer = function(user) {
      let playersArray = this.game.players;
      let userIndex = playersArray.indexOf(user);
      this.friendsList.push(playersArray[userIndex]);
      playersArray.splice(userIndex, 1);
    };

    this.updatePlayer = function(player) {
      return new Promise((resolve, reject) => {
        let playerData = {
          emailOrUsername: player.email,
        };
        $http.post('/users', playerData)
          .then((user) => {
            UserService.calcHandicap(user.data)
              .then((handicap) => {
                let handicapData = {
                  handicap: handicap,
                };
                UserService.updateUser(playerData, handicapData)
                  .then((user) => {
                    resolve(user);
                  })
                  .catch(reject);
              })
              .catch(reject);
          })
          .catch(reject);
      });
    };

  }]);
};
<|endoftext|>


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

  var Embed = Quill.import('blots/block/embed');

  // IMPORTANT
  // Quill is built with ES6 classes and is transpiled with Babel. In order to extend a class
  // a Quill's class, we have to write the code using ES6 and transpile it down to ES5

  // To modify this code, please open the file with the same name and ending with the extension
  // ".js" and read how to proceed.

  /* eslint-disable */
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var WidgetBlot = function (_Embed) {
  _inherits(WidgetBlot, _Embed);

  /**
   * Creates an instance of WidgetBlot.
   *
   * @param {HTMLElement} domNode
   * @param {any} value
   *
   * @memberOf WidgetBlot
   */
  function WidgetBlot(domNode, value) {
    _classCallCheck(this, WidgetBlot);

    var _this = _possibleConstructorReturn(this, (WidgetBlot.__proto__ || Object.getPrototypeOf(WidgetBlot)).call(this, domNode, value));

    _this.editor = window.editor;
    _this.caption = domNode.querySelector('.js-caption');
    _this.widgetContainer = domNode.querySelector('.js-widget-container');

    if (!_this.editor.options.readOnly) {
      // We make the caption editable
      _this.caption.setAttribute('contenteditable', true);
    }

    _this.widgetContainer.innerHTML = '

';

    _this._fetchWidget().done(function () {
      _this._initWidget();

      // If wanted, we set the widget's description as default text
      // of the caption
      if (_this.caption.dataset.defaultCaption) {
        _this.caption.textContent = _this.model.toJSON().description;
      }
    }).fail(function () {
      if (!this.editor.options.readOnly) {
        App.notifications.broadcast(App.Helper.Notifications.page.widgetError);
        this._onClickRemove();
      } else {
        App.notifications.broadcast(App.Helper.Notifications.widget.loadingWarning);
      }

      this.widgetContainer.innerHTML = '
This widget couldn\'t be loaded properly
';
    }.bind(_this));
    return _this;
  }

  /**
   * Fetch the data associated to the widget
   * @returns {any} jQuery deferred object
   */

  _createClass(WidgetBlot, [{
    key: '_fetchWidget',
    value: function _fetchWidget() {
      var id = WidgetBlot.value(this.domNode).id;

      var url = '/widget_data.json?widget_id=' + id;
      if (this.editor.options.readOnly) {
        url = window.location.origin + url;
      } else {
        url = window.location.pathname + url;
      }

      this.model = new (Backbone.Model.extend({
        url: url
      }))();

      return this.model.fetch();
    }

    /**
     * Init the widget
     */

  }, {
    key: '_initWidget',
    value: function _initWidget() {
      var _this2 = this;

      var chart = this.model.toJSON();

      // We retrieve the chart's configuration
      var config;
      try {
        config = JSON.parse(chart.visualization);
      } catch (e) {
        config = {
          chart: null,
          x: null,
          y: null,
          xLabel: null,
          yLabel: null
        };
      }

      var meta = chart.metadata;

      // We render the widget
      this.widget = new App.View.ChartWidgetView({
        el: this.domNode.querySelector('.js-widget-container'),
        data: chart.data,
        chart: config.chart,
        columnX: config.x,
        columnY: config.y,
        xLabel: config.xLabel,
        yLabel: config.yLabel,
        enableChartSelector: false,
        metadata: meta
      });

      if (!this.editor.options.readOnly) {
        // We render the toolbar
        this._renderToolbar();
      }

      // Little trick to wait for the block to be appended to the DOM
      // before rendering the widget (which requires it)
      setTimeout(function () {
        return _this2.widget.render();
      }, 0);
    }

    /**
     * Create the DOM node
     * @param {any} obj - attributes describing the widget
     * @returns {HTMLElement} node
     */

  }, {
    key: 'format',

    /**
     * Set an attribute of the node
     * @param {string} name - attribute name
     * @param {any} value
     * @memberOf WidgetBlot
     */
    value: function format(name, value) {
      if (name === 'id') {
        this.domNode.dataset.id = value;
      } else if (name === 'caption') {
        if (value) {
          this.caption.textContent = value;
        } else {
          this.caption.parentElement.removeChild(this.caption);
        }
      } else if (name === 'size') {
        if (value === 'cover') {
          this.domNode.classList.add('-cover');
          this.domNode.classList.remove('-large');
        } else if (value === 'large') {
          this.domNode.classList.add('-large');
          this.domNode.classList.remove('-cover');
        } else {
          this.domNode.classList.remove('-cover');
          this.domNode.classList.remove('-large');
        }
      } else {
        _get(WidgetBlot.prototype.__proto__ || Object.getPrototypeOf(WidgetBlot.prototype), 'format', this).call(this, name, value);
      }
    }

    /**
     * Event handler called when the user clicks the remove button
     * @memberOf WidgetBlot
     */

  }, {
    key: '_onClickRemove',
    value: function _onClickRemove() {
      var offset = this.offset();
      this.editor.deleteText(offset, this.length());
      this.editor.setSelection(offset);
    }

    /**
     * Event handler called when the user clicks the toggle size button
     */

  }, {
    key: '_onClickToggleSize',
    value: function _onClickToggleSize() {
      var formats = WidgetBlot.formats(this.domNode);

      switch (formats.size) {
        case 'normal':
          this.format('size', 'large');
          break;

        case 'large':
          this.format('size', 'cover');
          break;

        case 'cover':
          this.format('size', 'normal');
          break;
      }

      this.widget.render();
    }

    /**
     * Render the toolbar
     * @memberOf WidgetBlot
     */

  }, {
    key: '_renderToolbar',
    value: function _renderToolbar() {
      var _this3 = this;

      // We create the element with the default state
      this.toolbar = document.createElement('div');
      this.domNode.appendChild(this.toolbar);
      this.toolbar.classList.add('toolbar');

      // We append its content
      this.toolbar.innerHTML = HandlebarsTemplates['management/wysiwyg-block-toolbar']({
        hideChangeBtn: true,
        showSizeBtn: true
      });

      // We attach the event listeners
      this.toolbar.querySelector('.js-remove').addEventListener('click', function () {
        return _this3._onClickRemove();
      });
      this.toolbar.querySelector('.js-toggle-size').addEventListener('click', function () {
        return _this3._onClickToggleSize();
      });
    }
  }], [{
    key: 'create',
    value: function create(obj) {
      var node = _get(WidgetBlot.__proto__ || Object.getPrototypeOf(WidgetBlot), 'create', this).call(this);

      // On the next line we need to check the type of obj because the widget's value (obj)
      // was saved differently in the past and we need to ensure the compatibility with the
      // previous widgets
      var id = (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' ? obj.id : obj;
      var defaultCaption = obj.defaultCaption || false;

      var widgetContainer = document.createElement('div');
      widgetContainer.classList.add('widget-container');
      widgetContainer.classList.add('js-widget-container');

      node.appendChild(widgetContainer);

      // We save the id of the widget into the DOM
      node.dataset.id = id;

      // We don't want the user to be able to edit the widget
      node.setAttribute('contenteditable', false);

      // We add the caption container
      var captionContainer = document.createElement('p');
      captionContainer.classList.add('caption');
      captionContainer.classList.add('js-caption');
      if (defaultCaption) captionContainer.dataset.defaultCaption = 'true';

      node.appendChild(captionContainer);

      // If we don't disable the "content editable" feature of the editor
      // when the user writes in the caption container, the browsers
      // jump to the top as it considers it as the element we're editing
      captionContainer.addEventListener('focusin', function () {
        window.editor.root.setAttribute('contenteditable', false);
      });

      captionContainer.addEventListener('focusout', function () {
        window.editor.root.setAttribute('contenteditable', true);
      });

      captionContainer.addEventListener('blur', function () {
        // If the user deleted the whole content, we want the default
        // text to appear, nevertheless a br tag is inserted so we delete it
        if (!this.textContent.length && this.innerHTML.length) {
          this.innerHTML = '';
        }
      });

      return node;
    }

    /**
     * Return the attributes describing the widget
     * @static
     * @param {HTMLElement} node
     * @returns {object}
     * @memberOf WidgetBlot
     */

  }, {
    key: 'value',
    value: function value(node) {
      return {
        id: +node.dataset.id
      };
    }

    /**
     * Return the attributes attached to the node
     * @static
     * @param {HTMLElement} node
     * @returns {any}
     * @memberOf WidgetBlot
     */

  }, {
    key: 'formats',
    value: function formats(node) {
      var res = {
        id: +node.dataset.id
      };

      var caption = node.querySelector('.js-caption');
      if (caption && caption.textContent) {
        res.caption = caption.textContent;
      }

      if (node.classList.contains('-cover')) {
        res.size = 'cover';
      } else if (node.classList.contains('-large')) {
        res.size = 'large';
      } else {
        res.size = 'normal';
      }

      return res;
    }
  }]);

  return WidgetBlot;
}(Embed);

  WidgetBlot.blotName = 'widget';
  WidgetBlot.tagName = 'div';
  WidgetBlot.className = '-widget';
  /* eslint-enable */

  App.Blot.WidgetBlot = WidgetBlot;
})(this.App));
<commit_msg>we are not dealing with a integer anymore, so remove id increment logic<commit_after>((function () {
  'use strict';

  var Embed = Quill.import('blots/block/embed');

  // IMPORTANT
  // Quill is built with ES6 classes and is transpiled with Babel. In order to extend a class
  // a Quill's class, we have to write the code using ES6 and transpile it down to ES5

  // To modify this code, please open the file with the same name and ending with the extension
  // ".js" and read how to proceed.

  /* eslint-disable */
  var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; };

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

var _get = function get(object, property, receiver) { if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var WidgetBlot = function (_Embed) {
  _inherits(WidgetBlot, _Embed);

  /**
   * Creates an instance of WidgetBlot.
   *
   * @param {HTMLElement} domNode
   * @param {any} value
   *
   * @memberOf WidgetBlot
   */
  function WidgetBlot(domNode, value) {
    _classCallCheck(this, WidgetBlot);

    var _this = _possibleConstructorReturn(this, (WidgetBlot.__proto__ || Object.getPrototypeOf(WidgetBlot)).call(this, domNode, value));

    _this.editor = window.editor;
    _this.caption = domNode.querySelector('.js-caption');
    _this.widgetContainer = domNode.querySelector('.js-widget-container');

    if (!_this.editor.options.readOnly) {
      // We make the caption editable
      _this.caption.setAttribute('contenteditable', true);
    }

    _this.widgetContainer.innerHTML = '

';

    _this._fetchWidget().done(function () {
      _this._initWidget();

      // If wanted, we set the widget's description as default text
      // of the caption
      if (_this.caption.dataset.defaultCaption) {
        _this.caption.textContent = _this.model.toJSON().description;
      }
    }).fail(function () {
      if (!this.editor.options.readOnly) {
        App.notifications.broadcast(App.Helper.Notifications.page.widgetError);
        this._onClickRemove();
      } else {
        App.notifications.broadcast(App.Helper.Notifications.widget.loadingWarning);
      }

      this.widgetContainer.innerHTML = '
This widget couldn\'t be loaded properly
';
    }.bind(_this));
    return _this;
  }

  /**
   * Fetch the data associated to the widget
   * @returns {any} jQuery deferred object
   */

  _createClass(WidgetBlot, [{
    key: '_fetchWidget',
    value: function _fetchWidget() {
      var id = WidgetBlot.value(this.domNode).id;

      var url = '/widget_data.json?widget_id=' + id;
      if (this.editor.options.readOnly) {
        url = window.location.origin + url;
      } else {
        url = window.location.pathname + url;
      }

      this.model = new (Backbone.Model.extend({
        url: url
      }))();

      return this.model.fetch();
    }

    /**
     * Init the widget
     */

  }, {
    key: '_initWidget',
    value: function _initWidget() {
      var _this2 = this;

      var chart = this.model.toJSON();

      // We retrieve the chart's configuration
      var config;
      try {
        config = JSON.parse(chart.visualization);
      } catch (e) {
        config = {
          chart: null,
          x: null,
          y: null,
          xLabel: null,
          yLabel: null
        };
      }

      var meta = chart.metadata;

      // We render the widget
      this.widget = new App.View.ChartWidgetView({
        el: this.domNode.querySelector('.js-widget-container'),
        data: chart.data,
        chart: config.chart,
        columnX: config.x,
        columnY: config.y,
        xLabel: config.xLabel,
        yLabel: config.yLabel,
        enableChartSelector: false,
        metadata: meta
      });

      if (!this.editor.options.readOnly) {
        // We render the toolbar
        this._renderToolbar();
      }

      // Little trick to wait for the block to be appended to the DOM
      // before rendering the widget (which requires it)
      setTimeout(function () {
        return _this2.widget.render();
      }, 0);
    }

    /**
     * Create the DOM node
     * @param {any} obj - attributes describing the widget
     * @returns {HTMLElement} node
     */

  }, {
    key: 'format',

    /**
     * Set an attribute of the node
     * @param {string} name - attribute name
     * @param {any} value
     * @memberOf WidgetBlot
     */
    value: function format(name, value) {
      if (name === 'id') {
        this.domNode.dataset.id = value;
      } else if (name === 'caption') {
        if (value) {
          this.caption.textContent = value;
        } else {
          this.caption.parentElement.removeChild(this.caption);
        }
      } else if (name === 'size') {
        if (value === 'cover') {
          this.domNode.classList.add('-cover');
          this.domNode.classList.remove('-large');
        } else if (value === 'large') {
          this.domNode.classList.add('-large');
          this.domNode.classList.remove('-cover');
        } else {
          this.domNode.classList.remove('-cover');
          this.domNode.classList.remove('-large');
        }
      } else {
        _get(WidgetBlot.prototype.__proto__ || Object.getPrototypeOf(WidgetBlot.prototype), 'format', this).call(this, name, value);
      }
    }

    /**
     * Event handler called when the user clicks the remove button
     * @memberOf WidgetBlot
     */

  }, {
    key: '_onClickRemove',
    value: function _onClickRemove() {
      var offset = this.offset();
      this.editor.deleteText(offset, this.length());
      this.editor.setSelection(offset);
    }

    /**
     * Event handler called when the user clicks the toggle size button
     */

  }, {
    key: '_onClickToggleSize',
    value: function _onClickToggleSize() {
      var formats = WidgetBlot.formats(this.domNode);

      switch (formats.size) {
        case 'normal':
          this.format('size', 'large');
          break;

        case 'large':
          this.format('size', 'cover');
          break;

        case 'cover':
          this.format('size', 'normal');
          break;
      }

      this.widget.render();
    }

    /**
     * Render the toolbar
     * @memberOf WidgetBlot
     */

  }, {
    key: '_renderToolbar',
    value: function _renderToolbar() {
      var _this3 = this;

      // We create the element with the default state
      this.toolbar = document.createElement('div');
      this.domNode.appendChild(this.toolbar);
      this.toolbar.classList.add('toolbar');

      // We append its content
      this.toolbar.innerHTML = HandlebarsTemplates['management/wysiwyg-block-toolbar']({
        hideChangeBtn: true,
        showSizeBtn: true
      });

      // We attach the event listeners
      this.toolbar.querySelector('.js-remove').addEventListener('click', function () {
        return _this3._onClickRemove();
      });
      this.toolbar.querySelector('.js-toggle-size').addEventListener('click', function () {
        return _this3._onClickToggleSize();
      });
    }
  }], [{
    key: 'create',
    value: function create(obj) {
      var node = _get(WidgetBlot.__proto__ || Object.getPrototypeOf(WidgetBlot), 'create', this).call(this);

      // On the next line we need to check the type of obj because the widget's value (obj)
      // was saved differently in the past and we need to ensure the compatibility with the
      // previous widgets
      var id = (typeof obj === 'undefined' ? 'undefined' : _typeof(obj)) === 'object' ? obj.id : obj;
      var defaultCaption = obj.defaultCaption || false;

      var widgetContainer = document.createElement('div');
      widgetContainer.classList.add('widget-container');
      widgetContainer.classList.add('js-widget-container');

      node.appendChild(widgetContainer);

      // We save the id of the widget into the DOM
      node.dataset.id = id;

      // We don't want the user to be able to edit the widget
      node.setAttribute('contenteditable', false);

      // We add the caption container
      var captionContainer = document.createElement('p');
      captionContainer.classList.add('caption');
      captionContainer.classList.add('js-caption');
      if (defaultCaption) captionContainer.dataset.defaultCaption = 'true';

      node.appendChild(captionContainer);

      // If we don't disable the "content editable" feature of the editor
      // when the user writes in the caption container, the browsers
      // jump to the top as it considers it as the element we're editing
      captionContainer.addEventListener('focusin', function () {
        window.editor.root.setAttribute('contenteditable', false);
      });

      captionContainer.addEventListener('focusout', function () {
        window.editor.root.setAttribute('contenteditable', true);
      });

      captionContainer.addEventListener('blur', function () {
        // If the user deleted the whole content, we want the default
        // text to appear, nevertheless a br tag is inserted so we delete it
        if (!this.textContent.length && this.innerHTML.length) {
          this.innerHTML = '';
        }
      });

      return node;
    }

    /**
     * Return the attributes describing the widget
     * @static
     * @param {HTMLElement} node
     * @returns {object}
     * @memberOf WidgetBlot
     */

  }, {
    key: 'value',
    value: function value(node) {
      return {
        id: +node.dataset.id
      };
    }

    /**
     * Return the attributes attached to the node
     * @static
     * @param {HTMLElement} node
     * @returns {any}
     * @memberOf WidgetBlot
     */

  }, {
    key: 'formats',
    value: function formats(node) {
      var res = {
        id: node.dataset.id
      };

      var caption = node.querySelector('.js-caption');
      if (caption && caption.textContent) {
        res.caption = caption.textContent;
      }

      if (node.classList.contains('-cover')) {
        res.size = 'cover';
      } else if (node.classList.contains('-large')) {
        res.size = 'large';
      } else {
        res.size = 'normal';
      }

      return res;
    }
  }]);

  return WidgetBlot;
}(Embed);

  WidgetBlot.blotName = 'widget';
  WidgetBlot.tagName = 'div';
  WidgetBlot.className = '-widget';
  /* eslint-enable */

  App.Blot.WidgetBlot = WidgetBlot;
})(this.App));
<|endoftext|>


<commit_before>// ECMAScript polyfills
import 'core-js/fn/array/find';
import 'core-js/fn/object/assign';
import 'core-js/fn/promise';
import 'core-js/fn/string/code-point-at';
import 'core-js/fn/string/from-code-point';
import 'core-js/fn/symbol';

// Browser polyfills
import './polyfills/custom_event';
import './polyfills/element';
<commit_msg>add polyfill for Array.from to enable ES spread operator<commit_after>// ECMAScript polyfills
import 'core-js/fn/array/find';
import 'core-js/fn/array/from';
import 'core-js/fn/object/assign';
import 'core-js/fn/promise';
import 'core-js/fn/string/code-point-at';
import 'core-js/fn/string/from-code-point';
import 'core-js/fn/symbol';

// Browser polyfills
import './polyfills/custom_event';
import './polyfills/element';
<|endoftext|>