<commit_before>
<commit_msg>Update ant_switch.js<commit_after>// Copyright (c) 2016 Kari Karvonen, OH1KK

var ant_switch_ext_name = 'ant_switch';		// NB: must match ant_switch.c:ant_switch_ext.name

var ant_switch_first_time = true;

function ant_switch_main()
{
	ext_switch_to_client(ant_switch_ext_name, ant_switch_first_time, ant_switch_recv);		// tell server to use us (again)
	if (!ant_switch_first_time)
		ant_switch_controls_setup();
	ant_switch_first_time = false;
}

var ant_switch_cmd_e = { CMD1:0 };

function ant_switch_recv(data)
{
	var firstChars = getFirstChars(data, 3);

	// process data sent from server/C by ext_send_data_msg()
	if (firstChars == "DAT") {
		var ba = new Uint8Array(data, 4);
		var cmd = ba[0];

		if (cmd == ant_switch_cmd_e.CMD1) {
			// do something ...
		} else {
			console.log('ant_switch_recv: DATA UNKNOWN cmd='+ cmd +' len='+ (ba.length-1));
		}
		return;
	}

	// process command sent from server/C by ext_send_msg() or ext_send_encoded_msg()
	var stringData = arrayBufferToString(data);
	var params = stringData.substring(4).split(" ");

	for (var i=0; i < params.length; i++) {
		var param = params[i].split("=");

		switch (param[0]) {

			case "ready":
				ant_switch_controls_setup();
				break;

			case "Antenna":
				var arg = parseInt(param[1]);
                                ant_switch_process_reply(arg);
				break;

			default:
				console.log('ant_switch_recv: UNKNOWN CMD '+ param[0]);
				break;
		}
	}
}

function ant_switch_controls_setup()
{

   var antdesc = [ ];
   antdesc[1] = ext_get_cfg_param_string('ant_switch.ant1desc', '');
   antdesc[2] = ext_get_cfg_param_string('ant_switch.ant2desc', '');
   antdesc[3] = ext_get_cfg_param_string('ant_switch.ant3desc', '');
   antdesc[4] = ext_get_cfg_param_string('ant_switch.ant4desc', '');
   antdesc[5] = ext_get_cfg_param_string('ant_switch.ant5desc', '');
   antdesc[6] = ext_get_cfg_param_string('ant_switch.ant6desc', '');
   antdesc[7] = ext_get_cfg_param_string('ant_switch.ant7desc', '');

   var buttons_html = ''

   var tmp;
   console.log('ant_switch: Antenna configuration');
   for (tmp = 1; tmp<8; tmp++) {
           if (antdesc[tmp] == undefined || antdesc[tmp] == null || antdesc[tmp] == '') {
                antdesc[tmp] = '';
           }  else {
                buttons_html+=w3_half('', '',
                        w3_btn('Antenna '+tmp, 'ant_switch_select_'+tmp),
                        w3_divs('', '',antdesc[tmp])
                        );
           }
           console.log('ant_switch: Antenna '+ tmp +': '+ antdesc[tmp]);
   }

   var data_html =
      '

';
	var controls_html =
		w3_divs('id-ant_display-controls w3-text-white', '',
			data_html,
        		w3_divs('w3-container', 'w3-tspace-8',
			        w3_divs('', 'w3-medium w3-text-aqua', 'MS-S7-WEB Antenna switch'),
                                w3_divs('id-ant-display-selected', '','Selected antenna: unknown'),
                                w3_divs('', '', 'Antenna switch does not work yet. Still waiting for hardware parts.'),
                                w3_divs('', '',buttons_html),
                                w3_divs('', '','')
                        )
		);

	ext_panel_show(controls_html, null, null);
	ant_switch_visible(1);
	ext_send('GET Antenna');
	ant_display_update();
}

function ant_switch_blur()
{
	console.log('### ant_switch_blur');
	ant_switch_visible(0);		// hook to be called when controls panel is closed
}

// called to display HTML for configuration parameters in admin interface
function ant_switch_config_html()
{
	ext_admin_config(ant_switch_ext_name, 'Antenna switch',
		w3_divs('id-ant_switch w3-text-teal w3-hide', '',
			'MS-S7-WEB Antenna switch configuration' +
			'
Leave Antenna description field empty if you want to disable antenna' +
			'
' +
			w3_third('', 'w3-container',
				w3_divs('', 'w3-margin-bottom',
					w3_input_get_param('Antenna 1 description', 'ant_switch.ant1desc', 'admin_string_cb'),
					w3_input_get_param('Antenna 2 description', 'ant_switch.ant2desc', 'admin_string_cb'),
					w3_input_get_param('Antenna 3 description', 'ant_switch.ant3desc', 'admin_string_cb'),
					w3_input_get_param('Antenna 4 description', 'ant_switch.ant4desc', 'admin_string_cb'),
					w3_input_get_param('Antenna 5 description', 'ant_switch.ant5desc', 'admin_string_cb'),
					w3_input_get_param('Antenna 6 description', 'ant_switch.ant6desc', 'admin_string_cb'),
					w3_input_get_param('Antenna 7 description', 'ant_switch.ant7desc', 'admin_string_cb'),
					w3_input_get_param('Antenna switch failure or unknown status decription', 'ant_switch.ant0desc', 'admin_string_cb')
				), '', ''
			)
		)
	);
}

function ant_switch_visible(v)
{
	visible_block('id-ant_switch-data', v);
}

function ant_switch_select_1(path,val) {
        setTimeout('w3_radio_unhighlight('+ q(path) +')', w3_highlight_time);
        ant_switch_select_antenna(1);
}

function ant_switch_select_2(path,val) {
        setTimeout('w3_radio_unhighlight('+ q(path) +')', w3_highlight_time);
        ant_switch_select_antenna(2);
}

function ant_switch_select_3(path,val) {
        setTimeout('w3_radio_unhighlight('+ q(path) +')', w3_highlight_time);
        ant_switch_select_antenna(3);
}

function ant_switch_select_4(path,val) {
        setTimeout('w3_radio_unhighlight('+ q(path) +')', w3_highlight_time);
        ant_switch_select_antenna(4);
}

function ant_switch_select_5(path,val) {
        setTimeout('w3_radio_unhighlight('+ q(path) +')', w3_highlight_time);
        ant_switch_select_antenna(5);
}

function ant_switch_select_6(path,val) {
        setTimeout('w3_radio_unhighlight('+ q(path) +')', w3_highlight_time);
        ant_switch_select_antenna(6);
}

function ant_switch_select_7(path,val) {
        setTimeout('w3_radio_unhighlight('+ q(path) +')', w3_highlight_time);
        ant_switch_select_antenna(7);
}

function ant_switch_select_antenna(ant) {
        console.log('ant_switch: switching to antenna '+ant);
	ext_send('SET Antenna='+ant);
        ext_send('GET Antenna');
}

function ant_switch_process_reply(ant) {
        ant_selected_antenna = ant;
        console.log('ant_switch: antenna '+ ant_selected_antenna +' in use');
        ant_display_update('Antenna '+ant_selected_antenna + ": "+ext_get_cfg_param_string('ant_switch.ant'+ant_selected_antenna+'desc', ''));
}

function ant_display_update(ant) {
        html('id-ant-display-selected').innerHTML = ant;
        var el = html('rx-antenna');
        if (el != undefined && ant) {
                el.innerHTML = ant;
        }
}
<|endoftext|>


<commit_before><commit_msg>Allow to overwrite markitup configuration even if javascript compression is disabled<commit_after><|endoftext|>


<commit_before>/**
 * Represents a cinema rendering options. Stores the required info in the model's
 * attributes.
 */
cinema.models.RenderingModel = Backbone.Model.extend({
    constructor: function (settings) {
        Backbone.Model.apply(this, arguments);

        this.url = settings.url;
        this.ranges = settings.ranges;
        this.colorByFields = settings.fields;

        this.lutMap = {};
    },

    defaults: {
    },

    initializeLookupTables: function() {
        var that = this;
        _.each(this.colorByFields, function(fieldName) {
            that.initializeLutForFieldToPreset(fieldName, 'spectral');
        });
    },

    ensureLookupTablesReady: function() {
        if (_.isEmpty(this.lutMap)) {
            this.initializeLookupTables();
        }
    },

    initializeLutForFieldToPreset: function(fieldName, presetName) {
        var controlPoints = this.getControlPoints(presetName);
        if (controlPoints !== 'no-match') {
            var controlPointsArray = $.extend(true, [], controlPoints);
            var range = this.getRangeForField(fieldName);
            if (range !== null) {
                this.lutMap[fieldName] = {
                    'controlPoints': controlPointsArray,
                    'clampedRange': range,
                    'dataRange': range
                };
                this._invalidateTable(fieldName);
                return true;
            }
        }
        return false;
    },

    getLookupTableForField: function(fieldName) {
        this.ensureLookupTablesReady();
        if (_.has(this.lutMap, fieldName)) {
            return this.getLutFunction(this.lutMap[fieldName]);
        }
        return null;
    },

    getControlPointsForField: function(fieldName) {
        this.ensureLookupTablesReady();
        if (_.has(this.lutMap, fieldName)) {
            return this.lutMap[fieldName].controlPoints;
        }
        return null;
    },

    getClampedRangeForField: function(fieldName) {
        if (_.has(this.lutMap, fieldName)) {
            return this.lutMap[fieldName].clampedRange;
        }
        return null;
    },

    setClampedRangeForField: function(fieldName, clampedRange) {
        if (_.has(this.lutMap, fieldName)) {
            this.lutMap[fieldName].clampedRange = clampedRange;
            this._invalidateTable(fieldName);
        }
    },

    getRangeForField: function(fieldName) {
        if (_.has(this.ranges, fieldName)) {
            return this.ranges[fieldName];
        }
        return null;
    },

    getFields: function() {
        this.ensureLookupTablesReady();
        return this.colorByFields;
    },

    loaded: function () {
        return this.has('swatches');
    },

    url: function () {
        return this.url;
    },

    getData: function (name) {
        if(this.loaded()) {
            return this.get(name);
        }
        return 'no-match';
    },

    getPresetNames: function() {
        if (this.loaded()) {
            return _.keys(this.get('lookuptables'));
        }
        return [];
    },

    getControlPoints: function (name) {
        if(this.loaded()) {
            return this.get('lookuptables')[name].controlpoints;
        }
        return 'no-match';
    },

    applyRatio: function (a, b, ratio) {
        return ((b - a) * ratio) + a;
    },

    interpolateColor: function (pointA, pointB, value) {
        var ratio = (value - pointA[0]) / (pointB[0] - pointA[0]);
        return [ this.applyRatio(pointA[1], pointB[1], ratio) * 255,
                 this.applyRatio(pointA[2], pointB[2], ratio) * 255,
                 this.applyRatio(pointA[3], pointB[3], ratio) * 255 ];
    },

    extractPoint: function (controlPoints, idx) {
        return [ controlPoints[idx].x, controlPoints[idx].r, controlPoints[idx].g, controlPoints[idx].b ];
    },

    transform: function(inMin, value, inMax, outMin, outMax) {
        return (((value - inMin) / (inMax - inMin)) * (outMax - outMin)) + outMin;
    },

    getLutFunction: function(config) {
        var table =  [],
            controlPoints = $.extend(true, [], config.controlPoints),
            clampedRange = config.clampedRange,
            dataRange = config.dataRange,
            currentControlIdx = 0,
            nbColorInTable = 256; // Can be increased

        // Now actually generate the lookup table from the (maybe modified)
        // control points.
        for (var idx = 0; idx < nbColorInTable; idx += 1) {
            var value = idx / (nbColorInTable - 1),
                pointA = this.extractPoint(controlPoints, currentControlIdx),
                pointB = this.extractPoint(controlPoints, currentControlIdx + 1);

            if (value > pointB[0]) {
                currentControlIdx += 1;
                pointA = this.extractPoint(controlPoints, currentControlIdx);
                pointB = this.extractPoint(controlPoints, currentControlIdx + 1);
            }

            table.push(this.interpolateColor(pointA, pointB, value));
        }

        var self = this;

        function lut(value) {
            var actualValue = self.transform(0.0, value, 1.0, dataRange[0], dataRange[1]);
            if (actualValue < clampedRange[0]) {
                var cp1 = controlPoints[0];
                return [ cp1.r * 255, cp1.g * 255, cp1.b * 255 ];
            } else if (actualValue > clampedRange[1]) {
                var cpn = controlPoints[controlPoints.length - 1];
                return [ cpn.r * 255, cpn.g * 255, cpn.b * 255 ];
            }
            var clampedValue = self.transform(clampedRange[0], actualValue, clampedRange[1], 0.0, 1.0);
            return table[Math.floor(clampedValue * (nbColorInTable - 1))];
        }

        return lut;
    },

    _invalidateTable: function (name) {
        this.trigger('c:lut-invalid', {'field': name});
    }
});
<commit_msg>fix edge condition for constant data ranges in lut function.<commit_after>/**
 * Represents a cinema rendering options. Stores the required info in the model's
 * attributes.
 */
cinema.models.RenderingModel = Backbone.Model.extend({
    constructor: function (settings) {
        Backbone.Model.apply(this, arguments);

        this.url = settings.url;
        this.ranges = settings.ranges;
        this.colorByFields = settings.fields;

        this.lutMap = {};
    },

    defaults: {
    },

    initializeLookupTables: function() {
        var that = this;
        _.each(this.colorByFields, function(fieldName) {
            that.initializeLutForFieldToPreset(fieldName, 'spectral');
        });
    },

    ensureLookupTablesReady: function() {
        if (_.isEmpty(this.lutMap)) {
            this.initializeLookupTables();
        }
    },

    initializeLutForFieldToPreset: function(fieldName, presetName) {
        var controlPoints = this.getControlPoints(presetName);
        if (controlPoints !== 'no-match') {
            var controlPointsArray = $.extend(true, [], controlPoints);
            var range = this.getRangeForField(fieldName);
            if (range !== null) {
                this.lutMap[fieldName] = {
                    'controlPoints': controlPointsArray,
                    'clampedRange': range,
                    'dataRange': range
                };
                this._invalidateTable(fieldName);
                return true;
            }
        }
        return false;
    },

    getLookupTableForField: function(fieldName) {
        this.ensureLookupTablesReady();
        if (_.has(this.lutMap, fieldName)) {
            return this.getLutFunction(this.lutMap[fieldName]);
        }
        return null;
    },

    getControlPointsForField: function(fieldName) {
        this.ensureLookupTablesReady();
        if (_.has(this.lutMap, fieldName)) {
            return this.lutMap[fieldName].controlPoints;
        }
        return null;
    },

    getClampedRangeForField: function(fieldName) {
        if (_.has(this.lutMap, fieldName)) {
            return this.lutMap[fieldName].clampedRange;
        }
        return null;
    },

    setClampedRangeForField: function(fieldName, clampedRange) {
        if (_.has(this.lutMap, fieldName)) {
            this.lutMap[fieldName].clampedRange = clampedRange;
            this._invalidateTable(fieldName);
        }
    },

    getRangeForField: function(fieldName) {
        if (_.has(this.ranges, fieldName)) {
            return this.ranges[fieldName];
        }
        return null;
    },

    getFields: function() {
        this.ensureLookupTablesReady();
        return this.colorByFields;
    },

    loaded: function () {
        return this.has('swatches');
    },

    url: function () {
        return this.url;
    },

    getData: function (name) {
        if(this.loaded()) {
            return this.get(name);
        }
        return 'no-match';
    },

    getPresetNames: function() {
        if (this.loaded()) {
            return _.keys(this.get('lookuptables'));
        }
        return [];
    },

    getControlPoints: function (name) {
        if(this.loaded()) {
            return this.get('lookuptables')[name].controlpoints;
        }
        return 'no-match';
    },

    applyRatio: function (a, b, ratio) {
        return ((b - a) * ratio) + a;
    },

    interpolateColor: function (pointA, pointB, value) {
        var ratio = (value - pointA[0]) / (pointB[0] - pointA[0]);
        return [ this.applyRatio(pointA[1], pointB[1], ratio) * 255,
                 this.applyRatio(pointA[2], pointB[2], ratio) * 255,
                 this.applyRatio(pointA[3], pointB[3], ratio) * 255 ];
    },

    extractPoint: function (controlPoints, idx) {
        return [ controlPoints[idx].x, controlPoints[idx].r, controlPoints[idx].g, controlPoints[idx].b ];
    },

    transform: function(inMin, value, inMax, outMin, outMax) {
        return (((value - inMin) / (inMax - inMin)) * (outMax - outMin)) + outMin;
    },

    getLutFunction: function(config) {
        var table =  [],
            controlPoints = $.extend(true, [], config.controlPoints),
            clampedRange = config.clampedRange,
            dataRange = config.dataRange,
            currentControlIdx = 0,
            nbColorInTable = 256; // Can be increased

        // Now actually generate the lookup table from the (maybe modified)
        // control points.
        for (var idx = 0; idx < nbColorInTable; idx += 1) {
            var value = idx / (nbColorInTable - 1),
                pointA = this.extractPoint(controlPoints, currentControlIdx),
                pointB = this.extractPoint(controlPoints, currentControlIdx + 1);

            if (value > pointB[0]) {
                currentControlIdx += 1;
                pointA = this.extractPoint(controlPoints, currentControlIdx);
                pointB = this.extractPoint(controlPoints, currentControlIdx + 1);
            }

            table.push(this.interpolateColor(pointA, pointB, value));
        }

        var self = this;

        function lut(value) {
            if (dataRange[0] === dataRange[1]) {
                var cp1 = controlPoints[0];
                return [ cp1.r * 255, cp1.g * 255, cp1.b * 255 ];
            }
            var actualValue = self.transform(0.0, value, 1.0, dataRange[0], dataRange[1]);
            if (actualValue < clampedRange[0]) {
                var cp1 = controlPoints[0];
                return [ cp1.r * 255, cp1.g * 255, cp1.b * 255 ];
            } else if (actualValue > clampedRange[1]) {
                var cpn = controlPoints[controlPoints.length - 1];
                return [ cpn.r * 255, cpn.g * 255, cpn.b * 255 ];
            }
            var clampedValue = self.transform(clampedRange[0], actualValue, clampedRange[1], 0.0, 1.0);
            return table[Math.floor(clampedValue * (nbColorInTable - 1))];
        }

        return lut;
    },

    _invalidateTable: function (name) {
        this.trigger('c:lut-invalid', {'field': name});
    }
});
<|endoftext|>


<commit_before>//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// 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.
//

/**
* Demonstrates how to define sendingrequest and receivedresponse event handlers.
*/
const fs = require('fs');
const azure = require('azure-storage');
const container = 'sendingrequestevent3';
// The service object which will define the event handlers
const blobService = azure.createBlobService();
// optionally set a proxy
/*const proxy = {
  protocol: 'http:',
  host: '127.0.0.1',
  port: 8888
};
blobService.setProxy(proxy);
blobService2.setProxy(proxy);
*/
// the sending request event handler
let sendingRequestHandler = (webresource) => {
  webresource.withHeader('x-ms-custom-header', 'value');
  console.log('sending request event handler called');
};

// the response received event handler
let responseReceivedHandler = (response) => {
  console.log('received response event handler called');
};

let eventHandlersSample = () => {
  console.log('Starting eventHandlersSample.');
  // set the event handlers
  blobService.on('sendingRequestEvent', sendingRequestHandler);
  blobService.on('receivedResponseEvent', responseReceivedHandler);
  // create and delete a container with these handlers
  createContainer(container)
  .then((container) => {
    console.log('Created the container ' + container);
    // Delete the container
    console.log('Ending eventHandlersSample.');
    return deleteContainer(container);
  }).then((container) => {
      console.log('Deleted the container ' + container);
    })
  .catch((error) => console.error(error));
}
// Create the container.
let createContainer = (container) => new Promise((resolve, reject) => {
  blobService.createContainer(container, (error) => {
    if (error) {
      reject(error);
    } else {
      resolve(container);
    }
  });
});

// Delete the container.
let deleteContainer = (container) => new Promise((resolve, reject) => {
  blobService.deleteContainer(container, (error) => {
    if (error) {
      reject(error);
    } else {
      resolve(container);
    }
  });
});
//
eventHandlersSample();
<commit_msg>Rename params and variables<commit_after>//
// Copyright (c) Microsoft and contributors.  All rights reserved.
//
// 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.
//

/**
* Demonstrates how to define sendingrequest and receivedresponse event handlers.
*/
const fs = require('fs');
const azure = require('azure-storage');
const container = 'sendingrequestevent3';
// The service object which will define the event handlers
const blobService = azure.createBlobService();
// optionally set a proxy
/*const proxy = {
  protocol: 'http:',
  host: '127.0.0.1',
  port: 8888
};
blobService.setProxy(proxy);
blobService2.setProxy(proxy);
*/
// the sending request event handler
let sendingRequestHandler = (webresource) => {
  webresource.withHeader('x-ms-custom-header', 'value');
  console.log('sending request event handler called');
};

// the response received event handler
let responseReceivedHandler = (response) => {
  console.log('received response event handler called');
};

let eventHandlersSample = (service, container) => {
  console.log('Starting eventHandlersSample.');
  // set the event handlers
  service.on('sendingRequestEvent', sendingRequestHandler);
  service.on('receivedResponseEvent', responseReceivedHandler);
  // create and delete a container with these handlers
  createContainer(container)
  .then((container) => {
    console.log('Created the container ' + container);
    // Delete the container
    console.log('Ending eventHandlersSample.');
    return deleteContainer(container);
  }).then((container) => {
      console.log('Deleted the container ' + container);
    })
  .catch((error) => console.error(error));
}
// Create the container.
let createContainer = (container) => new Promise((resolve, reject) => {
  blobService.createContainer(container, (error) => {
    if (error) {
      reject(error);
    } else {
      resolve(container);
    }
  });
});

// Delete the container.
let deleteContainer = (container) => new Promise((resolve, reject) => {
  blobService.deleteContainer(container, (error) => {
    if (error) {
      reject(error);
    } else {
      resolve(container);
    }
  });
});
//
eventHandlersSample(blobService, container);
<|endoftext|>


<commit_before>;
(function(mag) {

  'use strict';

  var render = {
      roots: [],
      contexts: [],
      templates: {},
      unloaders: [],
      cache: {}
    },
    iscached = function(key, data) {
      if (render.cache[key] && render.cache[key] === JSON.stringify(data)) {
        return true
      }
      render.cache[key] = JSON.stringify(data)
    }

  function callView(elementClone, module, i) {
    var args = module.getArgs(i),
      mod = module.modules[i],
      controller = module.controllers[i];

    //module.modules[i].id = elementClone.id;
    mag.count = []

    if (mod) mod.view(args[0], elementClone)
  }

  // call Lifecycle event
  render.callLCEvent = function(eventName, module, index, once) {
    var isPrevented = false,
      event = {
        preventDefault: function() {
          isPrevented = true
        }
      }
    if (module.controllers[index] && module.controllers[index][eventName]) {
      module.controllers[index][eventName].call({}, event, module.elements[index])
      if (once) module.controllers[index][eventName] = 0
    }

    if (isPrevented) {
      // unloading

      for (var i = 0, unloader; unloader = render.unloaders[i]; i++) {

        if (unloader.controller.onunload) {
          unloader.handler.call(unloader.controller, module.elements[index])
          unloader.controller.onunload = 0
        }
      }
    }

    return isPrevented
  }

  render.callConfigs = function(configs) {
    for (var i = 0, len = configs.length; i < len; i++) configs[i]()
  }

  render.redraw = function(module, fill, force) {

    module = module || render.module || {}
    if (force) render.cache = {}

    this.fun = (this.fun || throttle(function(id) {
      // clear existing configs
      fill.configs.splice(0, fill.configs.length)
      render.doLoop(module, fill)
    }))
    this.fun()
  }

  function addConfigUnloaders(module, fill, index) {

    //var cfgUnloaders = []

    for (var k in fill.cached) {
      //console.log(module.elements[index].id, k)
      if (k.indexOf('id("' + module.elements[index].id + '")/') !== -1 && k.indexOf('-config') !== -1 && fill.cached[k].configContext) {
        //            console.log(k, fill.cached[k].configContext.onunload)

        render.unloaders.push({
          controller: fill.cached[k].configContext,
          handler: fill.cached[k].configContext.onunload
        })

      }
    }
  }
  render.doLoop = function(module, fill) {
    for (var i = 0, root; root = render.roots[i]; i++) {

      if (module.controllers[i] && module.elements[i]) {
        if (render.callLCEvent('willload', module, i, 1)) return

        if (!render.innerLoop(module, fill, i)) {

        } else {
          module.deferreds[i][1]({
            _html: mag.prop(module.elements[i])
              // _html: function(node){ return node }.bind({}, module.elements[i])
              // _html : function(node){return fill.cloneNodeWithEvents(node)}.bind({}, module.elements[i])
              //clone: fill.cloneNodeWithEvents(module.elements[i])
              //_html: module.elements[i].innerHTML
          })
          render.callLCEvent('didload', module, i, 1)
          render.callConfigs(fill.configs)

          // add configs unloaders
          addConfigUnloaders(module, fill, i)
            //TODO: remove clones
            // if (module.deferreds[i][0]) {
            //   delete module.elements[i]
            //   delete module.modules[i]
            //   delete module.controllers[i]
            //   delete module.promises[i]
            //   delete module.deferreds[i]
            // }
        }
      }
    }

  }

  render.clear = function(index, elementId, fill) {
    if (index !== -1 && render.cache[index]) {
      //console.log('clear called on reload', elementId)
      delete render.cache[index]
    }
  }
  render.innerLoop = function(module, fill, i) {
    var elementClone = module.elements[i]
    var args = module.getArgs(i)

    if (iscached(i, args)) {
      return false
    }
    // circular references will throw an exception
    // such as setting to a dom element
    callView(elementClone, module, i)

    render.setupWatch(args, fill, elementClone, i, module)

    fill.fill(elementClone, args[0])

    return true
  }

  var $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
  var $requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;

  var throttle = function(fn, threshhold) {
    var lastRedrawCallTime, FRAME_BUDGET = threshhold || 16,
      deferTimer
    return function() {
      var args = arguments
      if ($requestAnimationFrame === window.requestAnimationFrame || +new Date - lastRedrawCallTime > FRAME_BUDGET) {
        // hold on to it
        if (deferTimer > 0) $cancelAnimationFrame(deferTimer)
        deferTimer = $requestAnimationFrame(function() {
          lastRedrawCallTime = +new Date
          var nargs = [].slice.call(arguments).concat([].slice.call(args))
          fn.apply(this, nargs);
          mag.redrawing = false
        }, FRAME_BUDGET)
      } else {
        // called when setTimeout is used
        lastRedrawCallTime = +new Date
        var nargs = [].slice.call(arguments).concat([].slice.call(args))
        fn.apply(this, nargs)
        deferTimer = $requestAnimationFrame(function() {
          deferTimer = null
          mag.redrawing = false
        }, FRAME_BUDGET)
      }
    }
  }

  mag.render = render

  var prevId

  render.doWatch = function(fill, ele, i, module, changes, frameId) {

    if (frameId == prevId) return
    prevId = frameId

    render.callLCEvent('isupdate', module, i)

    var args = module.getArgs(i)
      // check if data changed
    if (iscached(i, args)) {
      return
    }
    //TODO: return true then skip execution?
    if (render.callLCEvent('willupdate', module, i, 1)) return

    callView(ele, module, i)

    fill.fill(ele, args[0])
    render.callLCEvent('didupdate', module, i)
  }

  render.setupWatch = function(args, fill, elementClone, i, module) {

    // console.log('setup', i)

    var observer = function(changes) {
        changes.forEach(function(change) {

          if (change.type == 'update' && change.oldValue && change.oldValue.type == 'fun' && change.oldValue.data && change.oldValue.data.type == 'module' && change.object[change.name] && !change.object[change.name].data) {
            // call unloader for module
            render.callLCEvent('onunload', module, change.oldValue.data.id, 1)
              //console.log(change.name,change.object[change.name].data, change.oldValue.data)
          }
          //console.log('change', change.type, change.name)

        });

        module.controllers[i] = args[0]
        throttle(render.doWatch.bind({}, fill, elementClone, i, module, changes))()
      }
      // Which we then observe
    observeNested(args[0], observer);
  }

  function debounce(func, wait, immediate) {
    var timeout;
    return function() {

      var obj = this,
        args = arguments;

      function delayed() {
        if (!immediate)
          func.apply(obj, args);
        timeout = null;
      };

      if (timeout)
        $cancelAnimationFrame(timeout);
      else if (immediate)
        func.apply(obj, args);

      timeout = $requestAnimationFrame(delayed, wait);
    };
  };
  var exclude = ['add', 'update', 'delete']

  function notifySubobjectChanges(object) {
    var notifier = Object.getNotifier(object); // get notifier for this object
    var handle = function(changes) { // observe the property value
      changes.forEach(function(change) { // and for each change
        notifier.notify(change);
      });
    }
    for (var k in object) { // loop over its properties
      var prop = object[k]; // get property value
      if (!prop || typeof prop !== 'object') break; // skip over non-objects
      if (typeof Array.observe !== 'undefined' && Array.isArray(prop)) {
        Array.observe(prop, handle, exclude);
      } else {
        Object.observe(prop, handle, exclude);
      }
      notifySubobjectChanges(prop); // repeat for sub-subproperties
    }
  }

  function observeNested(obj, callback) {
    if (obj && typeof Object.observe !== 'undefined') {
      var handler = debounce(callback, 16)
        // var handler = callback
      notifySubobjectChanges(obj); // set up recursive observers
      Object.observe(obj, handler, exclude);
      //Object.unobserve(obj, handler);
    }
  }

})(window.mag || {})
<commit_msg>Update render.js<commit_after>;
(function(mag) {

  'use strict';

  var render = {
      roots: [],
      contexts: [],
      templates: {},
      unloaders: [],
      cache: {}
    },
    iscached = function(key, data) {
      if (render.cache[key] && render.cache[key] === JSON.stringify(data)) {
        return true
      }
      render.cache[key] = JSON.stringify(data)
    }

  function callView(elementClone, module, i) {
    var args = module.getArgs(i),
      mod = module.modules[i],
      controller = module.controllers[i];

    //module.modules[i].id = elementClone.id;
    // mag.count = []

    if (mod) mod.view(args[0], elementClone)
  }

  // call Lifecycle event
  render.callLCEvent = function(eventName, module, index, once) {
    var isPrevented = false,
      event = {
        preventDefault: function() {
          isPrevented = true
        }
      }
    if (module.controllers[index] && module.controllers[index][eventName]) {
      module.controllers[index][eventName].call({}, event, module.elements[index])
      if (once) module.controllers[index][eventName] = 0
    }

    if (isPrevented) {
      // unloading

      for (var i = 0, unloader; unloader = render.unloaders[i]; i++) {

        if (unloader.controller.onunload) {
          unloader.handler.call(unloader.controller, module.elements[index])
          unloader.controller.onunload = 0
        }
      }
    }

    return isPrevented
  }

  render.callConfigs = function(configs) {
    for (var i = 0, len = configs.length; i < len; i++) configs[i]()
  }

  render.redraw = function(module, fill, force) {

    module = module || render.module || {}
    if (force) render.cache = {}

    this.fun = (this.fun || throttle(function(id) {
      // clear existing configs
      fill.configs.splice(0, fill.configs.length)
      render.doLoop(module, fill)
    }))
    this.fun()
  }

  function addConfigUnloaders(module, fill, index) {

    //var cfgUnloaders = []

    for (var k in fill.cached) {
      //console.log(module.elements[index].id, k)
      if (k.indexOf('id("' + module.elements[index].id + '")/') !== -1 && k.indexOf('-config') !== -1 && fill.cached[k].configContext) {
        //            console.log(k, fill.cached[k].configContext.onunload)

        render.unloaders.push({
          controller: fill.cached[k].configContext,
          handler: fill.cached[k].configContext.onunload
        })

      }
    }
  }
  render.doLoop = function(module, fill) {
    for (var i = 0, root; root = render.roots[i]; i++) {

      if (module.controllers[i] && module.elements[i]) {
        if (render.callLCEvent('willload', module, i, 1)) return

        if (!render.innerLoop(module, fill, i)) {

        } else {
          module.deferreds[i][1]({
            _html: mag.prop(module.elements[i])
              // _html: function(node){ return node }.bind({}, module.elements[i])
              // _html : function(node){return fill.cloneNodeWithEvents(node)}.bind({}, module.elements[i])
              //clone: fill.cloneNodeWithEvents(module.elements[i])
              //_html: module.elements[i].innerHTML
          })
          render.callLCEvent('didload', module, i, 1)
          render.callConfigs(fill.configs)

          // add configs unloaders
          addConfigUnloaders(module, fill, i)
            //TODO: remove clones
            // if (module.deferreds[i][0]) {
            //   delete module.elements[i]
            //   delete module.modules[i]
            //   delete module.controllers[i]
            //   delete module.promises[i]
            //   delete module.deferreds[i]
            // }
        }
      }
    }

  }

  render.clear = function(index, elementId, fill) {
    if (index !== -1 && render.cache[index]) {
      //console.log('clear called on reload', elementId)
      delete render.cache[index]
    }
  }
  render.innerLoop = function(module, fill, i) {
    var elementClone = module.elements[i]
    var args = module.getArgs(i)

    if (iscached(i, args)) {
      return false
    }
    // circular references will throw an exception
    // such as setting to a dom element
    callView(elementClone, module, i)

    render.setupWatch(args, fill, elementClone, i, module)

    fill.fill(elementClone, args[0])

    return true
  }

  var $cancelAnimationFrame = window.cancelAnimationFrame || window.clearTimeout;
  var $requestAnimationFrame = window.requestAnimationFrame || window.setTimeout;

  var throttle = function(fn, threshhold) {
    var lastRedrawCallTime, FRAME_BUDGET = threshhold || 16,
      deferTimer
    return function() {
      var args = arguments
      if ($requestAnimationFrame === window.requestAnimationFrame || +new Date - lastRedrawCallTime > FRAME_BUDGET) {
        // hold on to it
        if (deferTimer > 0) $cancelAnimationFrame(deferTimer)
        deferTimer = $requestAnimationFrame(function() {
          lastRedrawCallTime = +new Date
          var nargs = [].slice.call(arguments).concat([].slice.call(args))
          fn.apply(this, nargs);
          mag.redrawing = false
        }, FRAME_BUDGET)
      } else {
        // called when setTimeout is used
        lastRedrawCallTime = +new Date
        var nargs = [].slice.call(arguments).concat([].slice.call(args))
        fn.apply(this, nargs)
        deferTimer = $requestAnimationFrame(function() {
          deferTimer = null
          mag.redrawing = false
        }, FRAME_BUDGET)
      }
    }
  }

  mag.render = render

  var prevId

  render.doWatch = function(fill, ele, i, module, changes, frameId) {

    if (frameId == prevId) return
    prevId = frameId

    render.callLCEvent('isupdate', module, i)

    var args = module.getArgs(i)
      // check if data changed
    if (iscached(i, args)) {
      return
    }
    //TODO: return true then skip execution?
    if (render.callLCEvent('willupdate', module, i, 1)) return

    callView(ele, module, i)

    fill.fill(ele, args[0])
    render.callLCEvent('didupdate', module, i)
  }

  render.setupWatch = function(args, fill, elementClone, i, module) {

    // console.log('setup', i)

    var observer = function(changes) {
        changes.forEach(function(change) {

          if (change.type == 'update' && change.oldValue && change.oldValue.type == 'fun' && change.oldValue.data && change.oldValue.data.type == 'module' && change.object[change.name] && !change.object[change.name].data) {
            // call unloader for module
            render.callLCEvent('onunload', module, change.oldValue.data.id, 1)
              //console.log(change.name,change.object[change.name].data, change.oldValue.data)
          }
          //console.log('change', change.type, change.name)

        });

        module.controllers[i] = args[0]
        throttle(render.doWatch.bind({}, fill, elementClone, i, module, changes))()
      }
      // Which we then observe
    observeNested(args[0], observer);
  }

  function debounce(func, wait, immediate) {
    var timeout;
    return function() {

      var obj = this,
        args = arguments;

      function delayed() {
        if (!immediate)
          func.apply(obj, args);
        timeout = null;
      };

      if (timeout)
        $cancelAnimationFrame(timeout);
      else if (immediate)
        func.apply(obj, args);

      timeout = $requestAnimationFrame(delayed, wait);
    };
  };
  var exclude = ['add', 'update', 'delete']

  function notifySubobjectChanges(object) {
    var notifier = Object.getNotifier(object); // get notifier for this object
    var handle = function(changes) { // observe the property value
      changes.forEach(function(change) { // and for each change
        notifier.notify(change);
      });
    }
    for (var k in object) { // loop over its properties
      var prop = object[k]; // get property value
      if (!prop || typeof prop !== 'object') break; // skip over non-objects
      if (typeof Array.observe !== 'undefined' && Array.isArray(prop)) {
        Array.observe(prop, handle, exclude);
      } else {
        Object.observe(prop, handle, exclude);
      }
      notifySubobjectChanges(prop); // repeat for sub-subproperties
    }
  }

  function observeNested(obj, callback) {
    if (obj && typeof Object.observe !== 'undefined') {
      var handler = debounce(callback, 16)
        // var handler = callback
      notifySubobjectChanges(obj); // set up recursive observers
      Object.observe(obj, handler, exclude);
      //Object.unobserve(obj, handler);
    }
  }

})(window.mag || {})
<|endoftext|>


<commit_before>import {inject} from 'aurelia-dependency-injection';
import {ObserverLocator, calcSplices, getChangeRecords} from 'aurelia-binding';
import {BoundViewFactory, ViewSlot, customAttribute, bindable, templateController} from 'aurelia-templating';

/**
* Binding to iterate over an array and repeat a template
*
* @class Repeat
* @constructor
* @param {BoundViewFactory} viewFactory The factory generating the view
* @param {ViewSlot} viewSlot The slot the view is injected in to
* @param {ObserverLocator} observerLocator The observer locator instance
*/
@customAttribute('repeat')
@templateController
@inject(BoundViewFactory, ViewSlot, ObserverLocator)
export class Repeat {
  /**
  * List of items to bind the repeater to
  *
  * @property items
  * @type {Array}
  */
  @bindable items
  @bindable local
  @bindable key
  @bindable value
  constructor(viewFactory, viewSlot, observerLocator){
    this.viewFactory = viewFactory;
    this.viewSlot = viewSlot;
    this.observerLocator = observerLocator;
    this.local = 'item';
    this.key = 'key';
    this.value = 'value';
  }

  bind(executionContext){
    var items = this.items,
      observer;

    this.executionContext = executionContext;

    if(!items){
      if(this.oldItems){
        this.viewSlot.removeAll();
      }

      return;
    }

    if (this.oldItems === items) {
      if (items instanceof Map) {
        var records = getChangeRecords(items);
        observer = this.observerLocator.getMapObserver(items);

        this.handleMapChangeRecords(items, records);

        this.disposeSubscription = observer.subscribe(records => {
          this.handleMapChangeRecords(items, records);
        });
      } else {
        var splices = calcSplices(items, 0, items.length, this.lastBoundItems, 0, this.lastBoundItems.length);
        observer = this.observerLocator.getArrayObserver(items);

        this.handleSplices(items, splices);
        this.lastBoundItems = this.oldItems = null;

        this.disposeSubscription = observer.subscribe(splices => {
          this.handleSplices(items, splices);
        });
      }
    } else {
      this.processItems();
    }
  }

  unbind(){
    this.oldItems = this.items;

    if(this.items instanceof Array){
      this.lastBoundItems = this.items.slice(0);
    }

    if(this.disposeSubscription){
      this.disposeSubscription();
      this.disposeSubscription = null;
    }
  }

  itemsChanged() {
    this.processItems();
  }

  processItems() {
    var items = this.items,
      viewSlot = this.viewSlot;

    if (this.disposeSubscription) {
      this.disposeSubscription();
      viewSlot.removeAll();
    }

    if(!items){
      return;
    }

    if (items instanceof Array) {
      this.processArrayItems(items);
    } else if(items instanceof Map) {
      this.processMapEntries(items);
    } else if((typeof items === 'number')){
      this.processNumber(items);
    }else{
      throw new Error('Object in "repeat" must be of type Array, Map or Number');
    }
  }

  processArrayItems(items){
    var viewFactory = this.viewFactory,
      viewSlot = this.viewSlot,
      i, ii, row, view, observer;

    observer = this.observerLocator.getArrayObserver(items);

    for(i = 0, ii = items.length; i < ii; ++i){
      row = this.createFullExecutionContext(items[i], i, ii);
      view = viewFactory.create(row);
      viewSlot.add(view);
    }

    this.disposeSubscription = observer.subscribe(splices => {
      this.handleSplices(items, splices);
    });
  }

  processMapEntries(items) {
    var viewFactory = this.viewFactory,
      viewSlot = this.viewSlot,
      index = 0,
      row, view, observer;

    observer = this.observerLocator.getMapObserver(items);

    items.forEach((value, key) => {
      row = this.createFullExecutionKvpContext(key, value, index, items.size);
      view = viewFactory.create(row);
      viewSlot.add(view);
      ++index;
    });

    this.disposeSubscription = observer.subscribe(record => {
      this.handleMapChangeRecords(items, record);
    });
  }

  processNumber(value){
    var viewFactory = this.viewFactory,
      viewSlot = this.viewSlot,
      i, ii, row, view;

    for(i = 0, ii = Math.floor(value); i < ii; ++i){
      row = this.createFullExecutionContext(i, i, ii);
      view = viewFactory.create(row);
      viewSlot.add(view);
    }
  }

  createBaseExecutionContext(data){
    var context = {};
    context[this.local] = data;
    context.$parent = this.executionContext;
    return context;
  }

  createBaseExecutionKvpContext(key, value){
    var context = {};
    context[this.key] = key;
    context[this.value] = value;
    context.$parent = this.executionContext;
    return context;
  }

  createFullExecutionContext(data, index, length){
    var context = this.createBaseExecutionContext(data);
    return this.updateExecutionContext(context, index, length);
  }

  createFullExecutionKvpContext(key, value, index, length){
    var context = this.createBaseExecutionKvpContext(key, value);
    return this.updateExecutionContext(context, index, length);
  }

  updateExecutionContext(context, index, length){
    var first = (index === 0),
        last = (index === length - 1),
        even = index % 2 === 0;

    context.$index = index;
    context.$first = first;
    context.$last = last;
    context.$middle = !(first || last);
    context.$odd = !even;
    context.$even = even;

    return context;
  }

  handleSplices(array, splices) {
    var viewLookup = new Map(),
      viewSlot = this.viewSlot,
      spliceIndexLow, viewOrPromise, view,
      i, ii, j, jj, row, splice,
      addIndex, end, itemsLeftToAdd,
      removed, model, children, length;

    for (i = 0, ii = splices.length; i < ii; ++i) {
      splice = splices[i];
      addIndex = splice.index;
      itemsLeftToAdd = splice.addedCount;
      end = splice.index + splice.addedCount;
      removed = splice.removed;
      if(typeof spliceIndexLow === 'undefined' || spliceIndexLow === null || spliceIndexLow > splice.index){
        spliceIndexLow = splice.index;
      }

      for (j = 0, jj = removed.length; j < jj; ++j) {
        if (itemsLeftToAdd > 0) {
          view = viewSlot.children[splice.index + j];
          view.executionContext[this.local] = array[addIndex + j];
          --itemsLeftToAdd;
        } else {
          viewOrPromise = viewSlot.removeAt(addIndex + splice.addedCount);
          if(viewOrPromise){
            viewLookup.set(removed[j], viewOrPromise);
          }
        }
      }

      addIndex += removed.length;

      for (; 0 < itemsLeftToAdd; ++addIndex) {
        model = array[addIndex];
        viewOrPromise = viewLookup.get(model);
        if(viewOrPromise instanceof Promise){
          ((localAddIndex, localModel) => {
            viewOrPromise.then(view => {
              viewLookup.delete(localModel);
              viewSlot.insert(localAddIndex, view);
            });
          })(addIndex, model);
        }else if(viewOrPromise){
          viewLookup.delete(model);
          viewSlot.insert(addIndex, viewOrPromise);
        }else{
          row = this.createBaseExecutionContext(model);
          view = this.viewFactory.create(row);
          viewSlot.insert(addIndex, view);
        }
        --itemsLeftToAdd;
      }
    }

    children = this.viewSlot.children;
    length = children.length;

    if(spliceIndexLow > 0){
      spliceIndexLow = spliceIndexLow - 1;
    }

    for(; spliceIndexLow < length; ++spliceIndexLow){
      this.updateExecutionContext(children[spliceIndexLow].executionContext, spliceIndexLow, length);
    }

    viewLookup.forEach(x => {
      if(x instanceof Promise){
        x.then(y => y.unbind());
      }else{
        x.unbind();
      }
    });
  }

  handleMapChangeRecords(map, records) {
    var viewSlot = this.viewSlot,
      key, i, ii, view, children, length, row, removeIndex, record;

    for (i = 0, ii = records.length; i < ii; ++i) {
      record = records[i];
      key = record.key;
      switch (record.type) {
        case 'update':
          removeIndex = this.getViewIndexByKey(key);
          viewSlot.removeAt(removeIndex);
          row = this.createBaseExecutionKvpContext(key, map.get(key));
          view = this.viewFactory.create(row);
          viewSlot.insert(removeIndex, view);
          break;
        case 'add':
          row = this.createBaseExecutionKvpContext(key, map.get(key));
          view = this.viewFactory.create(row);
          viewSlot.insert(map.size, view);
          break;
        case 'delete':
          if (!record.oldValue) { return; }
          removeIndex = this.getViewIndexByKey(key);
          viewSlot.removeAt(removeIndex);
          break;
        case 'clear':
          viewSlot.removeAll();
      }
    }

    children = viewSlot.children;
    length = children.length;

    for (i = 0; i < length; i++) {
      this.updateExecutionContext(children[i].executionContext, i, length);
    }
  }

  getViewIndexByKey(key) {
    var viewSlot = this.viewSlot,
      i, ii, child;

    for (i = 0, ii = viewSlot.children.length; i < ii; ++i) { // TODO (martingust) better way to get index?
      child = viewSlot.children[i];
      if (child.bindings[0].source[this.key] === key) {
        return i;
      }
    }
  }
}
<commit_msg>fix(repeat): unbind children on property change<commit_after>import {inject} from 'aurelia-dependency-injection';
import {ObserverLocator, calcSplices, getChangeRecords} from 'aurelia-binding';
import {BoundViewFactory, ViewSlot, customAttribute, bindable, templateController} from 'aurelia-templating';

/**
* Binding to iterate over an array and repeat a template
*
* @class Repeat
* @constructor
* @param {BoundViewFactory} viewFactory The factory generating the view
* @param {ViewSlot} viewSlot The slot the view is injected in to
* @param {ObserverLocator} observerLocator The observer locator instance
*/
@customAttribute('repeat')
@templateController
@inject(BoundViewFactory, ViewSlot, ObserverLocator)
export class Repeat {
  /**
  * List of items to bind the repeater to
  *
  * @property items
  * @type {Array}
  */
  @bindable items
  @bindable local
  @bindable key
  @bindable value
  constructor(viewFactory, viewSlot, observerLocator){
    this.viewFactory = viewFactory;
    this.viewSlot = viewSlot;
    this.observerLocator = observerLocator;
    this.local = 'item';
    this.key = 'key';
    this.value = 'value';
  }

  bind(executionContext){
    var items = this.items,
      observer;

    this.executionContext = executionContext;

    if(!items){
      if(this.oldItems){
        this.viewSlot.removeAll();
      }

      return;
    }

    if (this.oldItems === items) {
      if (items instanceof Map) {
        var records = getChangeRecords(items);
        observer = this.observerLocator.getMapObserver(items);

        this.handleMapChangeRecords(items, records);

        this.disposeSubscription = observer.subscribe(records => {
          this.handleMapChangeRecords(items, records);
        });
      } else {
        var splices = calcSplices(items, 0, items.length, this.lastBoundItems, 0, this.lastBoundItems.length);
        observer = this.observerLocator.getArrayObserver(items);

        this.handleSplices(items, splices);
        this.lastBoundItems = this.oldItems = null;

        this.disposeSubscription = observer.subscribe(splices => {
          this.handleSplices(items, splices);
        });
      }
    } else {
      this.processItems();
    }
  }

  unbind(){
    this.oldItems = this.items;

    if(this.items instanceof Array){
      this.lastBoundItems = this.items.slice(0);
    }

    if(this.disposeSubscription){
      this.disposeSubscription();
      this.disposeSubscription = null;
    }
  }

  itemsChanged() {
    this.processItems();
  }

  processItems() {
    var items = this.items,
      viewSlot = this.viewSlot,
      views, i;

    if (this.disposeSubscription) {
      this.disposeSubscription();
      views = viewSlot.children;
      viewSlot.removeAll();
      i = views.length;
      while(i--) {
        views[i].unbind();
      }
    }

    if(!items){
      return;
    }

    if (items instanceof Array) {
      this.processArrayItems(items);
    } else if(items instanceof Map) {
      this.processMapEntries(items);
    } else if((typeof items === 'number')){
      this.processNumber(items);
    }else{
      throw new Error('Object in "repeat" must be of type Array, Map or Number');
    }
  }

  processArrayItems(items){
    var viewFactory = this.viewFactory,
      viewSlot = this.viewSlot,
      i, ii, row, view, observer;

    observer = this.observerLocator.getArrayObserver(items);

    for(i = 0, ii = items.length; i < ii; ++i){
      row = this.createFullExecutionContext(items[i], i, ii);
      view = viewFactory.create(row);
      viewSlot.add(view);
    }

    this.disposeSubscription = observer.subscribe(splices => {
      this.handleSplices(items, splices);
    });
  }

  processMapEntries(items) {
    var viewFactory = this.viewFactory,
      viewSlot = this.viewSlot,
      index = 0,
      row, view, observer;

    observer = this.observerLocator.getMapObserver(items);

    items.forEach((value, key) => {
      row = this.createFullExecutionKvpContext(key, value, index, items.size);
      view = viewFactory.create(row);
      viewSlot.add(view);
      ++index;
    });

    this.disposeSubscription = observer.subscribe(record => {
      this.handleMapChangeRecords(items, record);
    });
  }

  processNumber(value){
    var viewFactory = this.viewFactory,
      viewSlot = this.viewSlot,
      i, ii, row, view;

    for(i = 0, ii = Math.floor(value); i < ii; ++i){
      row = this.createFullExecutionContext(i, i, ii);
      view = viewFactory.create(row);
      viewSlot.add(view);
    }
  }

  createBaseExecutionContext(data){
    var context = {};
    context[this.local] = data;
    context.$parent = this.executionContext;
    return context;
  }

  createBaseExecutionKvpContext(key, value){
    var context = {};
    context[this.key] = key;
    context[this.value] = value;
    context.$parent = this.executionContext;
    return context;
  }

  createFullExecutionContext(data, index, length){
    var context = this.createBaseExecutionContext(data);
    return this.updateExecutionContext(context, index, length);
  }

  createFullExecutionKvpContext(key, value, index, length){
    var context = this.createBaseExecutionKvpContext(key, value);
    return this.updateExecutionContext(context, index, length);
  }

  updateExecutionContext(context, index, length){
    var first = (index === 0),
        last = (index === length - 1),
        even = index % 2 === 0;

    context.$index = index;
    context.$first = first;
    context.$last = last;
    context.$middle = !(first || last);
    context.$odd = !even;
    context.$even = even;

    return context;
  }

  handleSplices(array, splices) {
    var viewLookup = new Map(),
      viewSlot = this.viewSlot,
      spliceIndexLow, viewOrPromise, view,
      i, ii, j, jj, row, splice,
      addIndex, end, itemsLeftToAdd,
      removed, model, children, length;

    for (i = 0, ii = splices.length; i < ii; ++i) {
      splice = splices[i];
      addIndex = splice.index;
      itemsLeftToAdd = splice.addedCount;
      end = splice.index + splice.addedCount;
      removed = splice.removed;
      if(typeof spliceIndexLow === 'undefined' || spliceIndexLow === null || spliceIndexLow > splice.index){
        spliceIndexLow = splice.index;
      }

      for (j = 0, jj = removed.length; j < jj; ++j) {
        if (itemsLeftToAdd > 0) {
          view = viewSlot.children[splice.index + j];
          view.executionContext[this.local] = array[addIndex + j];
          --itemsLeftToAdd;
        } else {
          viewOrPromise = viewSlot.removeAt(addIndex + splice.addedCount);
          if(viewOrPromise){
            viewLookup.set(removed[j], viewOrPromise);
          }
        }
      }

      addIndex += removed.length;

      for (; 0 < itemsLeftToAdd; ++addIndex) {
        model = array[addIndex];
        viewOrPromise = viewLookup.get(model);
        if(viewOrPromise instanceof Promise){
          ((localAddIndex, localModel) => {
            viewOrPromise.then(view => {
              viewLookup.delete(localModel);
              viewSlot.insert(localAddIndex, view);
            });
          })(addIndex, model);
        }else if(viewOrPromise){
          viewLookup.delete(model);
          viewSlot.insert(addIndex, viewOrPromise);
        }else{
          row = this.createBaseExecutionContext(model);
          view = this.viewFactory.create(row);
          viewSlot.insert(addIndex, view);
        }
        --itemsLeftToAdd;
      }
    }

    children = this.viewSlot.children;
    length = children.length;

    if(spliceIndexLow > 0){
      spliceIndexLow = spliceIndexLow - 1;
    }

    for(; spliceIndexLow < length; ++spliceIndexLow){
      this.updateExecutionContext(children[spliceIndexLow].executionContext, spliceIndexLow, length);
    }

    viewLookup.forEach(x => {
      if(x instanceof Promise){
        x.then(y => y.unbind());
      }else{
        x.unbind();
      }
    });
  }

  handleMapChangeRecords(map, records) {
    var viewSlot = this.viewSlot,
      key, i, ii, view, children, length, row, removeIndex, record;

    for (i = 0, ii = records.length; i < ii; ++i) {
      record = records[i];
      key = record.key;
      switch (record.type) {
        case 'update':
          removeIndex = this.getViewIndexByKey(key);
          viewSlot.removeAt(removeIndex);
          row = this.createBaseExecutionKvpContext(key, map.get(key));
          view = this.viewFactory.create(row);
          viewSlot.insert(removeIndex, view);
          break;
        case 'add':
          row = this.createBaseExecutionKvpContext(key, map.get(key));
          view = this.viewFactory.create(row);
          viewSlot.insert(map.size, view);
          break;
        case 'delete':
          if (!record.oldValue) { return; }
          removeIndex = this.getViewIndexByKey(key);
          viewSlot.removeAt(removeIndex);
          break;
        case 'clear':
          viewSlot.removeAll();
      }
    }

    children = viewSlot.children;
    length = children.length;

    for (i = 0; i < length; i++) {
      this.updateExecutionContext(children[i].executionContext, i, length);
    }
  }

  getViewIndexByKey(key) {
    var viewSlot = this.viewSlot,
      i, ii, child;

    for (i = 0, ii = viewSlot.children.length; i < ii; ++i) { // TODO (martingust) better way to get index?
      child = viewSlot.children[i];
      if (child.bindings[0].source[this.key] === key) {
        return i;
      }
    }
  }
}
<|endoftext|>


<commit_before>var m = require('mithril');
var $ = require('jquery');
var $osf = require('js/osfHelpers');
var waterbutler = require('js/waterbutler');

var util = require('./util.js');

// Helper for filtering
function TRUTHY(item) {
    return !!item; //Force cast to a bool
}

var model = {
    revisions: [],
    loaded: m.prop(false),
    errorMessage: undefined,
    hasUser: false,
    hasDate: false,
    hasMd5: false,
    selectedRevision: 0
};

var FileRevisionsTable = {
    controller: function(file, node, enableEditing, canEdit) {
        var self = {};
        self.node = node;
        self.file = file;
        self.canEdit = canEdit;
        self.enableEditing = enableEditing;
        self.baseUrl = (window.location.href).split('?')[0];
        self.md5 = [];
        self.buttonToText = [];

        model.hasMd5 = self.file.provider === 'osfstorage';
        model.hasDate = self.file.provider !== 'dataverse';

        self.reload = function() {
            model.loaded(false);
            m.redraw();
            $.ajax({
                dataType: 'json',
                async: true,
                url: self.file.urls.revisions,
                beforeSend: $osf.setXHRAuthorization
            }).done(function(response) {
                m.startComputation();
                var urlParmas = $osf.urlParams();
                model.revisions = response.data.map(function(rev, index) {
                    rev = FileRevisionsTable.postProcessRevision(self.file, self.node, rev, index);
                    if (urlParmas[rev.versionIdentifier] === rev.version) {
                        model.selectedRevision = index;
                    }
                    return rev;
                });
                model.loaded(true);
                // Can only edit the latest version of a file
                if (model.selectedRevision === 0) {
                    self.enableEditing();
                }
                model.hasUser = model.revisions[0] && model.revisions[0].extra && model.revisions[0].extra.user;
                m.endComputation();
            }).fail(function(response) {
                m.startComputation();
                model.loaded(true);
                model.errorMessage = response.responseJSON ?
                    response.responseJSON.message || 'Unable to fetch versions' :
                    'Unable to fetch versions';
                m.endComputation();

                // model.errorMessage(err);

                if (self.file.provider === 'figshare') {
                    // Hack for Figshare
                    // only figshare will error on a revisions request
                    // so dont allow downloads and set a fake current version
                    $.ajax({
                        method: 'GET',
                        url: self.file.urls.metadata,
                        beforeSend: $osf.setXHRAuthorization
                    }).done(function(resp) {
                        self.canEdit(self.canEdit() && resp.data.extra.canDelete);
                        m.redraw();
                    }).fail(function(xhr) {
                        self.canEdit(false);
                        m.redraw();
                    });
                }
            });
        };

        self.getTableHead = function() {
            return m('thead', [
                m('tr', [
                    m('th', 'Version ID'),
                    model.hasDate ? m('th', 'Date') : false,
                    model.hasUser ? m('th', 'User') : false,
                    model.hasMd5 ? m('th', 'Hashes') : false,
                    m('th[colspan=2]', 'Download'),
                ].filter(TRUTHY))
            ]);
        };

        self.makeTableRow = function(revision, index) {
            var isSelected = index === model.selectedRevision;

            return m('tr' + (isSelected ? '.active' : ''), [
                m('td',  isSelected ? revision.displayVersion :
                  m('a', {href: parseInt(revision.displayVersion) === model.revisions.length ? self.baseUrl : revision.osfViewUrl}, revision.displayVersion)
                ),
                model.hasDate ? m('td', revision.displayDate) : false,
                model.hasUser ?
                    m('td', revision.extra.user.url ?
                            m('a', {href: revision.extra.user.url}, revision.extra.user.name) :
                            revision.extra.user.name
                    ) : false,
                model.hasMd5 ? m('td',
                    m( self.buttonToText[revision.displayVersion] || 'a.btn.btn-primary.btn-sm', {
                        style: {wordBreak: "break-all"},
                        onclick: function() {
                            if ((self.md5[revision.displayVersion] === 'MD5') ||
                                (typeof self.md5[revision.displayVersion] === 'undefined')){
                                self.md5[revision.displayVersion] = revision.displayMd5;
                                self.buttonToText[revision.displayVersion] = 'td';
                            } else {
                                self.md5[revision.displayVersion] = 'MD5';
                                self.buttonToText[revision.displayVersion] = 'a.btn.btn-primary.btn-sm';
                            }
                        },

                    }, m('td', self.md5[revision.displayVersion] || 'MD5') )) : false,
                m('td', revision.extra.downloads > -1 ? m('.badge', revision.extra.downloads) : ''),
                m('td',
                    m('a.btn.btn-primary.btn-sm.file-download', {
                        href: revision.osfDownloadUrl,
                        onclick: function() {
                            window.location = revision.waterbutlerDownloadUrl;
                            return false;
                        }
                    }, m('i.fa.fa-download'))
                ),
            ].filter(TRUTHY));
        };

        if (!model.loaded()) {
            self.reload();
        }
        $(document).on('fileviewpage:reload', self.reload);
        return self;
    },
    view: function(ctrl) {
        return m('#revisionsPanel.panel.panel-default', [
                m('.panel-heading.clearfix', m('h3.panel-title', 'Revisions')),
                m('.panel-body', {style:{'padding-right': '0px','padding-left':'0px'}}, (function() {
                    if (!model.loaded()) {
                        return util.Spinner;
                    }
                    if (model.errorMessage) {
                        return m('.alert.alert-warning', {style:{margin: '10px'}}, model.errorMessage);
                    }

                    return m('table.table', {style:{'table-layout': 'fixed'}}, [
                        ctrl.getTableHead(),
                        m('tbody', model.revisions.map(ctrl.makeTableRow))
                    ]);
                })())
            ]);
    },
    postProcessRevision: function(file, node, revision, index) {
        var options = {};
        var urlParams = $osf.urlParams();

        if (urlParams.branch !== undefined) {
            options.branch = urlParams.branch;
        }
        options[revision.versionIdentifier] = revision.version;

        revision.date = new $osf.FormattableDate(revision.modified);
        revision.displayDate = revision.date.local !== 'Invalid date' ?
            revision.date.local :
            revision.date;

        switch (file.provider) {
            // Note: Google Drive version identifiers often begin with the same sequence
            case 'googledrive':
                revision.displayVersion = revision.version.substring(revision.version.length - 8);
                break;
            // Note: Dataverse internal version names are ugly; Substitute our own
            case 'dataverse':
                var displayMap = {
                    'latest': 'Draft',
                    'latest-published': 'Published'
                };

                revision.displayVersion = revision.version in displayMap ?
                    displayMap[revision.version] : revision.version.substring(0, 8);
                break;
            default:
                revision.displayVersion = revision.version.substring(0, 8);
        }

        if (file.provider === 'osfstorage' && file.name && index !== 0) {
            var parts = file.name.split('.');
            if (parts.length === 1) {
                options.displayName = parts[0] + '-' + revision.modified;
            } else {
                options.displayName = parts.slice(0, parts.length - 1).join('') + '-' + revision.modified + '.' + parts[parts.length - 1];
            }
        }
        revision.displayMd5 = revision.extra.md5;

        revision.osfViewUrl = '?' + $.param(options);
        revision.osfDownloadUrl = '?' + $.param($.extend({action: 'download'}, options));
        revision.waterbutlerDownloadUrl = waterbutler.buildDownloadUrl(file.path, file.provider, node.id, options);

        return revision;
    }
};

module.exports = FileRevisionsTable;
<commit_msg>jshint is a poopface<commit_after>var m = require('mithril');
var $ = require('jquery');
var $osf = require('js/osfHelpers');
var waterbutler = require('js/waterbutler');

var util = require('./util.js');

// Helper for filtering
function TRUTHY(item) {
    return !!item; //Force cast to a bool
}

var model = {
    revisions: [],
    loaded: m.prop(false),
    errorMessage: undefined,
    hasUser: false,
    hasDate: false,
    hasMd5: false,
    selectedRevision: 0
};

var FileRevisionsTable = {
    controller: function(file, node, enableEditing, canEdit) {
        var self = {};
        self.node = node;
        self.file = file;
        self.canEdit = canEdit;
        self.enableEditing = enableEditing;
        self.baseUrl = (window.location.href).split('?')[0];
        self.md5 = [];
        self.buttonToText = [];

        model.hasMd5 = self.file.provider === 'osfstorage';
        model.hasDate = self.file.provider !== 'dataverse';

        self.reload = function() {
            model.loaded(false);
            m.redraw();
            $.ajax({
                dataType: 'json',
                async: true,
                url: self.file.urls.revisions,
                beforeSend: $osf.setXHRAuthorization
            }).done(function(response) {
                m.startComputation();
                var urlParmas = $osf.urlParams();
                model.revisions = response.data.map(function(rev, index) {
                    rev = FileRevisionsTable.postProcessRevision(self.file, self.node, rev, index);
                    if (urlParmas[rev.versionIdentifier] === rev.version) {
                        model.selectedRevision = index;
                    }
                    return rev;
                });
                model.loaded(true);
                // Can only edit the latest version of a file
                if (model.selectedRevision === 0) {
                    self.enableEditing();
                }
                model.hasUser = model.revisions[0] && model.revisions[0].extra && model.revisions[0].extra.user;
                m.endComputation();
            }).fail(function(response) {
                m.startComputation();
                model.loaded(true);
                model.errorMessage = response.responseJSON ?
                    response.responseJSON.message || 'Unable to fetch versions' :
                    'Unable to fetch versions';
                m.endComputation();

                // model.errorMessage(err);

                if (self.file.provider === 'figshare') {
                    // Hack for Figshare
                    // only figshare will error on a revisions request
                    // so dont allow downloads and set a fake current version
                    $.ajax({
                        method: 'GET',
                        url: self.file.urls.metadata,
                        beforeSend: $osf.setXHRAuthorization
                    }).done(function(resp) {
                        self.canEdit(self.canEdit() && resp.data.extra.canDelete);
                        m.redraw();
                    }).fail(function(xhr) {
                        self.canEdit(false);
                        m.redraw();
                    });
                }
            });
        };

        self.getTableHead = function() {
            return m('thead', [
                m('tr', [
                    m('th', 'Version ID'),
                    model.hasDate ? m('th', 'Date') : false,
                    model.hasUser ? m('th', 'User') : false,
                    model.hasMd5 ? m('th', 'Hashes') : false,
                    m('th[colspan=2]', 'Download'),
                ].filter(TRUTHY))
            ]);
        };

        self.makeTableRow = function(revision, index) {
            var isSelected = index === model.selectedRevision;

            return m('tr' + (isSelected ? '.active' : ''), [
                m('td',  isSelected ? revision.displayVersion :
                  m('a', {href: parseInt(revision.displayVersion) === model.revisions.length ? self.baseUrl : revision.osfViewUrl}, revision.displayVersion)
                ),
                model.hasDate ? m('td', revision.displayDate) : false,
                model.hasUser ?
                    m('td', revision.extra.user.url ?
                            m('a', {href: revision.extra.user.url}, revision.extra.user.name) :
                            revision.extra.user.name
                    ) : false,
                model.hasMd5 ? m('td',
                    m( self.buttonToText[revision.displayVersion] || 'a.btn.btn-primary.btn-sm', {
                        style: {wordBreak: 'break-all'},
                        onclick: function() {
                            if ((self.md5[revision.displayVersion] === 'MD5') ||
                                (typeof self.md5[revision.displayVersion] === 'undefined')){
                                self.md5[revision.displayVersion] = revision.displayMd5;
                                self.buttonToText[revision.displayVersion] = 'td';
                            } else {
                                self.md5[revision.displayVersion] = 'MD5';
                                self.buttonToText[revision.displayVersion] = 'a.btn.btn-primary.btn-sm';
                            }
                        },

                    }, m('td', self.md5[revision.displayVersion] || 'MD5') )) : false,
                m('td', revision.extra.downloads > -1 ? m('.badge', revision.extra.downloads) : ''),
                m('td',
                    m('a.btn.btn-primary.btn-sm.file-download', {
                        href: revision.osfDownloadUrl,
                        onclick: function() {
                            window.location = revision.waterbutlerDownloadUrl;
                            return false;
                        }
                    }, m('i.fa.fa-download'))
                ),
            ].filter(TRUTHY));
        };

        if (!model.loaded()) {
            self.reload();
        }
        $(document).on('fileviewpage:reload', self.reload);
        return self;
    },
    view: function(ctrl) {
        return m('#revisionsPanel.panel.panel-default', [
                m('.panel-heading.clearfix', m('h3.panel-title', 'Revisions')),
                m('.panel-body', {style:{'padding-right': '0px','padding-left':'0px'}}, (function() {
                    if (!model.loaded()) {
                        return util.Spinner;
                    }
                    if (model.errorMessage) {
                        return m('.alert.alert-warning', {style:{margin: '10px'}}, model.errorMessage);
                    }

                    return m('table.table', {style:{'table-layout': 'fixed'}}, [
                        ctrl.getTableHead(),
                        m('tbody', model.revisions.map(ctrl.makeTableRow))
                    ]);
                })())
            ]);
    },
    postProcessRevision: function(file, node, revision, index) {
        var options = {};
        var urlParams = $osf.urlParams();

        if (urlParams.branch !== undefined) {
            options.branch = urlParams.branch;
        }
        options[revision.versionIdentifier] = revision.version;

        revision.date = new $osf.FormattableDate(revision.modified);
        revision.displayDate = revision.date.local !== 'Invalid date' ?
            revision.date.local :
            revision.date;

        switch (file.provider) {
            // Note: Google Drive version identifiers often begin with the same sequence
            case 'googledrive':
                revision.displayVersion = revision.version.substring(revision.version.length - 8);
                break;
            // Note: Dataverse internal version names are ugly; Substitute our own
            case 'dataverse':
                var displayMap = {
                    'latest': 'Draft',
                    'latest-published': 'Published'
                };

                revision.displayVersion = revision.version in displayMap ?
                    displayMap[revision.version] : revision.version.substring(0, 8);
                break;
            default:
                revision.displayVersion = revision.version.substring(0, 8);
        }

        if (file.provider === 'osfstorage' && file.name && index !== 0) {
            var parts = file.name.split('.');
            if (parts.length === 1) {
                options.displayName = parts[0] + '-' + revision.modified;
            } else {
                options.displayName = parts.slice(0, parts.length - 1).join('') + '-' + revision.modified + '.' + parts[parts.length - 1];
            }
        }
        revision.displayMd5 = revision.extra.md5;

        revision.osfViewUrl = '?' + $.param(options);
        revision.osfDownloadUrl = '?' + $.param($.extend({action: 'download'}, options));
        revision.waterbutlerDownloadUrl = waterbutler.buildDownloadUrl(file.path, file.provider, node.id, options);

        return revision;
    }
};

module.exports = FileRevisionsTable;
<|endoftext|>


<commit_before>import { Terminal } from 'xterm';
import { AttachAddon } from 'xterm-addon-attach';
import { FitAddon } from 'xterm-addon-fit';
import { SearchAddon } from 'xterm-addon-search';
import { WebLinksAddon } from 'xterm-addon-web-links';

let term;
let searchAddon;
let fitAddon;
let protocol;
let socketURL;
let socket;
let pid;
let curFont;
let curTheme;
let alive;

let myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");

const terminalContainer = document.getElementById('terminal-container');
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
const lineEnd = isWindows ? '\r\n' : '\n';
const clearCmd = isWindows ? 'cls' : 'clear';

const closeEvent = new Event('terminalClose');
const promptEvent = new Event('promptReady');

function createTerminal(){
  // Clean terminal
  while (terminalContainer.children.length) {
      terminalContainer.removeChild(terminalContainer.children[0]);
  }

  term = new Terminal({
      cursorBlink: true,
      scrollback: 10000,
      tabStopWidth: 10,
      windowsMode: isWindows
      });

  term.loadAddon(new WebLinksAddon());
  searchAddon = new SearchAddon();
  term.loadAddon(searchAddon);
  fitAddon = new FitAddon();
  term.loadAddon(fitAddon);

  term.onResize((size) => {
      if (!pid) {
          return;
      }
      const cols = size.cols;
      const rows = size.rows;
      const url = '/api/terminals/' + pid + '/size?cols=' + cols + '&rows=' + rows;

      fetch(url, {method: 'POST', headers: myHeaders});
      term.setOption('theme', curTheme);
      term.setOption('fontFamily', curFont);
  });

  protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
  socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';

  term.open(terminalContainer);
  fitAddon.fit();
  term.focus();

  window.term = term

  let cols = term.cols;
  let rows = term.rows;

  fetch('/api/terminals?cols=' + cols + '&rows=' + rows, {
    method: 'POST',
    headers: myHeaders,
    credentials: 'include'
  }).then((res) => {
    let charWidth = Math.ceil(term.element.offsetWidth / cols);
    let charHeight = Math.ceil(term.element.offsetHeight / rows);
    res.text().then((pidf) => {
      pid = pidf;
      fitAddon.fit();
      window.pid = pid;
      socketURL += pid;
      socket = new WebSocket(socketURL);
      socket.onopen = runRealTerminal;
      socket.onclose = closeTerm;
      socket.onerror = closeTerm;
    });
  });
}

window.onresize = (event) => {
  fitAddon.fit();
}

function searchNext(regex) {
  if(searchAddon.findNext(regex)){
    return term.getSelectionPosition();
  }
  return -1;
}

function searchPrevious(regex) {
  if(searchAddon.findPrevious(regex)){
    return term.getSelectionPosition();
  }
  return -1;
}

function getFonts() {
  return term.getOption('fontFamily');
}

function setFont(font) {
    let fonts = "monospace";
    fonts = "'"+font+"', "+fonts;
    term.setOption('fontFamily', fonts);
}

function fitFont(font) {
  curFont = font;
  setFont(font);
  setFont('Ubuntu Mono');
  setFont(font);
}

function setcwd(cwd) {
  let path = cwd;
}

function getTerminalLines(){
  let text = '';
  for(let row = 0; row < term.rows; row++){
    let actLine = term.buffer.getLine(row);
    let length = actLine._line.length;
    text += actLine.translateToString(false, 0, length) + '';
  }
  return text;
}

function chdir(path) {
  socket.send('cd '+ path + lineEnd);
}

function clearTerm(){
  socket.send(clearCmd + lineEnd);
}

function exec(cmd){
  socket.send('' + cmd + lineEnd);
}

function closeTerm() {
  alive = false;
  window.dispatchEvent(closeEvent);
  console.log("Closed via server");
  term.writeln("Pipe closed");
}

function consoleReady() {
  return term._initialized
}

function scrollTerm(delta) {
  let viewport = document.getElementById('.xterm-viewport');
  let curScrollPos = viewport.scrollTop();
  let maxHeight = viewport.prop('scrollHeight') - viewport.innerHeight();
  curScrollPos = Math.min(maxHeight, Math.max(0, curScrollPos - delta));
  document.getElementById('.xterm-viewport').animate({ scrollTop: curScrollPos }, 0);
}

function isAlive() {
  return alive;
}

function setOption(option_name, option) {
  term.setOption(option_name, option);
  if(option_name === 'theme'){
    curTheme = option;
  }
}

function runRealTerminal() {
  term.loadAddon(new AttachAddon(socket));
  term._initialized = true;
  curFont = 'Ubuntu Mono';
  fitFont(curFont);
  alive = true;
  let timer = setInterval( () => {
    if(term !== undefined) {
      fitFont(curFont);
      window.dispatchEvent(promptEvent);
      clearInterval(timer);
    }
  }, 200);
}

function addDomListener(element, type, handler){
  element.addEventListener(type, handler);
  term._core.register({dispose: () => element.removeEventListener(type, handler)});
}

function addClassStyleToContainer(className){
  document.getElementById('terminal-container').classList.add(className);
}

$(document).ready( () => {
  createTerminal();
  new QWebChannel(qt.webChannelTransport, function (channel) {
    window.handler = channel.objects.handler;
    window.addEventListener('promptReady', function(e) {
      window.handler.ready();
    }, false);
    window.addEventListener('terminalClose', function(e) {
      window.handler.close();
    }, false);
  });
});

const term_functions = {
  fitFont: fitFont,
  getFonts: getFonts,
  setFont: setFont,
  setcwd: setcwd,
  chdir: chdir,
  clearTerm: clearTerm,
  exec: exec,
  closeTerm: closeTerm,
  consoleReady: consoleReady,
  scrollTerm: scrollTerm,
  isAlive: isAlive,
  getTerminalLines: getTerminalLines,
  searchNext: searchNext,
  searchPrevious: searchPrevious,
  setOption: setOption,
  addClassStyleToContainer: addClassStyleToContainer,
};

export default term_functions;<commit_msg>add compatibility update to new buffer api of xterm 4.5.0<commit_after>import { Terminal } from 'xterm';
import { AttachAddon } from 'xterm-addon-attach';
import { FitAddon } from 'xterm-addon-fit';
import { SearchAddon } from 'xterm-addon-search';
import { WebLinksAddon } from 'xterm-addon-web-links';

let term;
let searchAddon;
let fitAddon;
let protocol;
let socketURL;
let socket;
let pid;
let curFont;
let curTheme;
let alive;

let myHeaders = new Headers();
myHeaders.append("Content-Type", "application/x-www-form-urlencoded");

const terminalContainer = document.getElementById('terminal-container');
const isWindows = ['Windows', 'Win16', 'Win32', 'WinCE'].indexOf(navigator.platform) >= 0;
const lineEnd = isWindows ? '\r\n' : '\n';
const clearCmd = isWindows ? 'cls' : 'clear';

const closeEvent = new Event('terminalClose');
const promptEvent = new Event('promptReady');

function createTerminal(){
  // Clean terminal
  while (terminalContainer.children.length) {
      terminalContainer.removeChild(terminalContainer.children[0]);
  }

  term = new Terminal({
      cursorBlink: true,
      scrollback: 10000,
      tabStopWidth: 10,
      windowsMode: isWindows
      });

  term.loadAddon(new WebLinksAddon());
  searchAddon = new SearchAddon();
  term.loadAddon(searchAddon);
  fitAddon = new FitAddon();
  term.loadAddon(fitAddon);

  term.onResize((size) => {
      if (!pid) {
          return;
      }
      const cols = size.cols;
      const rows = size.rows;
      const url = '/api/terminals/' + pid + '/size?cols=' + cols + '&rows=' + rows;

      fetch(url, {method: 'POST', headers: myHeaders});
      term.setOption('theme', curTheme);
      term.setOption('fontFamily', curFont);
  });

  protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
  socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';

  term.open(terminalContainer);
  fitAddon.fit();
  term.focus();

  window.term = term

  let cols = term.cols;
  let rows = term.rows;

  fetch('/api/terminals?cols=' + cols + '&rows=' + rows, {
    method: 'POST',
    headers: myHeaders,
    credentials: 'include'
  }).then((res) => {
    let charWidth = Math.ceil(term.element.offsetWidth / cols);
    let charHeight = Math.ceil(term.element.offsetHeight / rows);
    res.text().then((pidf) => {
      pid = pidf;
      fitAddon.fit();
      window.pid = pid;
      socketURL += pid;
      socket = new WebSocket(socketURL);
      socket.onopen = runRealTerminal;
      socket.onclose = closeTerm;
      socket.onerror = closeTerm;
    });
  });
}

window.onresize = (event) => {
  fitAddon.fit();
}

function searchNext(regex) {
  if(searchAddon.findNext(regex)){
    return term.getSelectionPosition();
  }
  return -1;
}

function searchPrevious(regex) {
  if(searchAddon.findPrevious(regex)){
    return term.getSelectionPosition();
  }
  return -1;
}

function getFonts() {
  return term.getOption('fontFamily');
}

function setFont(font) {
    let fonts = "monospace";
    fonts = "'"+font+"', "+fonts;
    term.setOption('fontFamily', fonts);
}

function fitFont(font) {
  curFont = font;
  setFont(font);
  setFont('Ubuntu Mono');
  setFont(font);
}

function setcwd(cwd) {
  let path = cwd;
}

function getTerminalLines(){
  let text = '';
  for(let row = 0; row < term.rows; row++){
    let actLine = term.buffer.active.getLine(row);
    let length = actLine._line.length;
    text += actLine.translateToString(false, 0, length) + '';
  }
  return text;
}

function chdir(path) {
  socket.send('cd '+ path + lineEnd);
}

function clearTerm(){
  socket.send(clearCmd + lineEnd);
}

function exec(cmd){
  socket.send('' + cmd + lineEnd);
}

function closeTerm() {
  alive = false;
  window.dispatchEvent(closeEvent);
  console.log("Closed via server");
  term.writeln("Pipe closed");
}

function consoleReady() {
  return term._initialized
}

function scrollTerm(delta) {
  let viewport = document.getElementById('.xterm-viewport');
  let curScrollPos = viewport.scrollTop();
  let maxHeight = viewport.prop('scrollHeight') - viewport.innerHeight();
  curScrollPos = Math.min(maxHeight, Math.max(0, curScrollPos - delta));
  document.getElementById('.xterm-viewport').animate({ scrollTop: curScrollPos }, 0);
}

function isAlive() {
  return alive;
}

function setOption(option_name, option) {
  term.setOption(option_name, option);
  if(option_name === 'theme'){
    curTheme = option;
  }
}

function runRealTerminal() {
  term.loadAddon(new AttachAddon(socket));
  term._initialized = true;
  curFont = 'Ubuntu Mono';
  fitFont(curFont);
  alive = true;
  let timer = setInterval( () => {
    if(term !== undefined) {
      fitFont(curFont);
      window.dispatchEvent(promptEvent);
      clearInterval(timer);
    }
  }, 200);
}

function addDomListener(element, type, handler){
  element.addEventListener(type, handler);
  term._core.register({dispose: () => element.removeEventListener(type, handler)});
}

function addClassStyleToContainer(className){
  document.getElementById('terminal-container').classList.add(className);
}

$(document).ready( () => {
  createTerminal();
  new QWebChannel(qt.webChannelTransport, function (channel) {
    window.handler = channel.objects.handler;
    window.addEventListener('promptReady', function(e) {
      window.handler.ready();
    }, false);
    window.addEventListener('terminalClose', function(e) {
      window.handler.close();
    }, false);
  });
});

const term_functions = {
  fitFont: fitFont,
  getFonts: getFonts,
  setFont: setFont,
  setcwd: setcwd,
  chdir: chdir,
  clearTerm: clearTerm,
  exec: exec,
  closeTerm: closeTerm,
  consoleReady: consoleReady,
  scrollTerm: scrollTerm,
  isAlive: isAlive,
  getTerminalLines: getTerminalLines,
  searchNext: searchNext,
  searchPrevious: searchPrevious,
  setOption: setOption,
  addClassStyleToContainer: addClassStyleToContainer,
};

export default term_functions;<|endoftext|>


<commit_before>import Ember from 'ember';
import {
  module,
  test
} from 'qunit';
import Pretender from 'pretender';
import startApp from 'dummy/tests/helpers/start-app';

var application;
var store;
var server;

var posts = [
  {
    id: 1,
    post_title: 'post title 1',
    body: 'post body 1',
    comments: []
  },
  {
    id: 2,
    post_title: 'post title 2',
    body: 'post body 2',
    comments: []
  },
  {
    id: 3,
    post_title: 'post title 3',
    body: 'post body 3',
    comments: []
  }
];

module('Acceptance: CRUD Success', {
  beforeEach: function() {
    application = startApp();

    store = application.__container__.lookup('store:main');

    server = new Pretender(function() {

      // Retrieve list of non-paginated records
      this.get('/test-api/posts/', function(request) {
        if (request.queryParams.post_title === 'post title 2') {
          return [200, {'Content-Type': 'application/json'}, JSON.stringify([posts[1]])];
        } else {
          return [200, {'Content-Type': 'application/json'}, JSON.stringify(posts)];
        }
      });

      // Retrieve single record
      this.get('/test-api/posts/1/', function(request) {
        return [200, {'Content-Type': 'application/json'}, JSON.stringify(posts[0])];
      });

      // Create record
      this.post('/test-api/posts/', function(request) {
        var data = Ember.$.parseJSON(request.requestBody);
        data['id'] = 4;
        return [201, {'Content-Type': 'application/json'}, JSON.stringify(data)];
      });

      // Update record
      this.put('/test-api/posts/1/', function(request) {
        var data = Ember.merge(posts[0], Ember.$.parseJSON(request.requestBody));
        return [200, {'Content-Type': 'application/json'}, JSON.stringify(data)];
      });

      // Delete record
      this.delete('/test-api/posts/1/', function(request) {
        return [204];
      });
    });
  },

  afterEach: function() {
    Ember.run(application, 'destroy');
    server.shutdown();
  }
});

test('Retrieve list of non-paginated records', function(assert) {
  assert.expect(4);

  return store.findAll('post').then(function(posts) {

    assert.ok(posts);
    assert.equal(posts.get('length'), 3);

    var post = posts.objectAt(2);

    assert.equal(post.get('postTitle'), 'post title 3');
    assert.equal(post.get('body'), 'post body 3');
  });
});

test('Retrieve single record', function(assert) {
  assert.expect(3);

  return Ember.run(function() {

    return store.findRecord('post', 1).then(function(post) {

      assert.ok(post);
      assert.equal(post.get('postTitle'), 'post title 1');
      assert.equal(post.get('body'), 'post body 1');
    });
  });
});

test('Retrieve via query', function(assert) {
  assert.expect(3);

  return Ember.run(function() {

    return store.query('post', {post_title: 'post title 2'}).then(function(post) {

      assert.ok(post);

      post = post.objectAt(0);
      assert.equal(post.get('postTitle'), 'post title 2');
      assert.equal(post.get('body'), 'post body 2');
    });
  });
});

test('Create record', function(assert) {
  assert.expect(4);

  return Ember.run(function() {

    var post = store.createRecord('post', {
      postTitle: 'my new post title',
      body: 'my new post body'
    });

    return post.save().then(function(post) {

      assert.ok(post);
      assert.equal(post.get('id'), 4);
      assert.equal(post.get('postTitle'), 'my new post title');
      assert.equal(post.get('body'), 'my new post body');
    });
  });
});

test('Update record', function(assert) {
  assert.expect(7);

  return Ember.run(function() {

    return store.findRecord('post', 1).then(function(post) {

      assert.ok(post);
      assert.equal(post.get('isDirty'), false);

      return Ember.run(function() {

        post.set('postTitle', 'new post title');
        post.set('body', 'new post body');
        assert.equal(post.get('isDirty'), true);

        return post.save().then(function(post) {

          assert.ok(post);
          assert.equal(post.get('isDirty'), false);
          assert.equal(post.get('postTitle'), 'new post title');
          assert.equal(post.get('body'), 'new post body');
        });
      });
    });
  });
});

test('Delete record', function(assert) {
  assert.expect(2);

  return Ember.run(function() {

    return store.findRecord('post', 1).then(function(post) {

      assert.ok(post);

      return post.destroyRecord().then(function(post) {

        assert.ok(post);
      });
    });
  });
});
<commit_msg>Update create record test in crud-success-test.js to check that id field is correctly sent in save request<commit_after>import Ember from 'ember';
import {
  module,
  test
} from 'qunit';
import Pretender from 'pretender';
import startApp from 'dummy/tests/helpers/start-app';

var application;
var store;
var server;

var posts = [
  {
    id: 1,
    post_title: 'post title 1',
    body: 'post body 1',
    comments: []
  },
  {
    id: 2,
    post_title: 'post title 2',
    body: 'post body 2',
    comments: []
  },
  {
    id: 3,
    post_title: 'post title 3',
    body: 'post body 3',
    comments: []
  }
];

module('Acceptance: CRUD Success', {
  beforeEach: function() {
    application = startApp();

    store = application.__container__.lookup('store:main');

    server = new Pretender(function() {

      // Retrieve list of non-paginated records
      this.get('/test-api/posts/', function(request) {
        if (request.queryParams.post_title === 'post title 2') {
          return [200, {'Content-Type': 'application/json'}, JSON.stringify([posts[1]])];
        } else {
          return [200, {'Content-Type': 'application/json'}, JSON.stringify(posts)];
        }
      });

      // Retrieve single record
      this.get('/test-api/posts/1/', function(request) {
        return [200, {'Content-Type': 'application/json'}, JSON.stringify(posts[0])];
      });

      // Create record
      this.post('/test-api/posts/', function(request) {
        var data = Ember.$.parseJSON(request.requestBody);
        return [201, {'Content-Type': 'application/json'}, JSON.stringify(data)];
      });

      // Update record
      this.put('/test-api/posts/1/', function(request) {
        var data = Ember.merge(posts[0], Ember.$.parseJSON(request.requestBody));
        return [200, {'Content-Type': 'application/json'}, JSON.stringify(data)];
      });

      // Delete record
      this.delete('/test-api/posts/1/', function(request) {
        return [204];
      });
    });
  },

  afterEach: function() {
    Ember.run(application, 'destroy');
    server.shutdown();
  }
});

test('Retrieve list of non-paginated records', function(assert) {
  assert.expect(4);

  return store.findAll('post').then(function(posts) {

    assert.ok(posts);
    assert.equal(posts.get('length'), 3);

    var post = posts.objectAt(2);

    assert.equal(post.get('postTitle'), 'post title 3');
    assert.equal(post.get('body'), 'post body 3');
  });
});

test('Retrieve single record', function(assert) {
  assert.expect(3);

  return Ember.run(function() {

    return store.findRecord('post', 1).then(function(post) {

      assert.ok(post);
      assert.equal(post.get('postTitle'), 'post title 1');
      assert.equal(post.get('body'), 'post body 1');
    });
  });
});

test('Retrieve via query', function(assert) {
  assert.expect(3);

  return Ember.run(function() {

    return store.query('post', {post_title: 'post title 2'}).then(function(post) {

      assert.ok(post);

      post = post.objectAt(0);
      assert.equal(post.get('postTitle'), 'post title 2');
      assert.equal(post.get('body'), 'post body 2');
    });
  });
});

test('Create record', function(assert) {
  assert.expect(5);

  return Ember.run(function() {

    var post = store.createRecord('post', {
      id: 4,
      postTitle: 'my new post title',
      body: 'my new post body'
    });

    return post.save().then(function(post) {

      assert.ok(post);
      assert.equal(post.get('id'), 4);
      assert.equal(post.get('postTitle'), 'my new post title');
      assert.equal(post.get('body'), 'my new post body');

      var requestBody = (JSON.parse(server.handledRequests.pop().requestBody));
      assert.equal(requestBody.id, 4);

    });
  });
});

test('Update record', function(assert) {
  assert.expect(7);

  return Ember.run(function() {

    return store.findRecord('post', 1).then(function(post) {

      assert.ok(post);
      assert.equal(post.get('isDirty'), false);

      return Ember.run(function() {

        post.set('postTitle', 'new post title');
        post.set('body', 'new post body');
        assert.equal(post.get('isDirty'), true);

        return post.save().then(function(post) {

          assert.ok(post);
          assert.equal(post.get('isDirty'), false);
          assert.equal(post.get('postTitle'), 'new post title');
          assert.equal(post.get('body'), 'new post body');
        });
      });
    });
  });
});

test('Delete record', function(assert) {
  assert.expect(2);

  return Ember.run(function() {

    return store.findRecord('post', 1).then(function(post) {

      assert.ok(post);

      return post.destroyRecord().then(function(post) {

        assert.ok(post);
      });
    });
  });
});
<|endoftext|>