<commit_before>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013, 2014, 2015 School of Business and Engineering Vaud, Comem
 * Licensed under the MIT License
 */

/**
 *
 * @fileoverview
 * @author Cyril Junod <cyril.junod at gmail.com>
 */
/*global YUI*/
YUI.add("wegas-entitychooser", function(Y) {
    "use strict";
    var CONTENTBOX = "contentBox", EntityChooser, EntityChooser2,
        CLASSES = {
            CHOOSEN: "chooser-choosen"
        };

    EntityChooser = Y.Base.create("wegas-entitychooser",
        Y.Widget,
        [Y.WidgetChild,
            Y.Wegas.Widget,
            Y.Wegas.Editable],
        {
            CONTENT_TEMPLATE: "

",
            initializer: function() {
                this._handlers = [];
                /**
                 * hold a ref to the currently selected name
                 */
                this.currentTarget = null;
            },
            syncUI: function() {
                var items = (this.get("variable.evaluated") ?
                    (this.get("flatten") ?
                        this.get("variable.evaluated").flatten() :
                        this.get("variable.evaluated").get("items")) :
                    []),
                    i, tmp,
                    entityBox = this.get(CONTENTBOX).one(".chooser-entities"),
                    length = items.length,
                    filter = [];

                entityBox.empty();
                if (this.get("classFilter")) {
                    if (!Y.Lang.isArray(this.get("classFilter"))) {
                        filter.push(this.get("classFilter"));
                    } else {
                        filter = filter.concat(this.get("classFilter"));
                    }
                }

                for (i = 0; i < length; i += 1) {
                    if (filter.length === 0 || Y.Array.find(filter, function(item) {
                        return item === items[i].get("@class");
                    })) {
                        if ((!items[i].getInstance().getAttrs().hasOwnProperty("active") ||
                            items[i].getInstance().get("active")) &&
                            (!items[i].getInstance().getAttrs().hasOwnProperty("enabled") ||
                                items[i].getInstance().get("enabled"))) {
                            entityBox.append("
" +
                                (items[i].get("title") || items[i].get("label")) + "
");
                        }
                    }
                }
                if (this.currentTarget) {
                    tmp = entityBox.all("[data-name='" + this.currentTarget + "']");
                    tmp.addClass(CLASSES.CHOOSEN);
                    if (!tmp.size()) { //current target exists but is not rendered anymore
                        Y.later(200, this, function() {
                            this.widget.destroy();
                            this.widget = null;
                        });
                        this.currentTarget = null;
                    }
                }
            },
            bindUI: function() {
                this.get(CONTENTBOX).delegate("click", function(e) {
                    var targetName = e.target.getData("name");
                    if (this.currentTarget === targetName) { // I'm the choosen one
                        return;
                    }
                    this.genWidget(targetName);
                    this.get(CONTENTBOX).all("." + CLASSES.CHOOSEN).removeClass(CLASSES.CHOOSEN);
                    e.target.addClass(CLASSES.CHOOSEN);
                    this.currentTarget = targetName;
                }, ".chooser-entities .chooser-entity", this);
                this._handlers.push(Y.Wegas.Facade.Variable.after("update", this.syncUI, this));
            },
            genWidget: function(name) {
                var cfg = this.get("widget"),
                    ctx = this;
                Y.Wegas.Editable.use(cfg, function(Y) {
                    if (ctx.widget) {
                        ctx.widget.set(ctx.get("widgetAttr"), {
                            name: name
                        });
                    } else {
                        cfg[ctx.get("widgetAttr")] = {
                            name: name
                        };
                        Y.Wegas.use(cfg, Y.bind(function() {
                            this.widget = Y.Wegas.Widget.create(cfg);
                            this.widget.render(this.get(CONTENTBOX).one(".chooser-widget"));
                            this.widget.on(["*:message", "*:showOverlay", "*:hideOverlay"], this.fire, this); // Event on the loaded
                        }, ctx));
                    }
                });
            },
            destructor: function() {
                this.widget && this.widget.destroy();
                Y.Array.each(this._handlers, function(handle) {
                    handle.detach();
                });
            }

        },
        {
            ATTRS: {
                variable: {
                    getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                    _inputex: {
                        _type: "variableselect",
                        label: "Folder",
                        classFilter: ["ListDescriptor"]
                    }
                },
                widget: {
                    value: {
                        type: "HistoryDialog"
                    },
                    getter: function(v) {
                        return Y.JSON.parse(Y.JSON.stringify(v));
                    },
                    _inputex: {
                        _type: "group",
                        fields: [{
                                type: "string",
                                name: "type",
                                label: "Type"
                            }]
                    }
                },
                widgetAttr: {
                    value: "dialogueVariable",
                    type: "string"
                },
                flatten: {
                    type: "boolean",
                    value: "true"
                },
                classFilter: {
                    type: "array",
                    _inputex: {
                        elementType: {
                            required: true,
                            type: "select",
                            choices: Y.Wegas.persistence.AVAILABLE_TYPES
                        }
                    }
                }
            }
        });
    Y.Wegas.EntityChooser = EntityChooser;

    EntityChooser2 = Y.Base.create("wegas-entitychooser2",
        Y.Widget,
        [Y.WidgetChild,
            Y.Wegas.Widget,
            Y.Wegas.Editable],
        {
            CONTENT_TEMPLATE: "

",
            initializer: function() {
                this._handlers = [];
                /**
                 * hold a ref to the currently selected name
                 */
                this.currentTarget = null;
            },
            syncUI: function() {
                var items = (this.get("variable.evaluated") ? (this.get("flatten") ? this.get("variable.evaluated").flatten() : this.get("variable.evaluated").get("items")) : []),
                    i, tmp, li,
                    entityBox = this.get(CONTENTBOX).one(".chooser-entities"),
                    length = items.length,
                    filter = Y.Object.keys(this.get("widgets"));
                entityBox.empty();
                for (i = 0; i < length; i += 1) {
                    if (Y.Array.find(filter, function(item) {
                        return item === items[i].get("@class");
                    })) {
                        if ((!items[i].getInstance().getAttrs().hasOwnProperty("active") ||
                            items[i].getInstance().get("active")) &&
                            (!items[i].getInstance().getAttrs().hasOwnProperty("enabled") ||
                                items[i].getInstance().get("enabled"))) {
                            li = entityBox.appendChild("
" +
                                (items[i].get("title") || items[i].get("label")) + "
");
                            if (this.get("markUnread")) {
                                li.plug(Y.Plugin.MarkAsUnread, {
                                    userCounters: {"ObjectDescriptor": "function(descriptor, instance, resolve) {resolve ((descriptor.get(\"label\") === \"points\" && instance.get(\"properties.maxPoints\") && !instance.get(\"properties.submitted\") ? 1 : 0)); }"},
                                    variable: {
                                        name: items[i].get("name")
                                    }
                                });
                                li.MarkAsUnread.updateCounter();
                            }
                        }
                    }
                }
                if (this.currentTarget) {
                    tmp = entityBox.all("[data-name='" + this.currentTarget + "']");
                    tmp.addClass(CLASSES.CHOOSEN);
                    if (!tmp.size()) { //current target exists but is not rendered anymore
                        Y.later(200, this, function() {
                            this._currentWidget.destroy();
                            this._currentWidget = null;
                            this._currentWidgetType = null;
                        });
                        this.currentTarget = null;
                    }
                }
            },
            bindUI: function() {
                this.get(CONTENTBOX).delegate("click", function(e) {
                    var targetName = e.target.getData("name");
                    if (this.currentTarget === targetName) { // I'm the choosen one
                        return;
                    }
                    this.genWidget(e.target.getData("type"), targetName);
                    this.get(CONTENTBOX).all("." + CLASSES.CHOOSEN).removeClass(CLASSES.CHOOSEN);
                    e.target.addClass(CLASSES.CHOOSEN);
                    this.currentTarget = targetName;
                }, ".chooser-entities .chooser-entity", this);
                this._handlers.push(Y.Wegas.Facade.Variable.after("update", this.syncUI, this));
            },
            genWidget: function(type, name) {
                var widgetConfig = this.get("widgets")[type],
                    ctx = this, cfg;
                cfg = widgetConfig.widget;

                Y.Wegas.Editable.use(cfg, function(Y) {
                    if (ctx._currentWidgetType === type) {
                        ctx._currentWidget.set(widgetConfig.widgetAttr, {
                            name: name
                        });
                    } else {
                        cfg[widgetConfig.widgetAttr] = {
                            name: name
                        };
                        Y.Wegas.use(cfg, Y.bind(function() {
                            this._currentWidget && this._currentWidget.destroy();

                            this._currentWidgetType = type;
                            this._currentWidget = Y.Wegas.Widget.create(cfg);
                            this._currentWidget.render(this.get(CONTENTBOX).one(".chooser-widget"));
                            // propagates selected event to the "parent"
                            this._currentWidget.on(["*:message", "*:showOverlay", "*:hideOverlay"], this.fire, this);
                        }, ctx));
                    }
                });
            },
            destructor: function() {
                this._currentWidget && this._currentWidget.destroy();
                Y.Array.each(this._handlers, function(handle) {
                    handle.detach();
                });
            }
        },
        {
            ATTRS: {
                variable: {
                    getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                    _inputex: {
                        _type: "variableselect",
                        legend: "Folder",
                        classFilter: ["ListDescriptor"]
                    }
                },
                widgets: {
                    optional: false,
                    _inputex: {
                        _type: "hashlist",
                        keyField: "dataType",
                        valueField: "config",
                        elementType: {
                            type: "combine",
                            fields: [{
                                    name: "dataType",
                                    type: "select",
                                    value: "DialogueDescriptor",
                                    choices: Y.Wegas.persistence.AVAILABLE_TYPES
                                }, {
                                    name: "config",
                                    type: "group",
                                    fields: [{
                                            name: "widget",
                                            type: "group",
                                            value: {
                                                type: "HistoryDialogue"
                                            },
                                            fields: [{
                                                    type: "string",
                                                    name: "type",
                                                    label: "Type"
                                                }]
                                        }, {
                                            name: "widgetAttr",
                                            value: "dialogueVariable",
                                            type: "string"
                                        }]
                                }
                            ]
                        }
                    }
                },
                markUnread: {
                    type: "boolean",
                    value: false
                },
                userCounters: {
                    type: "object",
                    value: {},
                    optional: true,
                    _inputex: {
                        type: "hidden"
                    }
                },
                flatten: {
                    type: "boolean",
                    value: "true"
                }
            }
        });
    Y.Wegas.EntityChooser2 = EntityChooser2;

});
<commit_msg>EntityChooser<commit_after>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013, 2014, 2015 School of Business and Engineering Vaud, Comem
 * Licensed under the MIT License
 */

/**
 *
 * @fileoverview
 * @author Cyril Junod <cyril.junod at gmail.com>
 */
/*global YUI*/
YUI.add("wegas-entitychooser", function(Y) {
    "use strict";
    var CONTENTBOX = "contentBox", EntityChooser, EntityChooser2,
        CLASSES = {
            CHOOSEN: "chooser-choosen"
        };

    EntityChooser = Y.Base.create("wegas-entitychooser",
        Y.Widget,
        [Y.WidgetChild,
            Y.Wegas.Widget,
            Y.Wegas.Editable],
        {
            CONTENT_TEMPLATE: "

",
            initializer: function() {
                this._handlers = [];
                /**
                 * hold a ref to the currently selected name
                 */
                this.currentTarget = null;
            },
            syncUI: function() {
                var items = (this.get("variable.evaluated") ?
                    (this.get("flatten") ?
                        this.get("variable.evaluated").flatten() :
                        this.get("variable.evaluated").get("items")) :
                    []),
                    i, tmp,
                    entityBox = this.get(CONTENTBOX).one(".chooser-entities"),
                    length = items.length,
                    filter = [];

                entityBox.empty();
                if (this.get("classFilter")) {
                    if (!Y.Lang.isArray(this.get("classFilter"))) {
                        filter.push(this.get("classFilter"));
                    } else {
                        filter = filter.concat(this.get("classFilter"));
                    }
                }

                for (i = 0; i < length; i += 1) {
                    if (filter.length === 0 || Y.Array.find(filter, function(item) {
                        return item === items[i].get("@class");
                    })) {
                        if ((!items[i].getInstance().getAttrs().hasOwnProperty("active") ||
                            items[i].getInstance().get("active")) &&
                            (!items[i].getInstance().getAttrs().hasOwnProperty("enabled") ||
                                items[i].getInstance().get("enabled"))) {
                            entityBox.append("
" +
                                (items[i].get("title") || items[i].get("label")) + "
");
                        }
                    }
                }
                if (this.currentTarget) {
                    tmp = entityBox.all("[data-name='" + this.currentTarget + "']");
                    tmp.addClass(CLASSES.CHOOSEN);
                    if (!tmp.size()) { //current target exists but is not rendered anymore
                        Y.later(200, this, function() {
                            this.widget.destroy();
                            this.widget = null;
                        });
                        this.currentTarget = null;
                    }
                }
            },
            bindUI: function() {
                this.get(CONTENTBOX).delegate("click", function(e) {
                    var targetName = e.target.getData("name");
                    if (this.currentTarget === targetName) { // I'm the choosen one
                        return;
                    }
                    this.genWidget(targetName);
                    this.get(CONTENTBOX).all("." + CLASSES.CHOOSEN).removeClass(CLASSES.CHOOSEN);
                    e.target.addClass(CLASSES.CHOOSEN);
                    this.currentTarget = targetName;
                }, ".chooser-entities .chooser-entity", this);
                this._handlers.push(Y.Wegas.Facade.Variable.after("update", this.syncUI, this));
            },
            genWidget: function(name) {
                var cfg = this.get("widget"),
                    ctx = this;
                Y.Wegas.Editable.use(cfg, function(Y) {
                    if (ctx.widget) {
                        ctx.widget.set(ctx.get("widgetAttr"), {
                            name: name
                        });
                    } else {
                        cfg[ctx.get("widgetAttr")] = {
                            name: name
                        };
                        Y.Wegas.use(cfg, Y.bind(function() {
                            this.widget = Y.Wegas.Widget.create(cfg);
                            this.widget.render(this.get(CONTENTBOX).one(".chooser-widget"));
                            this.widget.on(["*:message", "*:showOverlay", "*:hideOverlay"], this.fire, this); // Event on the loaded
                        }, ctx));
                    }
                });
            },
            destructor: function() {
                this.widget && this.widget.destroy();
                Y.Array.each(this._handlers, function(handle) {
                    handle.detach();
                });
            }

        },
        {
            ATTRS: {
                variable: {
                    getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                    _inputex: {
                        _type: "variableselect",
                        label: "Folder",
                        classFilter: ["ListDescriptor"]
                    }
                },
                widget: {
                    value: {
                        type: "HistoryDialog"
                    },
                    getter: function(v) {
                        return Y.JSON.parse(Y.JSON.stringify(v));
                    },
                    _inputex: {
                        _type: "group",
                        fields: [{
                                type: "string",
                                name: "type",
                                label: "Type"
                            }]
                    }
                },
                widgetAttr: {
                    value: "dialogueVariable",
                    type: "string"
                },
                flatten: {
                    type: "boolean",
                    value: "true"
                },
                classFilter: {
                    type: "array",
                    _inputex: {
                        elementType: {
                            required: true,
                            type: "select",
                            choices: Y.Wegas.persistence.AVAILABLE_TYPES
                        }
                    }
                }
            }
        });
    Y.Wegas.EntityChooser = EntityChooser;

    EntityChooser2 = Y.Base.create("wegas-entitychooser2",
        Y.Widget,
        [Y.WidgetChild,
            Y.Wegas.Widget,
            Y.Wegas.Editable],
        {
            CONTENT_TEMPLATE: "

",
            initializer: function() {
                this._handlers = [];
                /**
                 * hold a ref to the currently selected name
                 */
                this.currentTarget = null;
            },
            syncUI: function() {
                var items = (this.get("variable.evaluated") ? (this.get("flatten") ? this.get("variable.evaluated").flatten() : this.get("variable.evaluated").get("items")) : []),
                    i, tmp, li,
                    entityBox = this.get(CONTENTBOX).one(".chooser-entities"),
                    length = items.length,
                    filter = Y.Object.keys(this.get("widgets"));
                entityBox.empty();
                for (i = 0; i < length; i += 1) {
                    if (Y.Array.find(filter, function(item) {
                        return item === items[i].get("@class");
                    })) {
                        if ((!items[i].getInstance().getAttrs().hasOwnProperty("active") ||
                            items[i].getInstance().get("active")) &&
                            (!items[i].getInstance().getAttrs().hasOwnProperty("enabled") ||
                                items[i].getInstance().get("enabled"))) {
                            li = entityBox.appendChild("
" +
                                (items[i].get("title") || items[i].get("label")) + "
");
                            if (this.get("markUnread")) {
                                li.plug(Y.Plugin.MarkAsUnread, {
                                    userCounters: this.get("userCounters"),
                                    variable: {
                                        name: items[i].get("name")
                                    }
                                });
                                li.MarkAsUnread.updateCounter();
                            }
                        }
                    }
                }
                if (this.currentTarget) {
                    tmp = entityBox.all("[data-name='" + this.currentTarget + "']");
                    tmp.addClass(CLASSES.CHOOSEN);
                    if (!tmp.size()) { //current target exists but is not rendered anymore
                        Y.later(200, this, function() {
                            this._currentWidget.destroy();
                            this._currentWidget = null;
                            this._currentWidgetType = null;
                        });
                        this.currentTarget = null;
                    }
                }
            },
            bindUI: function() {
                this.get(CONTENTBOX).delegate("click", function(e) {
                    var targetName = e.target.getData("name");
                    if (this.currentTarget === targetName) { // I'm the choosen one
                        return;
                    }
                    this.genWidget(e.target.getData("type"), targetName);
                    this.get(CONTENTBOX).all("." + CLASSES.CHOOSEN).removeClass(CLASSES.CHOOSEN);
                    e.target.addClass(CLASSES.CHOOSEN);
                    this.currentTarget = targetName;
                }, ".chooser-entities .chooser-entity", this);
                this._handlers.push(Y.Wegas.Facade.Variable.after("update", this.syncUI, this));
            },
            genWidget: function(type, name) {
                var widgetConfig = this.get("widgets")[type],
                    ctx = this, cfg;
                cfg = widgetConfig.widget;

                Y.Wegas.Editable.use(cfg, function(Y) {
                    if (ctx._currentWidgetType === type) {
                        ctx._currentWidget.set(widgetConfig.widgetAttr, {
                            name: name
                        });
                    } else {
                        cfg[widgetConfig.widgetAttr] = {
                            name: name
                        };
                        Y.Wegas.use(cfg, Y.bind(function() {
                            this._currentWidget && this._currentWidget.destroy();

                            this._currentWidgetType = type;
                            this._currentWidget = Y.Wegas.Widget.create(cfg);
                            this._currentWidget.render(this.get(CONTENTBOX).one(".chooser-widget"));
                            // propagates selected event to the "parent"
                            this._currentWidget.on(["*:message", "*:showOverlay", "*:hideOverlay"], this.fire, this);
                        }, ctx));
                    }
                });
            },
            destructor: function() {
                this._currentWidget && this._currentWidget.destroy();
                Y.Array.each(this._handlers, function(handle) {
                    handle.detach();
                });
            }
        },
        {
            ATTRS: {
                variable: {
                    getter: Y.Wegas.Widget.VARIABLEDESCRIPTORGETTER,
                    _inputex: {
                        _type: "variableselect",
                        legend: "Folder",
                        classFilter: ["ListDescriptor"]
                    }
                },
                widgets: {
                    optional: false,
                    _inputex: {
                        _type: "hashlist",
                        keyField: "dataType",
                        valueField: "config",
                        elementType: {
                            type: "combine",
                            fields: [{
                                    name: "dataType",
                                    type: "select",
                                    value: "DialogueDescriptor",
                                    choices: Y.Wegas.persistence.AVAILABLE_TYPES
                                }, {
                                    name: "config",
                                    type: "group",
                                    fields: [{
                                            name: "widget",
                                            type: "group",
                                            value: {
                                                type: "HistoryDialogue"
                                            },
                                            fields: [{
                                                    type: "string",
                                                    name: "type",
                                                    label: "Type"
                                                }]
                                        }, {
                                            name: "widgetAttr",
                                            value: "dialogueVariable",
                                            type: "string"
                                        }]
                                }
                            ]
                        }
                    }
                },
                markUnread: {
                    type: "boolean",
                    value: false
                },
                userCounters: {
                    type: "object",
                    value: {},
                    optional: true,
                    _inputex: {
                        type: "hidden"
                    }
                },
                flatten: {
                    type: "boolean",
                    value: "true"
                }
            }
        });
    Y.Wegas.EntityChooser2 = EntityChooser2;

});
<|endoftext|>


<commit_before>/*
 *
 * Description:
 * This file holds the controller logic.  It manages the connection to the Atmega328.
 *
 */
var path = require('path'), spawn = require('child_process').spawn, CONFIG = require('./config'), StatusReader = require('./StatusReader'), ArduinoPhysics = require('./ArduinoPhysics'), logger = require('./logger').create(CONFIG), EventEmitter = require('events').EventEmitter, Hardware = require('../' + CONFIG.Hardware);
var setup_serial = function () {
  var location = path.join(__dirname, '..', './linux');
  logger.log('Starting the script from ' + location + ' to setup UART1...');
  var setuart_process = spawn('sudo', [path.join(location, 'setuart.sh')]);
  setuart_process.on('error', function (err) {
    logger.log('Error while starting the UART1 setup scipt!\nThe error was: ' + err);
  });
};
var statusdata = {};
var settingsCollection = {
    smoothingIncriment: 0,
    deadZone_min: 0,
    deadZone_max: 0
  };
var rovsys = { capabilities: 0 };
var OpenROVController = function (eventLoop) {
  var serial;
  var globalEventLoop = eventLoop;
  var reader = new StatusReader();
  var physics = new ArduinoPhysics();
  var hardware = new Hardware();
  var controller = new EventEmitter();
  setInterval(function () {
    controller.emit('status', statusdata);
  }, 1000);
  hardware.on('serial-recieved', function (data) {
    globalEventLoop.emit('serial-recieved', data);
  });
  hardware.on('status', function (status) {
    for (var i in status) {
      statusdata[i] = status[i];
    }
    if ('ver' in status) {
      controller.ArduinoFirmwareVersion = status.ver;
    }
    if ('TSET' in status) {
      console.log(status.settings);
      var setparts = status.settings.split(',');
      settingsCollection.smoothingIncriment = setparts[0];
      settingsCollection.deadZone_min = setparts[1];
      settingsCollection.deadZone_max = setparts[2];
      controller.emit('Arduino-settings-reported', settingsCollection);
    }
    if ('CAPA' in status) {
      var s = rovsys;
      console.log('RovSys: ' + status.CAPA);
      s.capabilities = parseInt(status.CAPA);
      controller.Capabilities = s.capabilities;
      controller.emit('rovsys', s);
    }
    if ('cmd' in status) {
      if (status.com != 'ping(0)'){
        console.log('cmd: ' + status.cmd);
        controller.emit('command', status.cmd);
      }
    }
    if ('log' in status) {
      console.log('log: ' + status.log);
    }
    if ('boot' in status){
      this.Capabilities = 0;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
    }
  });
  setup_serial();
  hardware.connect();
  controller.ArduinoFirmwareVersion = 0;
  controller.Capabilities = 0;

  controller.requestCapabilities = function () {
    console.log('Sending rcap to arduino');
    var command = 'rcap();';
    hardware.write(command);
  };
  controller.requestSettings = function () {
    var command = 'reportSetting();';
    hardware.write(command);
    command = 'rmtrmod();';
    hardware.write(command);
  };
  controller.updateSetting = function () {

    var command = 'updateSetting(' + CONFIG.preferences.get('smoothingIncriment') + ',' + CONFIG.preferences.get('deadzone_neg') + ',' + CONFIG.preferences.get('deadzone_pos') + ',' + CONFIG.preferences.get('water_type') + ';';
    hardware.write(command);
    //This is the multiplier used to make the motor act linear fashion.
    //for example: the props generate twice the thrust in the positive direction
    //than the negative direction.  To make it linear we have to multiply the
    //negative direction * 2.
    var port = CONFIG.preferences.get('thrust_modifier_port');
    var vertical = CONFIG.preferences.get('thrust_modifier_vertical');
    var starbord = CONFIG.preferences.get('thrust_modifier_starbord');
    var nport = CONFIG.preferences.get('thrust_modifier_nport');
    var nvertical = CONFIG.preferences.get('thrust_modifier_nvertical');
    var nstarbord = CONFIG.preferences.get('thrust_modifier_nstarbord');
    if (CONFIG.preferences.get('reverse_port_thruster')) {
      port = port * -1;
      nport = nport * -1;
    }
    if (CONFIG.preferences.get('reverse_lift_thruster')) {
      vertical = vertical * -1;
      nvertical = nvertical * -1;
    }
    if (CONFIG.preferences.get('reverse_starbord_thruster')) {
      starbord = starbord * -1;
      nstarbord = nstarbord * -1;
    }
    //API to Arduino to pass a percent in 2 decimal accuracy requires multipling by 100 before sending.
    command = 'mtrmod(' + port * 100 + ',' + vertical * 100 + ',' + starbord * 100 + ',' + nport * 100 + ',' + nvertical * 100 + ',' + nstarbord * 100 + ');';
    hardware.write(command);
  };
  controller.notSafeToControl = function () {
    //Arduino is OK to accept commands. After the Capabilities was added, all future updates require
    //being backward safe compatible (meaning you cannot send a command that does something unexpected but
    //instead it should do nothing).
    if (this.Capabilities !== 0)
      return false;
    //This feature added after the swap to ms on the Arduino
    console.log('Waiting for the capability response from Arduino before sending command.');
    console.log('Arduno Version: ' + this.ArduinoFirmwareVersion);
    console.log('Capability bitmap: ' + this.Capabilities);
    return true;
  };
  controller.send = function (cmd) {
    if (this.notSafeToControl())
      return;

    var command = cmd + ';';
    console.log('Sending command to arduino: ' + command);

    hardware.write(command);
  };
  controller.sendMotorTest = function (port, starbord, vertical) {
    if (this.notSafeToControl())
      return;
    var command = 'go(' + physics.mapRawMotor(port) + ',' + physics.mapRawMotor(vertical) + ',' + physics.mapRawMotor(starbord) + ',1);';
    //the 1 bypasses motor smoothing
    hardware.write(command);
  };
  controller.sendCommand = function (throttle, yaw, vertical) {
    if (this.notSafeToControl())
      return;
    var motorCommands = physics.mapMotors(throttle, yaw, vertical);
    var command = 'go(' + motorCommands.port + ',' + motorCommands.vertical + ',' + motorCommands.starbord + ');';
    hardware.write(command);
  };
  controller.stop = function (value) {
    if (this.notSafeToControl())
      return;
    var command = 'stop();';
    hardware.write(command);
  };
  controller.start = function (value) {
    if (this.notSafeToControl())
      return;
    var command = 'start();';
    hardware.write(command);
  };
  globalEventLoop.on('register-ArdunoFirmwareVersion', function (val) {
    controller.ArduinoFirmwareVersion = val;
  });
  globalEventLoop.on('register-ArduinoCapabilities', function (val) {
    controller.Capabilities = val;
  });
  globalEventLoop.on('SerialMonitor_toggle_rawSerial', function () {
    hardware.toggleRawSerialData();
  });
  globalEventLoop.on('serial-stop', function () {
    logger.log('Closing serial connection for firmware upload');
    hardware.close();
  });
  globalEventLoop.on('serial-start', function () {
    hardware.connect();
    controller.updateSetting();
    logger.log('Opened serial connection after firmware upload');
  });

  controller.updateSetting();
  //Every few seconds we check to see if capabilities or settings changes on the arduino.
  //This handles the cases where we have garbled communication or a firmware update of the arduino.
  controller.requestSettings();
  controller.requestCapabilities();

  setInterval(function () {
    if (!controller.notSafeToControl()) return;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
  }, 10000);

  return controller;
};
module.exports = OpenROVController;
<commit_msg>Cleanup<commit_after>/*
 *
 * Description:
 * This file holds the controller logic.  It manages the connection to the Atmega328.
 *
 */
var path = require('path'), spawn = require('child_process').spawn, CONFIG = require('./config'), StatusReader = require('./StatusReader'), ArduinoPhysics = require('./ArduinoPhysics'), logger = require('./logger').create(CONFIG), EventEmitter = require('events').EventEmitter, Hardware = require('../' + CONFIG.Hardware);
var setup_serial = function () {
  var location = path.join(__dirname, '..', './linux');
  logger.log('Starting the script from ' + location + ' to setup UART1...');
  var setuart_process = spawn('sudo', [path.join(location, 'setuart.sh')]);
  setuart_process.on('error', function (err) {
    logger.log('Error while starting the UART1 setup scipt!\nThe error was: ' + err);
  });
};
var statusdata = {};
var settingsCollection = {
    smoothingIncriment: 0,
    deadZone_min: 0,
    deadZone_max: 0
  };

var rovsys = { capabilities: 0 };

var OpenROVController = function (eventLoop) {
  var controller = this;
  var serial;
  var globalEventLoop = eventLoop;
  this.physics = new ArduinoPhysics();
  this.hardware = new Hardware();

  setInterval(function () {
    controller.emit('status', statusdata);
  }, 1000);

  this.hardware.on('serial-recieved', function (data) {
    globalEventLoop.emit('serial-recieved', data);
  });

  this.hardware.on('status', function (status) {
    for (var i in status) {
      statusdata[i] = status[i];
    }
    if ('ver' in status) {
      controller.ArduinoFirmwareVersion = status.ver;
    }
    if ('TSET' in status) {
      console.log(status.settings);
      var setparts = status.settings.split(',');
      settingsCollection.smoothingIncriment = setparts[0];
      settingsCollection.deadZone_min = setparts[1];
      settingsCollection.deadZone_max = setparts[2];
      controller.emit('Arduino-settings-reported', settingsCollection);
    }
    if ('CAPA' in status) {
      var s = rovsys;
      console.log('RovSys: ' + status.CAPA);
      s.capabilities = parseInt(status.CAPA);
      controller.Capabilities = s.capabilities;
      controller.emit('rovsys', s);
    }
    if ('cmd' in status) {
      if (status.com != 'ping(0)'){
        console.log('cmd: ' + status.cmd);
        controller.emit('command', status.cmd);
      }
    }
    if ('log' in status) {
      console.log('log: ' + status.log);
    }
    if ('boot' in status){
      this.Capabilities = 0;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
    }
  });
  setup_serial();
  this.hardware.connect();
  controller.ArduinoFirmwareVersion = 0;
  controller.Capabilities = 0;

  controller.notSafeToControl = function () {
    //Arduino is OK to accept commands. After the Capabilities was added, all future updates require
    //being backward safe compatible (meaning you cannot send a command that does something unexpected but
    //instead it should do nothing).
    if (controller.Capabilities !== 0)
      return false;
    //This feature added after the swap to ms on the Arduino
    console.log('Waiting for the capability response from Arduino before sending command.');
    console.log('Arduno Version: ' + controller.ArduinoFirmwareVersion);
    console.log('Capability bitmap: ' + controller.Capabilities);
    return true;
  };

  globalEventLoop.on('register-ArdunoFirmwareVersion', function (val) {
    controller.ArduinoFirmwareVersion = val;
  });
  globalEventLoop.on('register-ArduinoCapabilities', function (val) {
    controller.Capabilities = val;
  });

  globalEventLoop.on('SerialMonitor_toggle_rawSerial', function () {
    controller.hardware.toggleRawSerialData();
  });

  globalEventLoop.on('serial-stop', function () {
    logger.log('Closing serial connection for firmware upload');
    controller.hardware.close();
  });

  globalEventLoop.on('serial-start', function () {
    controller.hardware.connect();
    controller.updateSetting();
    logger.log('Opened serial connection after firmware upload');
  });

  controller.updateSetting();
  //Every few seconds we check to see if capabilities or settings changes on the arduino.
  //This handles the cases where we have garbled communication or a firmware update of the arduino.
  controller.requestSettings();
  controller.requestCapabilities();

  setInterval(function () {
    if (!controller.notSafeToControl()) return;
      controller.updateSetting();
      controller.requestSettings();
      controller.requestCapabilities();
  }, 10000);

  return controller;
};
OpenROVController.prototype = new EventEmitter();
OpenROVController.prototype.constructor = OpenROVController;

OpenROVController.prototype.send = function (cmd) {
  var controller = this;
  if (controller.notSafeToControl())
    return;

  var command = cmd + ';';
  console.log('Sending command to arduino: ' + command);

  controller.hardware.write(command);
};

OpenROVController.prototype.requestCapabilities = function () {
  console.log('Sending rcap to arduino');
  var command = 'rcap();';
  this.hardware.write(command);
};

OpenROVController.prototype.requestSettings = function () {
  var command = 'reportSetting();';
  this.hardware.write(command);
  command = 'rmtrmod();';
  this.hardware.write(command);
};

OpenROVController.prototype.updateSetting = function () {

  var command = 'updateSetting(' + CONFIG.preferences.get('smoothingIncriment') + ',' + CONFIG.preferences.get('deadzone_neg') + ',' + CONFIG.preferences.get('deadzone_pos') + ',' + CONFIG.preferences.get('water_type') + ';';
  this.hardware.write(command);
  //This is the multiplier used to make the motor act linear fashion.
  //for example: the props generate twice the thrust in the positive direction
  //than the negative direction.  To make it linear we have to multiply the
  //negative direction * 2.
  var port = CONFIG.preferences.get('thrust_modifier_port');
  var vertical = CONFIG.preferences.get('thrust_modifier_vertical');
  var starbord = CONFIG.preferences.get('thrust_modifier_starbord');
  var nport = CONFIG.preferences.get('thrust_modifier_nport');
  var nvertical = CONFIG.preferences.get('thrust_modifier_nvertical');
  var nstarbord = CONFIG.preferences.get('thrust_modifier_nstarbord');
  if (CONFIG.preferences.get('reverse_port_thruster')) {
    port = port * -1;
    nport = nport * -1;
  }
  if (CONFIG.preferences.get('reverse_lift_thruster')) {
    vertical = vertical * -1;
    nvertical = nvertical * -1;
  }
  if (CONFIG.preferences.get('reverse_starbord_thruster')) {
    starbord = starbord * -1;
    nstarbord = nstarbord * -1;
  }
  //API to Arduino to pass a percent in 2 decimal accuracy requires multipling by 100 before sending.
  command = 'mtrmod(' + port * 100 + ',' + vertical * 100 + ',' + starbord * 100 + ',' + nport * 100 + ',' + nvertical * 100 + ',' + nstarbord * 100 + ');';
  this.hardware.write(command);
};

OpenROVController.prototype.sendMotorTest = function (port, starbord, vertical) {
  var command = 'go(' + this.physics.mapRawMotor(port) + ',' +
    this.physics.mapRawMotor(vertical) + ',' +
    this.physics.mapRawMotor(starbord) + ',1)';
  //the 1 bypasses motor smoothing
  this.send(command);
};

OpenROVController.prototype.sendCommand = function (throttle, yaw, vertical) {
  var motorCommands = this.physics.mapMotors(throttle, yaw, vertical);
  var command = 'go(' + motorCommands.port + ','
    + motorCommands.vertical + ','
    + motorCommands.starbord + ')';
  this.send(command);
};

OpenROVController.prototype.stop = function (value) {
  var command = 'stop()';
  this.send(command);
};

OpenROVController.prototype.start = function (value) {
  var command = 'start()';
  this.send(command);
};

module.exports = OpenROVController;
<|endoftext|>


<commit_before>import * as ScriptLoader from "../ScriptLoader.js";
import * as Base64ArrayBufferToUint8Array from "../Base64ArrayBufferToUint8Array.js";
import * as PartTime from "../PartTime.js";
import * as ValueMax from "../ValueMax.js";

function getRandomInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}

// This string will not fit to ASCII when base64 decoded. So can not be used to test.
//const base64EncodedString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// Use all printable ASCII codes form a string of 3-divisible length.
// (So its base64-encoded codes will divisible by 4.)
let originalArray = [];
{
  const ORIGINAL_TEST_STRING_LENGTH = 3 * 4;

  const PRINTABLE_ASCII_MIN = 32;
  const PRINTABLE_ASCII_MAX = 126;

  for (let i = 0; i < ORIGINAL_TEST_STRING_LENGTH; ++i) {
    let c = PRINTABLE_ASCII_MIN + getRandomInt(PRINTABLE_ASCII_MAX - PRINTABLE_ASCII_MIN + 1);
    originalArray.push( String.fromCodePoint( c ) );
  }
}

const originalString = originalArray.join("");
const base64EncodedString = btoa(originalString);
const base64DecodedString = atob(base64EncodedString);

const base64EncodedStrings_extra = [
  // Test empty base64 content.
  "",
  "\n",
  "\r",
  "\r\n",
  "\n\r",

  // Test extra has 0 to 3 bytes. (They should be ignored.)
  base64EncodedString,
  base64EncodedString + base64EncodedString.slice(0, 1),
  base64EncodedString + base64EncodedString.slice(0, 2),
  base64EncodedString + base64EncodedString.slice(0, 3),

  // Test extra non-base64 codes inside. (They should be ignored.)
  base64EncodedString.slice(0, 3) + "\n"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r\n" + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\n\r" + base64EncodedString.slice(3),

  // Test skip 3 lines. Test multiple non-base64 codes. (They should be ignored.)
  "qwerty5ASDFG7\n\n\r"
    + base64EncodedString.slice(0, 2) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(2, 7) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(7, 9) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(9)    + "\n\n\r\r\r\n\r\n",
];

let tEncoder = new TextEncoder();
let tDecoder = new TextDecoder();

//const base64EncodedUint8Array = tDecoder.decode(base64EncodedString);
const base64DecodedUint8Array = tEncoder.encode(base64DecodedString);
const emptyUint8Array = new Uint8Array(0);

class TestCase {
  constructor(source, skipLineCount, result, note) {
    this.source = source;
    this.skipLineCount = skipLineCount;
    this.result = result;
    this.note = note;
  }
}

let testCases = [
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 0, emptyUint8Array, "Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 1]), 1, emptyUint8Array, "LF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 2]), 1, emptyUint8Array, "CR Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 3]), 1, emptyUint8Array, "CRLF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 4]), 2, emptyUint8Array, "LFCR Empty" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 5]), 0, base64DecodedUint8Array, "Extra 0 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 6]), 0, base64DecodedUint8Array, "Extra 1 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 7]), 0, base64DecodedUint8Array, "Extra 2 bytes" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 8]), 0, base64DecodedUint8Array, "Extra 3 bytes" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 9]), 0, base64DecodedUint8Array, "Extra LF inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[10]), 0, base64DecodedUint8Array, "Extra CR inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[11]), 0, base64DecodedUint8Array, "Extra CRLF inside" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[12]), 0, base64DecodedUint8Array, "Extra LFCR inside" ),

  new TestCase( tEncoder.encode("\n"   + base64EncodedString), 1, base64DecodedUint8Array, "Begin LF" ),
  new TestCase( tEncoder.encode("\r"   + base64EncodedString), 1, base64DecodedUint8Array, "Begin CR" ),
  new TestCase( tEncoder.encode("\r\n" + base64EncodedString), 1, base64DecodedUint8Array, "Begin CRLF" ),
  new TestCase( tEncoder.encode("\n\r" + base64EncodedString), 2, base64DecodedUint8Array, "Begin LFCR" ),

  new TestCase( tEncoder.encode("qwerty\n"   + base64EncodedString), 1, base64DecodedUint8Array, "Text LF" ),
  new TestCase( tEncoder.encode("qwerty\r"   + base64EncodedString), 1, base64DecodedUint8Array, "Text CR" ),
  new TestCase( tEncoder.encode("qwerty\r\n" + base64EncodedString), 1, base64DecodedUint8Array, "Text CRLF" ),
  new TestCase( tEncoder.encode("qwerty\n\r" + base64EncodedString), 2, base64DecodedUint8Array, "Text LFCR" ),

  new TestCase( tEncoder.encode(base64EncodedStrings_extra[13]), 3, base64DecodedUint8Array, "Multiple LF and CR inside" ),
];

/** Aggregate all progress about downloading, JSON parsing, characters scanning, and weights scanning.  */
class Progress extends ValueMax.Percentage.Aggregate {
  constructor() {
    let children = [
//      new ValueMax.Percentage.Concrete(), // Increased when downloading from network.
//      new ValueMax.Percentage.Concrete(), // Increased when parsing the downloaded data to Uint8Array.
    ];

    for (let i = 0; i < testCases.length; ++i) {
      children.push(new ValueMax.Percentage.Concrete()); // Increased when parsing the downloaded data to Uint8Array.
    }

    super(children);

//    [this.download, this.uint8Array] = children;
//    [this.uint8Array] = children;
  }
}

let progress = new Progress();
let progressReceiver = new ValueMax.Receiver.HTMLProgress.createByTitle_or_getDummy("TestProgressBar");

window.addEventListener("load", event => {
  ScriptLoader.createPromise("https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js").then(test); });

function test() {
  console.log("Base64 decode testing...");
  let delayMilliseconds = 1000;

  let testPromiseAll = [];
  for (let i = 0; i < testCases.length; ++i) {
    let testCase = testCases[ i ];

    let testPromise = PartTime.forOf(
      Base64ArrayBufferToUint8Array.decode_Generator(
        testCase.source, testCase.skipLineCount, progress, progress.childProgressParts[ i ], 5),
      (valueMax) => { progressReceiver.setValueMax(valueMax); /* Report progress to UI. */ },
      delayMilliseconds
    ).then(r => {
      progressReceiver.informDone(r); /* Inform UI progress done. */
      tf.util.assert(
        r.toString() == testCase.result.toString(),
        `${i}. Skip ${testCase.skipLineCount} lines. ${testCase.note} [${r}] != [${testCase.result}]`);
    });

    testPromiseAll.push( testPromise );
  }

  Promise.all(testPromiseAll).then(values => {
    console.log("Base64 decode testing... Done.");
  });
}
<commit_msg>Update Base64ArrayBufferToUint8Array_tester.js<commit_after>import * as ScriptLoader from "../ScriptLoader.js";
import * as Base64ArrayBufferToUint8Array from "../Base64ArrayBufferToUint8Array.js";
import * as PartTime from "../PartTime.js";
import * as ValueMax from "../ValueMax.js";

function getRandomInt(max) {
  return Math.floor(Math.random() * Math.floor(max));
}

// This string will not fit to ASCII when base64 decoded. So can not be used to test.
//const base64EncodedString = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

// Use all printable ASCII codes form a string of 3-divisible length.
// (So its base64-encoded codes will divisible by 4.)
let originalArray = [];
{
  const ORIGINAL_TEST_STRING_LENGTH = 3 * 4;

  const PRINTABLE_ASCII_MIN = 32;
  const PRINTABLE_ASCII_MAX = 126;

  for (let i = 0; i < ORIGINAL_TEST_STRING_LENGTH; ++i) {
    let c = PRINTABLE_ASCII_MIN + getRandomInt(PRINTABLE_ASCII_MAX - PRINTABLE_ASCII_MIN + 1);
    originalArray.push( String.fromCodePoint( c ) );
  }
}

const originalString = originalArray.join("");
const base64EncodedString = btoa(originalString);
const base64DecodedString = atob(base64EncodedString);

const base64EncodedStrings_extra = [
  // Test empty base64 content.
  "",
  "\n",
  "\r",
  "\r\n",
  "\n\r",

  // Test extra has 0 to 3 bytes. (They should be ignored.)
  base64EncodedString,
  base64EncodedString + base64EncodedString.slice(0, 1),
  base64EncodedString + base64EncodedString.slice(0, 2),
  base64EncodedString + base64EncodedString.slice(0, 3),

  // Test extra non-base64 codes inside. (They should be ignored.)
  base64EncodedString.slice(0, 3) + "\n"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r"   + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\r\n" + base64EncodedString.slice(3),
  base64EncodedString.slice(0, 3) + "\n\r" + base64EncodedString.slice(3),

  // Test skip 3 lines. Test multiple non-base64 codes. (They should be ignored.)
  "qwerty5ASDFG7\n\n\r"
    + base64EncodedString.slice(0, 2) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(2, 7) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(7, 9) + "\n\n\r\r\r\n\r\n"
    + base64EncodedString.slice(9)    + "\n\n\r\r\r\n\r\n",
];

let tEncoder = new TextEncoder();
let tDecoder = new TextDecoder();

//const base64EncodedUint8Array = tDecoder.decode(base64EncodedString);
const base64DecodedUint8Array = tEncoder.encode(base64DecodedString);
const emptyUint8Array = new Uint8Array(0);

class TestCase {
  constructor(source, skipLineCount, result, note) {
    this.source = source;
    this.skipLineCount = skipLineCount;
    this.result = result;
    this.note = note;
  }
}

let testCases = [
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 0]), 0, emptyUint8Array, "Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 1]), 1, emptyUint8Array, "LF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 2]), 1, emptyUint8Array, "CR Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 3]), 1, emptyUint8Array, "CRLF Empty" ),
  new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 4]), 2, emptyUint8Array, "LFCR Empty" ),

//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 5]), 0, base64DecodedUint8Array, "Extra 0 bytes" ),
//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 6]), 0, base64DecodedUint8Array, "Extra 1 bytes" ),
//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 7]), 0, base64DecodedUint8Array, "Extra 2 bytes" ),
//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 8]), 0, base64DecodedUint8Array, "Extra 3 bytes" ),

//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[ 9]), 0, base64DecodedUint8Array, "Extra LF inside" ),
//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[10]), 0, base64DecodedUint8Array, "Extra CR inside" ),
//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[11]), 0, base64DecodedUint8Array, "Extra CRLF inside" ),
//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[12]), 0, base64DecodedUint8Array, "Extra LFCR inside" ),

//   new TestCase( tEncoder.encode("\n"   + base64EncodedString), 1, base64DecodedUint8Array, "Begin LF" ),
//   new TestCase( tEncoder.encode("\r"   + base64EncodedString), 1, base64DecodedUint8Array, "Begin CR" ),
//   new TestCase( tEncoder.encode("\r\n" + base64EncodedString), 1, base64DecodedUint8Array, "Begin CRLF" ),
//   new TestCase( tEncoder.encode("\n\r" + base64EncodedString), 2, base64DecodedUint8Array, "Begin LFCR" ),

//   new TestCase( tEncoder.encode("qwerty\n"   + base64EncodedString), 1, base64DecodedUint8Array, "Text LF" ),
//   new TestCase( tEncoder.encode("qwerty\r"   + base64EncodedString), 1, base64DecodedUint8Array, "Text CR" ),
//   new TestCase( tEncoder.encode("qwerty\r\n" + base64EncodedString), 1, base64DecodedUint8Array, "Text CRLF" ),
//   new TestCase( tEncoder.encode("qwerty\n\r" + base64EncodedString), 2, base64DecodedUint8Array, "Text LFCR" ),

//   new TestCase( tEncoder.encode(base64EncodedStrings_extra[13]), 3, base64DecodedUint8Array, "Multiple LF and CR inside" ),
];

/** Aggregate all progress about downloading, JSON parsing, characters scanning, and weights scanning.  */
class Progress extends ValueMax.Percentage.Aggregate {
  constructor() {
    let children = [
//      new ValueMax.Percentage.Concrete(), // Increased when downloading from network.
//      new ValueMax.Percentage.Concrete(), // Increased when parsing the downloaded data to Uint8Array.
    ];

    for (let i = 0; i < testCases.length; ++i) {
      children.push(new ValueMax.Percentage.Concrete()); // Increased when parsing the downloaded data to Uint8Array.
    }

    super(children);

//    [this.download, this.uint8Array] = children;
//    [this.uint8Array] = children;
  }
}

let progress = new Progress();
let progressReceiver = new ValueMax.Receiver.HTMLProgress.createByTitle_or_getDummy("TestProgressBar");

window.addEventListener("load", event => {
  ScriptLoader.createPromise("https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.0.0/dist/tf.min.js").then(test); });

function test() {
  console.log("Base64 decode testing...");
  let delayMilliseconds = 10000;

  let testPromiseAll = [];
  for (let i = 0; i < testCases.length; ++i) {
    let testCase = testCases[ i ];

    let testPromise = PartTime.forOf(
      Base64ArrayBufferToUint8Array.decode_Generator(
        testCase.source, testCase.skipLineCount, progress, progress.childProgressParts[ i ], 5),
      (valueMax) => { progressReceiver.setValueMax(valueMax); /* Report progress to UI. */ },
      delayMilliseconds
    ).then(r => {
      progressReceiver.informDone(r); /* Inform UI progress done. */
      tf.util.assert(
        r.toString() == testCase.result.toString(),
        `${i}. Skip ${testCase.skipLineCount} lines. ${testCase.note} [${r}] != [${testCase.result}]`);
    });

    testPromiseAll.push( testPromise );
  }

  Promise.all(testPromiseAll).then(values => {
    console.log("Base64 decode testing... Done.");
  });
}
<|endoftext|>


<commit_before>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013-2018  School of Business and Engineering Vaud, Comem, MEI
 * Licensed under the MIT License
 */
/**
 * @author Francois-Xavier Aeberhard <fx@red-agent.com>,
 * Cyril Junod <cyril.junod at gmail.com>
 */
YUI.add('wegas-pageeditor', function(Y) {
    "use strict";

    var PageEditor, Wegas = Y.Wegas,
        BOUNDINGBOX = "boundingBox", CONTENTBOX = "contentBox",
        Alignable = Y.Base.create("wegas-pageeditor-overlay", Y.Widget, [Y.WidgetPosition, Y.WidgetStack], {}, {
            CSS_PREFIX: "wegas-pageeditor-overlay"
        });
    /**
     *  @class
     *  @name Y.Plugin.PageEditor
     *  @extends Y.Plugin.Base
     *  @constructor
     */
    PageEditor = function() {
        PageEditor.superclass.constructor.apply(this, arguments);
    };
    Y.extend(PageEditor, Y.Plugin.Base, {
        // *** Lifecycle methods *** //
        initializer: function() {
            this.handlers = [];
            this.fixedHandlers = [];
            /**
             * Store user enabled active edition
             */
            this.isActive = false;

            if (!Wegas.Facade.Page.cache.isEditable()) {
                Y.later(100, this.get("host"), function() {
                    this.unplug(PageEditor);
                });
            } else {
                this.afterHostEvent("render", this.render);
            }
        },
        render: function() {
            var host = this.get('host');
            if (host.toolbar) {
                /** Edit page  **/
                this.designButton = host.toolbar.add({
                    type: "ToggleButton",
                    label: "Edit page",
                    cssClass: "wegas-pageeditor-editbutton"
                }).item(0);
                this.designButton.after("pressedChange", function(e) {
                    host.get(BOUNDINGBOX).toggleClass("wegas-pageeditor-designmode", e.newVal);
                    this.sourceButton.set("visible", e.newVal);
                    this.layoutButton.set("visible", e.newVal);
                    this.addButton.set("visible", e.newVal);
                    //this.refreshButton.set("visible", e.newVal);
                    if (e.newVal) {
                        //Wegas.Facade.Page.cache.getIndex(function(index) {
                        //    var pageName = index[host.get("pageId")] !== ""
                        //            ? index[host.get("pageId")]
                        //            : "unamed(" + host.get("pageId") + ")";
                        //    host.toolbar.setStatusMessage("Editing page: " + pageName);
                        //});
                        this.bind();
                        host.get(CONTENTBOX).prepend(this.overlayMask);
                    } else {
                        this.detachHandlers();
                        host.toolbar.setStatusMessage("");
                        this.overlayMask.remove(false);
                        this.shownOverlay.hide();
                        this.layoutButton.set("pressed", false);
                    }
                }, this);

                /** New button **/
                this.addButton = host.toolbar.add({
                    label: "New",
                    visible: false
                }).item(0);
                this.addButton.plug(Y.Plugin.WidgetMenu);
                this.addButton.menu.on("menuOpen", function() {
                    var menu = host.get("widget").getMenuCfg({
                        targetwidget: host.get("widget")
                    }), addElement = Y.Array.find(menu, function(o) {           /* search "Add" menu */
                        return o.label.indexOf("Add") > -1;
                    });
                    if (addElement) {
                        this.set("children", addElement.plugins[0].cfg.children);// And place it'
                    } else {
                        this.set("children", []);
                    }
                });

                /** Refresh **/
//                this.refreshButton = host.toolbar.add({
//                    label: "Refresh",
//                    cssClass: "wegas-advanced-feature"
//                }).item(0);
//                this.refreshButton.after("click", function(e) {
//                    this.get("host").reload();
//                }, this);

                this.layoutButton = host.toolbar.add({// Layout
                    type: "ToggleButton",
                    label: "Draw elements",
                    visible: false
                }).item(0);
                this.layoutButton.after("pressedChange", function(e) {
                    host.get(BOUNDINGBOX).toggleClass("wegas-pageeditor-layoutmode",
                        e.newVal);
                });

                /** Source view **/
                this.sourceButton = host.toolbar.add({
                    type: "ToggleButton",
                    label: "Source",
                    visible: false,
                    on: {
                        click: Y.bind(this.processSource, this)
                    }
                }).item(0);

                this.saveButton = host.toolbar.add({
                    label: "Save",
                    visible: false,
                    on: {
                        click: Y.bind(this.processSave, this)
                    }
                }).item(0);
            }
            this.fixedHandlers.push(this.afterHostEvent("contentUpdated", this.processSource));
            this.highlightOverlay = new Alignable({// Init the highlighting overlay
                zIndex: 30,
                render: true,
                visible: false
            });
            this.shownOverlay = new Alignable({// Init the highlighting overlay
                zIndex: 30,
                render: true,
                visible: false
            });
            this.shownOverlay.get(BOUNDINGBOX).addClass("pageditor-shownoverlay");
            this.highlightOverlay.get(CONTENTBOX).append("");
            this.shownOverlay.get(CONTENTBOX).append("");

            /** MASK **/
            this.overlayMask = new Y.Node.create("

");
            this.overlayMask.plug(Y.Plugin.WidgetMenu, {
                event: ["click", "contextmenu"]
            });
            this.overlayMask.menu.after("menuOpen", function(e) {
                this.fixedOverlay(this.overlayWidget);
            }, this);
            this.overlayMask.menu.getMenu().set("preventOverlap", false);
            this.overlayMask.append(this.shownOverlay.get(BOUNDINGBOX));
            this.overlayMask.append(this.highlightOverlay.get(BOUNDINGBOX));
            this.fixedHandlers.push(this.doBefore("pageIdChange", function(e) {
                if (this.get("host") === e.target) {
                    this.isActive = this.isActive || this.designButton.get("pressed");
                    this.designButton.set("pressed", false);
                }
            }));
            this.fixedHandlers.push(this.doAfter("contentUpdated", function(e) {
                this.designButton.set("pressed", this.isActive);
                this.isActive = false;
            }));
            this.fixedHandlers.push(host.get(CONTENTBOX).after("mouseout", function(e) {
                if (!PageEditor.inRegion(e.currentTarget, [e.clientX, e.clientY])) {
                    this.hideOverlay();
                }
            }, this));

            host.get(CONTENTBOX).plug(Y.Plugin.ScrollInfo);
            this.fixedHandlers.push(host.get(CONTENTBOX).scrollInfo.on("*:scroll", function(e) {
                this.overlayMask.setStyles({top: e.scrollTop, left: e.scrollLeft});
                if (this.shownOverlay._widget) {
                    this.fixedOverlay(this.shownOverlay._widget);
                }
            }, this));
        },
        bind: function() {
            if (this.binded) {
                return;
            }
            this.binded = true;
            this.handlers.push(this.overlayMask.on("mousemove", function(e) {
                var widget, vis = this.shownOverlay.get("visible");

                e.halt(true);
                this.overlayMask.hide();
                this.highlightOverlay.hide();
                this.shownOverlay.hide();
                widget = Y.Widget.getByNode(Y.Node(window.document.elementFromPoint(e.clientX, e.clientY)).ancestor(".wegas-widget-editable", true));//Find a parent Wegas widget or self
                this.overlayMask.show();
                if (vis) {
                    this.shownOverlay.show();
                }
                if (this.get("host") === widget || widget === null) {
                    return;
                }
                if (widget !== this.overlayWidget) {
                    this.showOverlay(widget);
                } else {
                    this.highlightOverlay.show();
                }
            }, this));
            this.handlers.push(this.overlayMask.menu.on("menuOpen", function(e) {
                if (PageEditor.inRegion(this.shownOverlay.get(CONTENTBOX).one(".wegas-editmenubutton-icon"), [e.domEvent.clientX, e.domEvent.clientY])) { /* Clicked editmenu */
                    this.targetWidget = this.shownOverlay._widget;
                    this.overlayMask.menu.set("children", this.targetWidget.getMenuCfg());
                    this.overlayMask.menu.menu.set("xy", [e.domEvent.clientX, e.domEvent.clientY]);
                    e.halt(true);
                } else if (e.domEvent.type === "contextmenu") {
                    this.targetWidget = this.overlayWidget;
                    this.overlayMask.menu.set("children", this.targetWidget.getMenuCfg());
                    if (this.overlayMask.menu.getMenu().size() > 0) {
                        this.overlayMask.menu.getMenu().item(0).fire("click");
                    }
                    this.overlayMask.menu.menu.set("xy", [e.domEvent.clientX, e.domEvent.clientY]);
                } else {                                                        /* Clicked widget*/
                    this.targetWidget = this.overlayWidget;
                    this.overlayMask.menu.set("children", this.targetWidget.getMenuCfg({
                        widget: this.targetWidget
                    }));
                    this.overlayMask.menu.menu.hide();
                    if (this.overlayMask.menu.getMenu().size() > 0) {
                        this.overlayMask.menu.getMenu().item(0).fire("click");
                    }
                }
            }, this));
            this.handlers.push(Wegas.app.after("layout:resize", function(e) {
                if (this.targetWidget) {
                    this.fixedOverlay(this.targetWidget);
                }
            }, this));
        },
        processSave: function() {
            var host = this.get("host"),
                page;
            try {
                page = Y.JSON.parse(this.jsonView.getValue());
                page["@pageId"] = this.get("host").get("pageId");
            } catch (ex) {
                Y.Widget.getByNode(host.get(BOUNDINGBOX).get("parentNode")).showMessage("error", ex.toString());
                return;
            }
            this.sourceButton.set("pressed", false);
            host.get(CONTENTBOX).show();
            this.jsonView.hide();
            this.designButton.enable();
            this.saveButton.hide();
            host.showOverlay();
            Wegas.Facade.Page.cache.patch(page, Y.bind(function() {
                host.hideOverlay();
                this.reload();
            }, host));
        },
        saveCurrentPage: function() {
            var page = this.get("host").get("widget").toObject();
            page["@pageId"] = this.get("host").get("widget")["@pageId"];
            Wegas.Facade.Page.cache.patch(page);
        },
        processSource: function() {
            var host = this.get("host");
            if (this.sourceButton.get("pressed")) {
                if (!this.jsonView) {
                    this.initJsonView();
                    return;
                }
                this.jsonView.setValue(host.get("widgetCfg"));
                host.get(CONTENTBOX).hide();
                this.jsonView.show();
                this.jsonView.editor.resize();
                this.jsonView.focus();
                this.designButton.disable();
                this.saveButton.show();
            } else {
                host.get(CONTENTBOX).show();
                if (this.jsonView) {
                    this.jsonView.hide();
                }
                this.designButton.enable();
                this.saveButton.hide();
            }
        },
        initJsonView: function() {
            if (!this.jsonView) {
                Y.use("wegas-inputex-ace", Y.bind(function(Y) {
                    this.jsonView = new Y.inputEx.AceField({
                        parentEl: this.get("host").get(BOUNDINGBOX),
                        name: 'text',
                        type: 'ace',
                        height: "100%",
                        language: "json",
                        value: '',
                        wrapperClass: "wegas-pageeditor-ace"
                    });
                    this.jsonView.hide();
                    this.processSource();
                }, this));
            }
        },
        detachHandlers: function() {
            for (var i = 0; i < this.handlers.length; i += 1) {
                this.handlers[i].detach();
            }
            this.handlers = [];
            this.binded = false;
        },
        showOverlay: function(widget) {
            var targetNode = widget.get(BOUNDINGBOX);
            this.overlayWidget = widget;
            this.highlightOverlay.show();
            this.highlightOverlay.get(BOUNDINGBOX)
                .setXY(targetNode.getXY())
                .setStyles({
                    width: targetNode.getDOMNode().offsetWidth,
                    height: targetNode.getDOMNode().offsetHeight
                });
        },
        fixedOverlay: function(widget) {
            var targetNode = widget.get(BOUNDINGBOX);
            if (!targetNode.getDOMNode()) {
                return;
            }
            this.shownOverlay.get(BOUNDINGBOX)
                .setXY(targetNode.getXY())
                .setStyles({
                    width: targetNode.getDOMNode().offsetWidth,
                    height: targetNode.getDOMNode().offsetHeight
                });
            this.shownOverlay.show();
            if (this.shownOverlay._widget && this.shownOverlay._widget._peDHandle) {
                this.shownOverlay._widget._peDHandle.detach();
                delete this.shownOverlay._widget._peDHandle;
            }
            this.shownOverlay._widget = widget;
            widget._peDHandle = widget.onceAfter("destroy", function(e) {
                if (e.target === this.shownOverlay._widget) {
                    this.shownOverlay._widget = null;
                    this.shownOverlay.hide();
                }
            }, this);
            this.showOverlay(widget);
        },
        hideOverlay: function() {
            this.overlayWidget = null;
            this.highlightOverlay && this.highlightOverlay.hide();
        },
        destructor: function() {
            if (!Wegas.Facade.Page.cache.isEditable()) {
                return;
            }

            this.detachHandlers();
            if (this.shownOverlay) {
                if (this.shownOverlay._widget && this.shownOverlay._widget._peDHandle) {
                    this.shownOverlay._widget._peDHandle.detach();
                    delete this.shownOverlay._widget._peDHandle;
                }
                this.shownOverlay.destroy(true);
            }
            if (this.highlightOverlay) {
                this.hideOverlay();
                this.highlightOverlay.destroy(true);
            }
            if (this.overlayMask) {
                this.overlayMask.destroy(true);
            }

            for (var i = 0; i < this.fixedHandlers.length; i += 1) {
                this.fixedHandlers[i].detach();
            }
            this.jsonView && this.jsonView.destroy();
        },
        _syncWidgetEdition: function(realWidget) {
            var widget = realWidget ?
                (Y.Plugin.EditEntityAction.currentEntity === realWidget ? realWidget : null) :
                (Y.Plugin.EditEntityAction.currentEntity === this.overlayWidget ? Y.Plugin.EditEntityAction.currentEntity : null);
            if (widget) {
                /*
                // This does not work anymore with Form 2.0:
                Y.Plugin.EditEntityAction.form.set("values", widget.toObject());
                Y.Plugin.EditEntityAction.form.syncUI();
                */
                // Simulate a renewed click on the same widget to regenerate the form:
                if (this.overlayMask.menu.getMenu().size() > 0) {
                    Y.later(10, this, function() {
                        this.overlayMask.menu.getMenu().item(0).fire("click");
                    });
                }
            }
        }
    }, {
        NS: "pageeditor",
        NAME: "pageeditor",
        inRegion: function(node, xy) {
            var region = Y.one(node).get("region");
            return xy[0] > region.left && xy[0] < (region.left + region.width) &&
                xy[1] > region.top && xy[1] < (region.top + region.height);
        }
    });
    Y.Base.mix(PageEditor, [Wegas.PageEditorDD, Wegas.PageEditorResize]);       //Enable dragdrop
    Y.Plugin.PageEditor = PageEditor;
});
<commit_msg>Page Editor "new" button<commit_after>/*
 * Wegas
 * http://wegas.albasim.ch
 *
 * Copyright (c) 2013-2018  School of Business and Engineering Vaud, Comem, MEI
 * Licensed under the MIT License
 */
/**
 * @author Francois-Xavier Aeberhard <fx@red-agent.com>,
 * Cyril Junod <cyril.junod at gmail.com>
 */
YUI.add('wegas-pageeditor', function(Y) {
    "use strict";

    var PageEditor, Wegas = Y.Wegas,
        BOUNDINGBOX = "boundingBox", CONTENTBOX = "contentBox",
        Alignable = Y.Base.create("wegas-pageeditor-overlay", Y.Widget, [Y.WidgetPosition, Y.WidgetStack], {}, {
            CSS_PREFIX: "wegas-pageeditor-overlay"
        });
    /**
     *  @class
     *  @name Y.Plugin.PageEditor
     *  @extends Y.Plugin.Base
     *  @constructor
     */
    PageEditor = function() {
        PageEditor.superclass.constructor.apply(this, arguments);
    };
    Y.extend(PageEditor, Y.Plugin.Base, {
        // *** Lifecycle methods *** //
        initializer: function() {
            this.handlers = [];
            this.fixedHandlers = [];
            /**
             * Store user enabled active edition
             */
            this.isActive = false;

            if (!Wegas.Facade.Page.cache.isEditable()) {
                Y.later(100, this.get("host"), function() {
                    this.unplug(PageEditor);
                });
            } else {
                this.afterHostEvent("render", this.render);
            }
        },
        render: function() {
            var host = this.get('host');
            if (host.toolbar) {
                /** Edit page  **/
                this.designButton = host.toolbar.add({
                    type: "ToggleButton",
                    label: "Edit page",
                    cssClass: "wegas-pageeditor-editbutton"
                }).item(0);
                this.designButton.after("pressedChange", function(e) {
                    host.get(BOUNDINGBOX).toggleClass("wegas-pageeditor-designmode", e.newVal);
                    this.sourceButton.set("visible", e.newVal);
                    this.layoutButton.set("visible", e.newVal);
                    this.addButton.set("visible", e.newVal);
                    //this.refreshButton.set("visible", e.newVal);
                    if (e.newVal) {
                        //Wegas.Facade.Page.cache.getIndex(function(index) {
                        //    var pageName = index[host.get("pageId")] !== ""
                        //            ? index[host.get("pageId")]
                        //            : "unamed(" + host.get("pageId") + ")";
                        //    host.toolbar.setStatusMessage("Editing page: " + pageName);
                        //});
                        this.bind();
                        host.get(CONTENTBOX).prepend(this.overlayMask);
                    } else {
                        this.detachHandlers();
                        host.toolbar.setStatusMessage("");
                        this.overlayMask.remove(false);
                        this.shownOverlay.hide();
                        this.layoutButton.set("pressed", false);
                    }
                }, this);

                /** New button **/
                this.addButton = host.toolbar.add({
                    label: " Add",
                    visible: false
                }).item(0);
                this.addButton.plug(Y.Plugin.WidgetMenu);
                this.addButton.menu.on("menuOpen", function() {
                    var menu = host.get("widget").getMenuCfg({
                        targetwidget: host.get("widget")
                    }), addElement = Y.Array.find(menu, function(o) {           /* search "Add" menu */
                        return o.label.indexOf("Add") > -1;
                    });
                    if (addElement) {
                        this.set("children", addElement.plugins[0].cfg.children);// And place it'
                    } else {
                        this.set("children", []);
                    }
                });

                /** Refresh **/
//                this.refreshButton = host.toolbar.add({
//                    label: "Refresh",
//                    cssClass: "wegas-advanced-feature"
//                }).item(0);
//                this.refreshButton.after("click", function(e) {
//                    this.get("host").reload();
//                }, this);

                this.layoutButton = host.toolbar.add({// Layout
                    type: "ToggleButton",
                    label: "Draw elements",
                    visible: false
                }).item(0);
                this.layoutButton.after("pressedChange", function(e) {
                    host.get(BOUNDINGBOX).toggleClass("wegas-pageeditor-layoutmode",
                        e.newVal);
                });

                /** Source view **/
                this.sourceButton = host.toolbar.add({
                    type: "ToggleButton",
                    label: "Source",
                    visible: false,
                    on: {
                        click: Y.bind(this.processSource, this)
                    }
                }).item(0);

                this.saveButton = host.toolbar.add({
                    label: "Save",
                    visible: false,
                    on: {
                        click: Y.bind(this.processSave, this)
                    }
                }).item(0);
            }
            this.fixedHandlers.push(this.afterHostEvent("contentUpdated", this.processSource));
            this.highlightOverlay = new Alignable({// Init the highlighting overlay
                zIndex: 30,
                render: true,
                visible: false
            });
            this.shownOverlay = new Alignable({// Init the highlighting overlay
                zIndex: 30,
                render: true,
                visible: false
            });
            this.shownOverlay.get(BOUNDINGBOX).addClass("pageditor-shownoverlay");
            this.highlightOverlay.get(CONTENTBOX).append("");
            this.shownOverlay.get(CONTENTBOX).append("");

            /** MASK **/
            this.overlayMask = new Y.Node.create("

");
            this.overlayMask.plug(Y.Plugin.WidgetMenu, {
                event: ["click", "contextmenu"]
            });
            this.overlayMask.menu.after("menuOpen", function(e) {
                this.fixedOverlay(this.overlayWidget);
            }, this);
            this.overlayMask.menu.getMenu().set("preventOverlap", false);
            this.overlayMask.append(this.shownOverlay.get(BOUNDINGBOX));
            this.overlayMask.append(this.highlightOverlay.get(BOUNDINGBOX));
            this.fixedHandlers.push(this.doBefore("pageIdChange", function(e) {
                if (this.get("host") === e.target) {
                    this.isActive = this.isActive || this.designButton.get("pressed");
                    this.designButton.set("pressed", false);
                }
            }));
            this.fixedHandlers.push(this.doAfter("contentUpdated", function(e) {
                this.designButton.set("pressed", this.isActive);
                this.isActive = false;
            }));
            this.fixedHandlers.push(host.get(CONTENTBOX).after("mouseout", function(e) {
                if (!PageEditor.inRegion(e.currentTarget, [e.clientX, e.clientY])) {
                    this.hideOverlay();
                }
            }, this));

            host.get(CONTENTBOX).plug(Y.Plugin.ScrollInfo);
            this.fixedHandlers.push(host.get(CONTENTBOX).scrollInfo.on("*:scroll", function(e) {
                this.overlayMask.setStyles({top: e.scrollTop, left: e.scrollLeft});
                if (this.shownOverlay._widget) {
                    this.fixedOverlay(this.shownOverlay._widget);
                }
            }, this));
        },
        bind: function() {
            if (this.binded) {
                return;
            }
            this.binded = true;
            this.handlers.push(this.overlayMask.on("mousemove", function(e) {
                var widget, vis = this.shownOverlay.get("visible");

                e.halt(true);
                this.overlayMask.hide();
                this.highlightOverlay.hide();
                this.shownOverlay.hide();
                widget = Y.Widget.getByNode(Y.Node(window.document.elementFromPoint(e.clientX, e.clientY)).ancestor(".wegas-widget-editable", true));//Find a parent Wegas widget or self
                this.overlayMask.show();
                if (vis) {
                    this.shownOverlay.show();
                }
                if (this.get("host") === widget || widget === null) {
                    return;
                }
                if (widget !== this.overlayWidget) {
                    this.showOverlay(widget);
                } else {
                    this.highlightOverlay.show();
                }
            }, this));
            this.handlers.push(this.overlayMask.menu.on("menuOpen", function(e) {
                if (PageEditor.inRegion(this.shownOverlay.get(CONTENTBOX).one(".wegas-editmenubutton-icon"), [e.domEvent.clientX, e.domEvent.clientY])) { /* Clicked editmenu */
                    this.targetWidget = this.shownOverlay._widget;
                    this.overlayMask.menu.set("children", this.targetWidget.getMenuCfg());
                    this.overlayMask.menu.menu.set("xy", [e.domEvent.clientX, e.domEvent.clientY]);
                    e.halt(true);
                } else if (e.domEvent.type === "contextmenu") {
                    this.targetWidget = this.overlayWidget;
                    this.overlayMask.menu.set("children", this.targetWidget.getMenuCfg());
                    if (this.overlayMask.menu.getMenu().size() > 0) {
                        this.overlayMask.menu.getMenu().item(0).fire("click");
                    }
                    this.overlayMask.menu.menu.set("xy", [e.domEvent.clientX, e.domEvent.clientY]);
                } else {                                                        /* Clicked widget*/
                    this.targetWidget = this.overlayWidget;
                    this.overlayMask.menu.set("children", this.targetWidget.getMenuCfg({
                        widget: this.targetWidget
                    }));
                    this.overlayMask.menu.menu.hide();
                    if (this.overlayMask.menu.getMenu().size() > 0) {
                        this.overlayMask.menu.getMenu().item(0).fire("click");
                    }
                }
            }, this));
            this.handlers.push(Wegas.app.after("layout:resize", function(e) {
                if (this.targetWidget) {
                    this.fixedOverlay(this.targetWidget);
                }
            }, this));
        },
        processSave: function() {
            var host = this.get("host"),
                page;
            try {
                page = Y.JSON.parse(this.jsonView.getValue());
                page["@pageId"] = this.get("host").get("pageId");
            } catch (ex) {
                Y.Widget.getByNode(host.get(BOUNDINGBOX).get("parentNode")).showMessage("error", ex.toString());
                return;
            }
            this.sourceButton.set("pressed", false);
            host.get(CONTENTBOX).show();
            this.jsonView.hide();
            this.designButton.enable();
            this.saveButton.hide();
            host.showOverlay();
            Wegas.Facade.Page.cache.patch(page, Y.bind(function() {
                host.hideOverlay();
                this.reload();
            }, host));
        },
        saveCurrentPage: function() {
            var page = this.get("host").get("widget").toObject();
            page["@pageId"] = this.get("host").get("widget")["@pageId"];
            Wegas.Facade.Page.cache.patch(page);
        },
        processSource: function() {
            var host = this.get("host");
            if (this.sourceButton.get("pressed")) {
                if (!this.jsonView) {
                    this.initJsonView();
                    return;
                }
                this.jsonView.setValue(host.get("widgetCfg"));
                host.get(CONTENTBOX).hide();
                this.jsonView.show();
                this.jsonView.editor.resize();
                this.jsonView.focus();
                this.designButton.disable();
                this.saveButton.show();
            } else {
                host.get(CONTENTBOX).show();
                if (this.jsonView) {
                    this.jsonView.hide();
                }
                this.designButton.enable();
                this.saveButton.hide();
            }
        },
        initJsonView: function() {
            if (!this.jsonView) {
                Y.use("wegas-inputex-ace", Y.bind(function(Y) {
                    this.jsonView = new Y.inputEx.AceField({
                        parentEl: this.get("host").get(BOUNDINGBOX),
                        name: 'text',
                        type: 'ace',
                        height: "100%",
                        language: "json",
                        value: '',
                        wrapperClass: "wegas-pageeditor-ace"
                    });
                    this.jsonView.hide();
                    this.processSource();
                }, this));
            }
        },
        detachHandlers: function() {
            for (var i = 0; i < this.handlers.length; i += 1) {
                this.handlers[i].detach();
            }
            this.handlers = [];
            this.binded = false;
        },
        showOverlay: function(widget) {
            var targetNode = widget.get(BOUNDINGBOX);
            this.overlayWidget = widget;
            this.highlightOverlay.show();
            this.highlightOverlay.get(BOUNDINGBOX)
                .setXY(targetNode.getXY())
                .setStyles({
                    width: targetNode.getDOMNode().offsetWidth,
                    height: targetNode.getDOMNode().offsetHeight
                });
        },
        fixedOverlay: function(widget) {
            var targetNode = widget.get(BOUNDINGBOX);
            if (!targetNode.getDOMNode()) {
                return;
            }
            this.shownOverlay.get(BOUNDINGBOX)
                .setXY(targetNode.getXY())
                .setStyles({
                    width: targetNode.getDOMNode().offsetWidth,
                    height: targetNode.getDOMNode().offsetHeight
                });
            this.shownOverlay.show();
            if (this.shownOverlay._widget && this.shownOverlay._widget._peDHandle) {
                this.shownOverlay._widget._peDHandle.detach();
                delete this.shownOverlay._widget._peDHandle;
            }
            this.shownOverlay._widget = widget;
            widget._peDHandle = widget.onceAfter("destroy", function(e) {
                if (e.target === this.shownOverlay._widget) {
                    this.shownOverlay._widget = null;
                    this.shownOverlay.hide();
                }
            }, this);
            this.showOverlay(widget);
        },
        hideOverlay: function() {
            this.overlayWidget = null;
            this.highlightOverlay && this.highlightOverlay.hide();
        },
        destructor: function() {
            if (!Wegas.Facade.Page.cache.isEditable()) {
                return;
            }

            this.detachHandlers();
            if (this.shownOverlay) {
                if (this.shownOverlay._widget && this.shownOverlay._widget._peDHandle) {
                    this.shownOverlay._widget._peDHandle.detach();
                    delete this.shownOverlay._widget._peDHandle;
                }
                this.shownOverlay.destroy(true);
            }
            if (this.highlightOverlay) {
                this.hideOverlay();
                this.highlightOverlay.destroy(true);
            }
            if (this.overlayMask) {
                this.overlayMask.destroy(true);
            }

            for (var i = 0; i < this.fixedHandlers.length; i += 1) {
                this.fixedHandlers[i].detach();
            }
            this.jsonView && this.jsonView.destroy();
        },
        _syncWidgetEdition: function(realWidget) {
            var widget = realWidget ?
                (Y.Plugin.EditEntityAction.currentEntity === realWidget ? realWidget : null) :
                (Y.Plugin.EditEntityAction.currentEntity === this.overlayWidget ? Y.Plugin.EditEntityAction.currentEntity : null);
            if (widget) {
                /*
                // This does not work anymore with Form 2.0:
                Y.Plugin.EditEntityAction.form.set("values", widget.toObject());
                Y.Plugin.EditEntityAction.form.syncUI();
                */
                // Simulate a renewed click on the same widget to regenerate the form:
                if (this.overlayMask.menu.getMenu().size() > 0) {
                    Y.later(10, this, function() {
                        this.overlayMask.menu.getMenu().item(0).fire("click");
                    });
                }
            }
        }
    }, {
        NS: "pageeditor",
        NAME: "pageeditor",
        inRegion: function(node, xy) {
            var region = Y.one(node).get("region");
            return xy[0] > region.left && xy[0] < (region.left + region.width) &&
                xy[1] > region.top && xy[1] < (region.top + region.height);
        }
    });
    Y.Base.mix(PageEditor, [Wegas.PageEditorDD, Wegas.PageEditorResize]);       //Enable dragdrop
    Y.Plugin.PageEditor = PageEditor;
});
<|endoftext|>