<commit_before>/**
 * Game Controller
 */
function GameController()
{
    var controller = this;

    this.games = new Collection([], 'name');

    this.onDie         = this.onDie.bind(this);
    this.onAngle       = this.onAngle.bind(this);
    this.onPosition    = this.onPosition.bind(this);
    this.onBonusPop    = this.onBonusPop.bind(this);
    this.onBonusClear  = this.onBonusClear.bind(this);
    this.onPrinting    = this.onPrinting.bind(this);
    this.onPoint       = this.onPoint.bind(this);
    this.onScore       = this.onScore.bind(this);
    this.onTrailClear  = this.onTrailClear.bind(this);
    this.onRoundNew    = this.onRoundNew.bind(this);
    this.onRoundEnd    = this.onRoundEnd.bind(this);
    this.onRoundWinner = this.onRoundWinner.bind(this);
    this.onEnd         = this.onEnd.bind(this);

    this.callbacks = {
        onGameLoaded: function () { controller.onGameLoaded(this); },
        onMove: function (data) { controller.onMove(this, data); },
    };
}

/**
 * Add game
 *
 * @param {Game} game
 */
GameController.prototype.addGame = function(game)
{
    if (this.games.add(game)) {
        game.on('round:new', this.onRoundNew);
        game.on('round:end', this.onRoundEnd);
        game.on('round:winner', this.onRoundWinner);

        game.bonusManager.on('bonus:pop', this.onBonusPop);
        game.bonusManager.on('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.attach(game.clients.items[i], game);
        }
    }
};

/**
 * Remove game
 *
 * @param {Game} game
 */
GameController.prototype.removeGame = function(game)
{
    if (this.games.remove(game)) {
        game.removeListener('end', this.onEnd);
        game.removeListener('round:new', this.onRoundNew);
        game.removeListener('round:end', this.onRoundEnd);
        game.removeListener('round:winner', this.onRoundWinner);
        game.bonusManager.removeListener('bonus:pop', this.onBonusPop);
        game.bonusManager.removeListener('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.detach(game.clients.items[i], game);
        }
    }
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attach = function(client, game)
{
    this.attachEvents(client);
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detach = function(client)
{
    this.detachEvents(client);

    var avatar;

    if (client.room.game) {
        for (var i = client.players.items.length - 1; i >= 0; i--) {
            avatar = client.players.items[i].avatar;
            client.room.game.client.addEvent('game:leave', {avatar: avatar.name});
            client.room.game.removeAvatar(avatar);
        }
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attachEvents = function(client)
{
    var controller = this,
        avatar;

    client.on('loaded', this.callbacks.onGameLoaded);
    client.on('player:move', this.callbacks.onMove);

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.on('die', this.onDie);
        avatar.on('angle', this.onAngle);
        avatar.on('position', this.onPosition);
        avatar.on('velocity:up', this.onVelocityUp);
        avatar.on('velocity:down', this.onVelocityDown);
        avatar.on('printing', this.onPrinting);
        avatar.on('point', this.onPoint);
        avatar.on('score', this.onScore);
        avatar.trail.on('clear', this.onTrailClear);
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detachEvents = function(client)
{
    var avatar;

    client.removeListener('loaded', this.callbacks.onGameLoaded);
    client.removeListener('player:move', this.callbacks.onMove);

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.removeListener('die', this.onDie);
        avatar.removeListener('angle', this.onAngle);
        avatar.removeListener('position', this.onPosition);
        avatar.removeListener('printing', this.onPrinting);
        avatar.removeListener('point', this.onPoint);
        avatar.removeListener('score', this.onScore);
        avatar.removeListener('velocity:up', this.onVelocityUp);
        avatar.removeListener('velocity:down', this.onVelocityDown);
        avatar.trail.removeListener('clear', this.onTrailClear);
    }
};

/**
 * On game loaded
 *
 * @param {SocketClient} client
 */
GameController.prototype.onGameLoaded = function(client)
{
    var game = client.room.game,
        avatar;

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;
        avatar.ready = true;
    }

    if (game.isReady()) {
        game.newRound();
    }
};

/**
 * On move
 *
 * @param {SocketClient} client
 * @param {Number} move
 */
GameController.prototype.onMove = function(client, data)
{
    var player = client.players.getById(data.avatar);

    if (player && player.avatar) {
        player.avatar.setAngularVelocity(data.move);
    }
};

/**
 * On position
 *
 * @param {Object} data
 */
GameController.prototype.onPosition = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        point = data.point;

    game.client.addEvent('position', {avatar: avatar.name, point: point});
};

/**
 * On printing
 *
 * @param {Object} data
 */
GameController.prototype.onPrinting = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        printing = data.printing;

    game.client.addEvent('printing', {avatar: avatar.name, printing: printing});
};

/**
 * On angle
 *
 * @param {Object} data
 */
GameController.prototype.onAngle = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        angle = data.angle;

    if(!avatar.player.client.room.game.isPlaying()) {
        game.client.addEvent('angle', {avatar: avatar.name, angle: angle});
    }
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onPoint = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        point = data.point;

    if (data.important) {
        game.client.addEvent('point', {avatar: avatar.name, point: point});
    }
};

/**
 * On die
 *
 * @param {Object} data
 */
GameController.prototype.onDie = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game;

    game.client.addEvent('die', {avatar: avatar.name});
};

/**
 *
 * @param {SocketClient} client
 */
GameController.prototype.onVelocityUp = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel;

    game.client.addEvent('die', {avatar: avatar.name});
};

/**
 *
 * @param {SocketClient} client
 */
GameController.prototype.onVelocityDown = function(data)
{
    var avatar = data.avatar,
        channel = avatar.player.client.room.game.channel;

    game.client.addEvent('velocity:down', {avatar: avatar.name});
};

/**
 * On bonus pop
 *
 * @param {SocketClient} game
 */
GameController.prototype.onBonusPop = function(data)
{
    var game = data.game,
        channel = data.game.channel;

    game.client.addEvent('bonus:pop', data.bonus.serialize());
};

/**
 * On bonus clear
 *
 * @param {SocketClient}client
 * @param data
 */
GameController.prototype.onBonusClear = function(data)
{
    var game = data.game,
        channel = data.game.channel;

    game.client.addEvent('bonus:clear', data.bonus.serialize());
};

/**
 * On score
 *
 * @param {Object} data
 */
GameController.prototype.onScore = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        score = data.score;

    game.client.addEvent('score', {avatar: avatar.name, score: score});
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onTrailClear = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game;

    game.client.addEvent('trail:clear', {avatar: avatar.name});
};

// Game events:

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundNew = function(data)
{
    data.game.client.addEvent('round:new');
};

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundEnd = function(data)
{
    data.game.client.addEvent('round:end');
};

/**
 * On round winner
 *
 * @param {Object} data
 */
GameController.prototype.onRoundWinner = function(data)
{
    data.game.client.addEvent('round:winner', {winner: data.winner.name});
};

/**
 * On end
 *
 * @param {Object} data
 */
GameController.prototype.onEnd = function(data)
{
    data.game.client.addEvent('end');
};
<commit_msg>remove unecessary velocity client methods<commit_after>/**
 * Game Controller
 */
function GameController()
{
    var controller = this;

    this.games = new Collection([], 'name');

    this.onDie         = this.onDie.bind(this);
    this.onAngle       = this.onAngle.bind(this);
    this.onPosition    = this.onPosition.bind(this);
    this.onBonusPop    = this.onBonusPop.bind(this);
    this.onBonusClear  = this.onBonusClear.bind(this);
    this.onPrinting    = this.onPrinting.bind(this);
    this.onPoint       = this.onPoint.bind(this);
    this.onScore       = this.onScore.bind(this);
    this.onTrailClear  = this.onTrailClear.bind(this);
    this.onRoundNew    = this.onRoundNew.bind(this);
    this.onRoundEnd    = this.onRoundEnd.bind(this);
    this.onRoundWinner = this.onRoundWinner.bind(this);
    this.onEnd         = this.onEnd.bind(this);

    this.callbacks = {
        onGameLoaded: function () { controller.onGameLoaded(this); },
        onMove: function (data) { controller.onMove(this, data); },
    };
}

/**
 * Add game
 *
 * @param {Game} game
 */
GameController.prototype.addGame = function(game)
{
    if (this.games.add(game)) {
        game.on('round:new', this.onRoundNew);
        game.on('round:end', this.onRoundEnd);
        game.on('round:winner', this.onRoundWinner);

        game.bonusManager.on('bonus:pop', this.onBonusPop);
        game.bonusManager.on('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.attach(game.clients.items[i], game);
        }
    }
};

/**
 * Remove game
 *
 * @param {Game} game
 */
GameController.prototype.removeGame = function(game)
{
    if (this.games.remove(game)) {
        game.removeListener('end', this.onEnd);
        game.removeListener('round:new', this.onRoundNew);
        game.removeListener('round:end', this.onRoundEnd);
        game.removeListener('round:winner', this.onRoundWinner);
        game.bonusManager.removeListener('bonus:pop', this.onBonusPop);
        game.bonusManager.removeListener('bonus:clear', this.onBonusClear);

        for (var i = game.clients.items.length - 1; i >= 0; i--) {
            this.detach(game.clients.items[i], game);
        }
    }
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attach = function(client, game)
{
    this.attachEvents(client);
};

/**
 * Attach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detach = function(client)
{
    this.detachEvents(client);

    var avatar;

    if (client.room.game) {
        for (var i = client.players.items.length - 1; i >= 0; i--) {
            avatar = client.players.items[i].avatar;
            client.room.game.client.addEvent('game:leave', {avatar: avatar.name});
            client.room.game.removeAvatar(avatar);
        }
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.attachEvents = function(client)
{
    var controller = this,
        avatar;

    client.on('loaded', this.callbacks.onGameLoaded);
    client.on('player:move', this.callbacks.onMove);

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.on('die', this.onDie);
        avatar.on('angle', this.onAngle);
        avatar.on('position', this.onPosition);
        avatar.on('printing', this.onPrinting);
        avatar.on('point', this.onPoint);
        avatar.on('score', this.onScore);
        avatar.trail.on('clear', this.onTrailClear);
    }
};

/**
 * Detach events
 *
 * @param {SocketClient} client
 */
GameController.prototype.detachEvents = function(client)
{
    var avatar;

    client.removeListener('loaded', this.callbacks.onGameLoaded);
    client.removeListener('player:move', this.callbacks.onMove);

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;

        avatar.removeListener('die', this.onDie);
        avatar.removeListener('angle', this.onAngle);
        avatar.removeListener('position', this.onPosition);
        avatar.removeListener('printing', this.onPrinting);
        avatar.removeListener('point', this.onPoint);
        avatar.removeListener('score', this.onScore);
        avatar.trail.removeListener('clear', this.onTrailClear);
    }
};

/**
 * On game loaded
 *
 * @param {SocketClient} client
 */
GameController.prototype.onGameLoaded = function(client)
{
    var game = client.room.game,
        avatar;

    for (var i = client.players.items.length - 1; i >= 0; i--) {
        avatar = client.players.items[i].avatar;
        avatar.ready = true;
    }

    if (game.isReady()) {
        game.newRound();
    }
};

/**
 * On move
 *
 * @param {SocketClient} client
 * @param {Number} move
 */
GameController.prototype.onMove = function(client, data)
{
    var player = client.players.getById(data.avatar);

    if (player && player.avatar) {
        player.avatar.setAngularVelocity(data.move);
    }
};

/**
 * On position
 *
 * @param {Object} data
 */
GameController.prototype.onPosition = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        point = data.point;

    game.client.addEvent('position', {avatar: avatar.name, point: point});
};

/**
 * On printing
 *
 * @param {Object} data
 */
GameController.prototype.onPrinting = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        printing = data.printing;

    game.client.addEvent('printing', {avatar: avatar.name, printing: printing});
};

/**
 * On angle
 *
 * @param {Object} data
 */
GameController.prototype.onAngle = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        angle = data.angle;

    if(!avatar.player.client.room.game.isPlaying()) {
        game.client.addEvent('angle', {avatar: avatar.name, angle: angle});
    }
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onPoint = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        point = data.point;

    if (data.important) {
        game.client.addEvent('point', {avatar: avatar.name, point: point});
    }
};

/**
 * On die
 *
 * @param {Object} data
 */
GameController.prototype.onDie = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game;

    game.client.addEvent('die', {avatar: avatar.name});
};

/**
 * On bonus pop
 *
 * @param {SocketClient} game
 */
GameController.prototype.onBonusPop = function(data)
{
    var game = data.game, bonus = data.bonus;

    game.client.addEvent('bonus:pop', bonus.serialize());
};

/**
 * On bonus clear
 *
 * @param {SocketClient}client
 * @param data
 */
GameController.prototype.onBonusClear = function(data)
{
    var game = data.game, bonus = data.bonus;

    game.client.addEvent('bonus:clear', bonus.serialize());
};

/**
 * On score
 *
 * @param {Object} data
 */
GameController.prototype.onScore = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game,
        score = data.score;

    game.client.addEvent('score', {avatar: avatar.name, score: score});
};

/**
 * On point
 *
 * @param {Object} data
 */
GameController.prototype.onTrailClear = function(data)
{
    var avatar = data.avatar,
        game = avatar.player.client.room.game;

    game.client.addEvent('trail:clear', {avatar: avatar.name});
};

// Game events:

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundNew = function(data)
{
    data.game.client.addEvent('round:new');
};

/**
 * On round new
 *
 * @param {Object} data
 */
GameController.prototype.onRoundEnd = function(data)
{
    data.game.client.addEvent('round:end');
};

/**
 * On round winner
 *
 * @param {Object} data
 */
GameController.prototype.onRoundWinner = function(data)
{
    data.game.client.addEvent('round:winner', {winner: data.winner.name});
};

/**
 * On end
 *
 * @param {Object} data
 */
GameController.prototype.onEnd = function(data)
{
    data.game.client.addEvent('end');
};
<|endoftext|>


<commit_before>// Author: Daniel G (oscar-daniel.gonzalez@hp.com)

new class Tridion_Ext
{
  constructor()
  {
    this._v = 1.0;
    this.ctx_menu = document.querySelector("#DashboardContextMenu");
    this.dashboard_tree = document.querySelector("#DashboardTree iframe");
    this.dashboard_list = document.querySelector("#FilteredDashboardList");
    this.publications_refs = [];
    this.list_lvls = [];
    this.list_items = [];
    this.items = [];
    this.lvls = [];

    this.init();
  }

  init()
  {
    console.debug("Tridion Extension v"+ this._v +", made by Daniel G [oscar-daniel.gonzalez@hp.com]");
    var _self = this;

      this.publications_refs = this.dashboard_tree.contentDocument.querySelectorAll("div.rootNode.populated div.children div.node");

      this.publications_refs
        .forEach(function(publication)
        {
          var id = publication.id.split(':')[1].split('-')[1];
          var lvl = publication.querySelector(".header .title").title;
          lvl = lvl.slice(0, lvl.indexOf(" ("));  // lvl   remove what is between parenthesis
          _self.lvls[id] = unescape(lvl);
        });

    this.add_actions();
    this.add_observers();
  }

/* Actions*/
  enable_pro_publishing()
  {
    var _self = this;
    this.pro_publishing = document.createElement("li");
    this.pro_publishing.className  = "item Publish";
    this.pro_publishing.id = "improved_sel_publish";

    var pro_publishing_div = document.createElement("div");
    pro_publishing_div.className = "image";
    pro_publishing_div.setAttribute("unselectable", "on");

    var pro_publishing_span = document.createElement("span");
    pro_publishing_span.innerHTML = "Automated Publishing";

    this.pro_publishing.appendChild(pro_publishing_div);
    this.pro_publishing.appendChild(pro_publishing_span);

    this.pro_publishing.onmouseover = function()
    {
      Tridion.Controls.ContextMenu.prototype._hightlightItem(this)
    };

    this.pro_publishing.onclick = function()
    {
      console.log("Publishing items");
    }

    this.ctx_menu.appendChild(this.pro_publishing);
  }

  enable_open_mult_items()
  {
    var _self = this;
    this.mult_open = document.createElement("li");
    this.mult_open.className  = "item Open";
    this.mult_open.id = "open_mult_items";

    var mult_open_div = document.createElement("div");
    mult_open_div.className = "image";
    mult_open_div.setAttribute("unselectable", "on");

    var mult_open_span = document.createElement("span");
    mult_open_span.innerHTML = "Open selected items";

    this.mult_open.appendChild(mult_open_div);
    this.mult_open.appendChild(mult_open_span);

    this.mult_open.onmouseover = function()
    {
      Tridion.Controls.ContextMenu.prototype._hightlightItem(this)
    };

    this.mult_open.onclick = function()
    {
      this.update_frame_items();              // quick fix for
      if(_self.items.length == 0) return;
      var sel_items = _self.items.querySelectorAll("tr.selected");

      sel_items
        .forEach(function(item)
        {
          if(item.type == 16)  // component
          {
            console.log("Opening tcm"+ item.tcm_id + " from " + _self.lvls[item.lvl]);
            var url_base = "https://epocms.www8.hp.com/WebUI/item.aspx?tcm=16#id=tcm:"+item.lvl+"-"+item.tcm_id;
            window.postMessage({action: "open_item", url: url_base}, "*");    // send a message to background to handle request
          }
          else        // everything else
          {
            console.error("Type not supported yet :P");
          }
        });
      // Tridion does not support double click trigger on folder
    }

    this.ctx_menu.appendChild(this.mult_open);
  }

/* Storage */
  get_localStorage()
  {
  }

  update_frame_items()
  {
    this.frame_items = document.querySelector("#FilteredItemsList_frame_details");
    this.items = this.frame_items.contentWindow.document.querySelector("table");
    this.process_items();
  }

/* Wrappers */
  observer_wr(target, config, callback)
  {
    var observer = new MutationObserver(callback);
    observer.observe(target, config);
    return function removeElementChange() {
        observer.disconnect();
    };
  }

/* Main Functions */
  add_actions()
  {
    var sep = document.createElement("li");
    sep.className = "separator";
    this.ctx_menu.appendChild(sep);

    this.enable_pro_publishing();
    this.enable_open_mult_items();
  }

  add_observers()
  {
    var _self = this;

    this.observer_wr(
      this.dashboard_list, { subtree: true, childList: true},function()
      {
        _self.list_items = document.querySelector("#FilteredItemsList_frame_details");
        if(_self.list_items != null)
        {
          _self.list_items.addEventListener("load",function()
          {
            if(this.contentWindow.document.body.innerText == "") return;
            _self.update_frame_items();
          });
          this.disconnect();
        }
      });
  }

  process_items()
  {
    var _self = this;
    this.items.querySelectorAll("tr.item")
      .forEach(function(row)
      {
        var cols = row.querySelectorAll("td");
        var item_lvl = cols[3].querySelector("div");
        var txt_lvl = _self.unicode_to_ascii(item_lvl.innerText);
        row.tcm_id = row.id.split(':')[1].split('-')[1];
        row.type = cols[2].getAttribute("value");
        row.lvl = _self.get_id_by_lvl(txt_lvl);
      });
  }

/* UTILS */
  get_id_by_lvl(lvl)
  {
    return this.lvls.indexOf(lvl);
  }

  unicode_to_ascii(str)
  {
    var out = "";
    for (var i = 0; i < str.length; i++) {
        out += String.fromCharCode(str.charCodeAt(i) % 128);
    }
    return out;
  }
};<commit_msg>fixed this reference to _self<commit_after>// Author: Daniel G (oscar-daniel.gonzalez@hp.com)

new class Tridion_Ext
{
  constructor()
  {
    this._v = 1.0;
    this.ctx_menu = document.querySelector("#DashboardContextMenu");
    this.dashboard_tree = document.querySelector("#DashboardTree iframe");
    this.dashboard_list = document.querySelector("#FilteredDashboardList");
    this.publications_refs = [];
    this.list_lvls = [];
    this.list_items = [];
    this.items = [];
    this.lvls = [];

    this.init();
  }

  init()
  {
    console.debug("Tridion Extension v"+ this._v +", made by Daniel G [oscar-daniel.gonzalez@hp.com]");
    var _self = this;

      this.publications_refs = this.dashboard_tree.contentDocument.querySelectorAll("div.rootNode.populated div.children div.node");

      this.publications_refs
        .forEach(function(publication)
        {
          var id = publication.id.split(':')[1].split('-')[1];
          var lvl = publication.querySelector(".header .title").title;
          lvl = lvl.slice(0, lvl.indexOf(" ("));  // lvl   remove what is between parenthesis
          _self.lvls[id] = unescape(lvl);
        });

    this.add_actions();
    this.add_observers();
  }

/* Actions*/
  enable_pro_publishing()
  {
    var _self = this;
    this.pro_publishing = document.createElement("li");
    this.pro_publishing.className  = "item Publish";
    this.pro_publishing.id = "improved_sel_publish";

    var pro_publishing_div = document.createElement("div");
    pro_publishing_div.className = "image";
    pro_publishing_div.setAttribute("unselectable", "on");

    var pro_publishing_span = document.createElement("span");
    pro_publishing_span.innerHTML = "Automated Publishing";

    this.pro_publishing.appendChild(pro_publishing_div);
    this.pro_publishing.appendChild(pro_publishing_span);

    this.pro_publishing.onmouseover = function()
    {
      Tridion.Controls.ContextMenu.prototype._hightlightItem(this)
    };

    this.pro_publishing.onclick = function()
    {
      console.log("Publishing items");
    }

    this.ctx_menu.appendChild(this.pro_publishing);
  }

  enable_open_mult_items()
  {
    var _self = this;
    this.mult_open = document.createElement("li");
    this.mult_open.className  = "item Open";
    this.mult_open.id = "open_mult_items";

    var mult_open_div = document.createElement("div");
    mult_open_div.className = "image";
    mult_open_div.setAttribute("unselectable", "on");

    var mult_open_span = document.createElement("span");
    mult_open_span.innerHTML = "Open selected items";

    this.mult_open.appendChild(mult_open_div);
    this.mult_open.appendChild(mult_open_span);

    this.mult_open.onmouseover = function()
    {
      Tridion.Controls.ContextMenu.prototype._hightlightItem(this)
    };

    this.mult_open.onclick = function()
    {
      _self.update_frame_items();              // quick fix for
      if(_self.items.length == 0) return;
      var sel_items = _self.items.querySelectorAll("tr.selected");

      sel_items
        .forEach(function(item)
        {
          if(item.type == 16)  // component
          {
            console.log("Opening tcm"+ item.tcm_id + " from " + _self.lvls[item.lvl]);
            var url_base = "https://epocms.www8.hp.com/WebUI/item.aspx?tcm=16#id=tcm:"+item.lvl+"-"+item.tcm_id;
            window.postMessage({action: "open_item", url: url_base}, "*");    // send a message to background to handle request
          }
          else        // everything else
          {
            console.error("Type not supported yet :P");
          }
        });
      // Tridion does not support double click trigger on folder
    }

    this.ctx_menu.appendChild(this.mult_open);
  }

/* Storage */
  get_localStorage()
  {
  }

  update_frame_items()
  {
    this.frame_items = document.querySelector("#FilteredItemsList_frame_details");
    this.items = this.frame_items.contentWindow.document.querySelector("table");
    this.process_items();
  }

/* Wrappers */
  observer_wr(target, config, callback)
  {
    var observer = new MutationObserver(callback);
    observer.observe(target, config);
    return function removeElementChange() {
        observer.disconnect();
    };
  }

/* Main Functions */
  add_actions()
  {
    var sep = document.createElement("li");
    sep.className = "separator";
    this.ctx_menu.appendChild(sep);

    this.enable_pro_publishing();
    this.enable_open_mult_items();
  }

  add_observers()
  {
    var _self = this;

    this.observer_wr(
      this.dashboard_list, { subtree: true, childList: true},function()
      {
        _self.list_items = document.querySelector("#FilteredItemsList_frame_details");
        if(_self.list_items != null)
        {
          _self.list_items.addEventListener("load",function()
          {
            if(this.contentWindow.document.body.innerText == "") return;
            _self.update_frame_items();
          });
          this.disconnect();
        }
      });
  }

  process_items()
  {
    var _self = this;
    this.items.querySelectorAll("tr.item")
      .forEach(function(row)
      {
        var cols = row.querySelectorAll("td");
        var item_lvl = cols[3].querySelector("div");
        var txt_lvl = _self.unicode_to_ascii(item_lvl.innerText);
        row.tcm_id = row.id.split(':')[1].split('-')[1];
        row.type = cols[2].getAttribute("value");
        row.lvl = _self.get_id_by_lvl(txt_lvl);
      });
  }

/* UTILS */
  get_id_by_lvl(lvl)
  {
    return this.lvls.indexOf(lvl);
  }

  unicode_to_ascii(str)
  {
    var out = "";
    for (var i = 0; i < str.length; i++) {
        out += String.fromCharCode(str.charCodeAt(i) % 128);
    }
    return out;
  }
};<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////////
/**
 * @module ogs.vgl
 */

/*jslint devel: true, forin: true, newcap: true, plusplus: true*/
/*jslint white: true, continue:true, indent: 2*/

/*global vglModule, ogs, vec4, inherit, $*/
//////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class uniform
 *
 * @param type
 * @param name
 * @returns {vglModule.uniform} OpenGL uniform encapsulation
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.uniform = function(type, name) {
  'use strict';

  if (!(this instanceof vglModule.uniform)) {
    return new vglModule.uniform();
  }

  this.getTypeNumberOfComponents = function(type) {
    switch (type) {
      case gl.FLOAT:
      case gl.INT:
      case gl.BOOL:
        return 1;

      case gl.FLOAT_VEC2:
      case gl.INT_VEC2:
      case gl.BOOL_VEC2:
        return 2;

      case gl.FLOAT_VEC2:
      case gl.INT_VEC2:
      case gl.FLOAT_VEC3:
        return 3;

      case gl.FLOAT_VEC4:
      case gl.INT_VEC4:
      case gl.BOOL_VEC4:
        return 4;

      case gl.FLOAT_MAT3:
        return 9;

      case gl.FLOAT_MAT4:
        return 16;

      default:
        return 0;
    }
  };

  var m_type = type,
      m_name = name,
      m_dataArray = [ this.getTypeNumberOfComponents(m_type) ],
      m_numberOfElements = 1;

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Get name of the uniform
   *
   * @returns {*}
   */
  /////////////////////////////////////////////////////////////////////////////
  this.name = function() {
    return m_name;
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Get type of the uniform
   *
   * @returns {*}
   */
  /////////////////////////////////////////////////////////////////////////////
  this.type = function() {
    return m_type;
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Get value of the uniform
   *
   * @returns {Array}
   */
  /////////////////////////////////////////////////////////////////////////////
  this.get = function() {
    return m_dataArray;
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Set value of the uniform
   *
   * @param value
   */
  /////////////////////////////////////////////////////////////////////////////
  this.set = function(value) {
    var i = 0;
    if (value instanceof mat4.constructor) {
      for (i = 0; i < 16; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof mat3.constructor) {
      for (i = 0; i < 9; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof vec4.constructor) {
      for (i = 0; i < 4; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof vec3.constructor) {
      for (i = 0; i < 3; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof vec2.constructor) {
      for (i = 0; i < 2; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else {
      m_dataArray[0] = value;
    }
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Call GL and pass updated values to the current shader
   *
   * @param location
   */
  /////////////////////////////////////////////////////////////////////////////
  this.callGL = function(location) {
    if (this.m_numberElements < 1) {
      return;
    }

    switch (m_type) {
      case gl.BOOL:
      case gl.INT:
        gl.uniform1iv(location, m_dataArray);
        break;
      case gl.FLOAT:
        gl.uniform1fv(location, m_dataArray);
        break;
      case gl.FLOAT_VEC2:
        gl.uniform2fv(location, m_dataArray);
        break;
      case gl.FLOAT_VEC3:
        gl.uniform3fv(location, m_dataArray);
        break;
      case gl.FLOAT_VEC4:
        gl.uniform4fv(location, m_dataArray);
        break;
      case gl.FLOAT_MAT3:
        gl.uniformMatrix3fv(location, gl.FALSE, m_dataArray);
        break;
      case gl.FLOAT_MAT4:
        gl.uniformMatrix4fv(location, gl.FALSE, m_dataArray);
        break;
      default:
        break;
    }
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Virtual method to update the uniform
   *
   * Should be implemented by the derived class.
   *
   * @param renderState
   * @param program
   */
  /////////////////////////////////////////////////////////////////////////////
  this.update = function(renderState, program) {
    // Should be implemented by the derived class
  };

  return this;
};

///////////////////////////////////////////////////////////////////////////////
/**
 * Create new instance of class modelViewUniform
 *
 * @param name
 * @returns {vglModule.modelViewUniform}
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.modelViewUniform = function(name) {

  if (!(this instanceof vglModule.modelViewUniform)) {
    return new vglModule.modelViewUniform(name);
  }

  if (name.length === 0) {
    name = "modelViewMatrix";
  }

  vglModule.uniform.call(this, gl.FLOAT_MAT4, name);

  this.set(mat4.create());

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Update the uniform given a render state and shader program
   *
   * @param {vglModule.renderState} renderState
   * @param {vglModule.shaderProgram} program
   */
  /////////////////////////////////////////////////////////////////////////////
  this.update = function(renderState, program) {
    this.set(renderState.m_modelViewMatrix);
  };

  return this;
};

inherit(vglModule.modelViewUniform, vglModule.uniform);

//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class projectionUniform
 *
 * @param name
 * @returns {vglModule.projectionUniform}
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.projectionUniform = function(name) {

  if (!(this instanceof vglModule.projectionUniform)) {
    return new vglModule.projectionUniform(name);
  }

  if (name.length === 0) {
    name = "projectionMatrix";
  }

  vglModule.uniform.call(this, gl.FLOAT_MAT4, name);

  this.set(mat4.create());

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Update the uniform given a render state and shader program
   *
   * @param renderState
   * @param program
   */
  /////////////////////////////////////////////////////////////////////////////
  this.update = function(renderState, program) {
    this.set(renderState.m_projectionMatrix);
  };

  return this;
};

inherit(vglModule.projectionUniform, vglModule.uniform);

///////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class floatUniform
 *
 * @param name
 * @param value
 * @returns {vglModule.floatUniform}
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.floatUniform = function(name, value) {

  if (!(this instanceof vglModule.floatUniform)) {
    return new vglModule.floatUniform(name, value);
  }

  if (name.length === 0) {
    name = "floatUniform";
  }

  if (!value) {
    value = 1.0;
  }

  vglModule.uniform.call(this, gl.FLOAT, name);

  this.set(value);
};

inherit(vglModule.floatUniform, vglModule.uniform);
<commit_msg>Fixed uniform<commit_after>//////////////////////////////////////////////////////////////////////////////
/**
 * @module ogs.vgl
 */

/*jslint devel: true, forin: true, newcap: true, plusplus: true*/
/*jslint white: true, continue:true, indent: 2*/

/*global vglModule, gl, ogs, vec2, vec3, vec4, mat3, mat4, inherit, $*/
//////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class uniform
 *
 * @param type
 * @param name
 * @returns {vglModule.uniform} OpenGL uniform encapsulation
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.uniform = function(type, name) {
  'use strict';

  if (!(this instanceof vglModule.uniform)) {
    return new vglModule.uniform();
  }

  this.getTypeNumberOfComponents = function(type) {
    switch (type) {
      case gl.FLOAT:
      case gl.INT:
      case gl.BOOL:
        return 1;

      case gl.FLOAT_VEC2:
      case gl.INT_VEC2:
      case gl.BOOL_VEC2:
        return 2;

      case gl.FLOAT_VEC3:
      case gl.INT_VEC3:
      case gl.BOOLT_VEC3:
        return 3;

      case gl.FLOAT_VEC4:
      case gl.INT_VEC4:
      case gl.BOOL_VEC4:
        return 4;

      case gl.FLOAT_MAT3:
        return 9;

      case gl.FLOAT_MAT4:
        return 16;

      default:
        return 0;
    }
  };

  var m_type = type,
      m_name = name,
      m_dataArray = [ this.getTypeNumberOfComponents(m_type) ],
      m_numberOfElements = 1;

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Get name of the uniform
   *
   * @returns {*}
   */
  /////////////////////////////////////////////////////////////////////////////
  this.name = function() {
    return m_name;
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Get type of the uniform
   *
   * @returns {*}
   */
  /////////////////////////////////////////////////////////////////////////////
  this.type = function() {
    return m_type;
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Get value of the uniform
   *
   * @returns {Array}
   */
  /////////////////////////////////////////////////////////////////////////////
  this.get = function() {
    return m_dataArray;
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Set value of the uniform
   *
   * @param value
   */
  /////////////////////////////////////////////////////////////////////////////
  this.set = function(value) {
    var i = 0;
    if (value instanceof mat4.constructor) {
      for (i = 0; i < 16; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof mat3.constructor) {
      for (i = 0; i < 9; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof vec4.constructor) {
      for (i = 0; i < 4; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof vec3.constructor) {
      for (i = 0; i < 3; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else if (value instanceof vec2.constructor) {
      for (i = 0; i < 2; ++i) {
        m_dataArray[i] = value[i];
      }
    }
    else {
      m_dataArray[0] = value;
    }
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Call GL and pass updated values to the current shader
   *
   * @param location
   */
  /////////////////////////////////////////////////////////////////////////////
  this.callGL = function(location) {
    if (this.m_numberElements < 1) {
      return;
    }

    switch (m_type) {
      case gl.BOOL:
      case gl.INT:
        gl.uniform1iv(location, m_dataArray);
        break;
      case gl.FLOAT:
        gl.uniform1fv(location, m_dataArray);
        break;
      case gl.FLOAT_VEC2:
        gl.uniform2fv(location, m_dataArray);
        break;
      case gl.FLOAT_VEC3:
        gl.uniform3fv(location, m_dataArray);
        break;
      case gl.FLOAT_VEC4:
        gl.uniform4fv(location, m_dataArray);
        break;
      case gl.FLOAT_MAT3:
        gl.uniformMatrix3fv(location, gl.FALSE, m_dataArray);
        break;
      case gl.FLOAT_MAT4:
        gl.uniformMatrix4fv(location, gl.FALSE, m_dataArray);
        break;
      default:
        break;
    }
  };

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Virtual method to update the uniform
   *
   * Should be implemented by the derived class.
   *
   * @param renderState
   * @param program
   */
  /////////////////////////////////////////////////////////////////////////////
  this.update = function(renderState, program) {
    // Should be implemented by the derived class
  };

  return this;
};

///////////////////////////////////////////////////////////////////////////////
/**
 * Create new instance of class modelViewUniform
 *
 * @param name
 * @returns {vglModule.modelViewUniform}
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.modelViewUniform = function(name) {
  'use strict';

  if (!(this instanceof vglModule.modelViewUniform)) {
    return new vglModule.modelViewUniform(name);
  }

  if (name.length === 0) {
    name = "modelViewMatrix";
  }

  vglModule.uniform.call(this, gl.FLOAT_MAT4, name);

  this.set(mat4.create());

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Update the uniform given a render state and shader program
   *
   * @param {vglModule.renderState} renderState
   * @param {vglModule.shaderProgram} program
   */
  /////////////////////////////////////////////////////////////////////////////
  this.update = function(renderState, program) {
    this.set(renderState.m_modelViewMatrix);
  };

  return this;
};

inherit(vglModule.modelViewUniform, vglModule.uniform);

//////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class projectionUniform
 *
 * @param name
 * @returns {vglModule.projectionUniform}
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.projectionUniform = function(name) {
  'use strict';

  if (!(this instanceof vglModule.projectionUniform)) {
    return new vglModule.projectionUniform(name);
  }

  if (name.length === 0) {
    name = "projectionMatrix";
  }

  vglModule.uniform.call(this, gl.FLOAT_MAT4, name);

  this.set(mat4.create());

  /////////////////////////////////////////////////////////////////////////////
  /**
   * Update the uniform given a render state and shader program
   *
   * @param renderState
   * @param program
   */
  /////////////////////////////////////////////////////////////////////////////
  this.update = function(renderState, program) {
    this.set(renderState.m_projectionMatrix);
  };

  return this;
};

inherit(vglModule.projectionUniform, vglModule.uniform);

///////////////////////////////////////////////////////////////////////////////
/**
 * Create a new instance of class floatUniform
 *
 * @param name
 * @param value
 * @returns {vglModule.floatUniform}
 */
///////////////////////////////////////////////////////////////////////////////
vglModule.floatUniform = function(name, value) {
  'use strict';

  if (!(this instanceof vglModule.floatUniform)) {
    return new vglModule.floatUniform(name, value);
  }

  if (name.length === 0) {
    name = "floatUniform";
  }

  if (!value) {
    value = 1.0;
  }

  vglModule.uniform.call(this, gl.FLOAT, name);

  this.set(value);
};

inherit(vglModule.floatUniform, vglModule.uniform);
<|endoftext|>


<commit_before>var statham = require('statham'),
    path = require('path'),
    addEventListener = function(){},
    originalWindow = typeof window !== 'undefined' ? window : undefined,
    fakeWindow = {
        addEventListener: addEventListener,
        document: {
            addEventListener: addEventListener
        }
    };

function buildPage(viewPath){

    GLOBAL.window = fakeWindow;
    GLOBAL.document = fakeWindow.document;

    var view = require(path.join(process.cwd(), viewPath))();

    console.log('built ' + viewPath.split('/').pop());

    GLOBAL.window = originalWindow;
    GLOBAL.document = originalWindow ? originalWindow.document : undefined;

    return statham.stringify(view);
}

module.exports = buildPage;<commit_msg>Improved GLOBAL handling<commit_after>var statham = require('statham'),
    path = require('path'),
    addEventListener = function(){},
    originalWindow = GLOBAL.window,
    originalDocument = GLOBAL.document,
    fakeWindow = {
        addEventListener: addEventListener,
        document: {
            addEventListener: addEventListener
        }
    };

function buildPage(viewPath){

    GLOBAL.window = fakeWindow;
    GLOBAL.document = fakeWindow.document;

    var view = require(path.join(process.cwd(), viewPath))();

    console.log('built ' + viewPath.split('/').pop());

    GLOBAL.window = originalWindow;
    GLOBAL.document = originalDocument;

    return statham.stringify(view);
}

module.exports = buildPage;<|endoftext|>


<commit_before>// ========================================================================
// SproutCore
// copyright 2006-2008 Sprout Systems, Inc.
// ========================================================================

require('views/view') ;
require('mixins/control') ;
require('mixins/delegate_support');
require('views/inline_text_field');
require('mixins/inline_editor_delegate');

/**
  @class

  Displays a static string of text.

  You use a label view anytime you need to display a static string of text
  or to display text that may need to be edited using only an inline control.

  @extends SC.View
  @extends SC.Control
  @extends SC.DelegateSupport
  @extends SC.InlineEditorDelegate
  @extends SC.Editable
  @since SproutCore 1.0
*/
SC.LabelView = SC.View.extend(SC.DelegateSupport, SC.Control, SC.InlineEditorDelegate,
/** @scope SC.LabelView.prototype */ {

  emptyElement: '',

  /**
    If true, value will be escaped to avoid scripting attacks.

    This is a default value that can be overridden by the
    settings on the owner view.
  */
  escapeHTML: true,

  /**
    If true, then the value will be localized.

    This is a default default that can be overidden by the
    settings in the owner view.
  */
  localize: false,

  /**
    Set this to a validator or to a function and the value
    will be passed through it before being set.

    This is a default default that can be overidden by the
    settings in the owner view.
  */
  formatter: null,

  /**
    The value of the label.

    You may also set the value using a content object and a contentValueKey.

    @field {String}
  */
  value: '',

  /**
    [RO] The value that will actually be displayed.

    This property is dynamically computed by applying localization,
    string conversion and other normalization utilities.

    @field
  */
  displayValue: function() {
    var value = this.get('value') ;

    // 1. apply the formatter
    var formatter = this.getDelegateProperty(this.displayDelegate, 'formatter') ;
    if (formatter) {
      var formattedValue = ($type(formatter) == T_FUNCTION) ? formatter(value, this) : formatter.fieldValueForObject(value, this) ;
      if (formattedValue != null) value = formattedValue ;
    }

    // 2. If the returned value is an array, convert items to strings and
    // join with commas.
    if ($type(value) == T_ARRAY) {
      var ary = [];
      for(var idx=0;idx<value.get('length');idx++) {
        var x = value.objectAt(idx) ;
        if (x != null && x.toString) x = x.toString() ;
        ary.push(x) ;
      }
      value = ary.join(',') ;
    }

    // 3. If value is not a string, convert to string. (handles 0)
    if (value != null && value.toString) value = value.toString() ;

    // 4. Localize
    if (value && this.getDelegateProperty(this.displayDelegate, 'localize')) value = value.loc() ;

    return value ;
  }.property('value'),

  /**
    enables editing using the inline editor
  */
  isEditable: NO,

  /**
    YES if currently editing label view.
  */
  isEditing: NO,

  /**
    set to true to have the value you set automatically localized.
  */
  localize: false,

  /**
    Validator to use during inline editing.

    If you have set isEditing to YES, then any validator you set on this
    property will be used when the label view is put into edit mode.

    @type {SC.Validator}
  */
  validator: null,

  /**
    Event dispatcher callback.
    If isEditable is set to true, opens the inline text editor view.

    @param {DOMMouseEvent} evt DOM event

  */
  doubleClick: function( evt ) { return this.beginEditing(); },

  /**
    Opens the inline text editor (closing it if it was already open for
    another view).

    @return {Boolean} YES if did begin editing
  */
  beginEditing: function()
  {
    if (this.get('isEditing')) return YES ;
    if (!this.get('isEditable')) return NO ;

    var value = this.get('value') || '' ;
    var f = this.convertFrameToView(this.get('frame'), null) ;
    var el = this.rootElement;
    SC.InlineTextFieldView.beginEditing({
      frame: f,
      delegate: this,
      exampleElement: el,
      value: value,
      multiline: NO,
      validator: this.get('validator')
    });
  },

  /**
    Cancels the current inline editor and then exits editor.

    @return {Boolean} NO if the editor could not exit.
  */
  discardEditing: function() {
    if (!this.get('isEditing')) return YES ;
    return SC.InlineTextFieldView.discardEditing() ;
  },

  /**
    Commits current inline editor and then exits editor.

    @return {Boolean} NO if the editor could not exit
  */
  commitEditing: function() {
    if (!this.get('isEditing')) return YES ;
    return SC.InlineTextFieldView.commitEditing() ;
  },

  /** @private
    Set editing to true so edits will no longer be allowed.
  */
  inlineEditorWillBeginEditing: function(inlineEditor) {
    this.set('isEditing', YES);
  },

  /** @private
    Hide the label view while the inline editor covers it.
  */
  inlineEditorDidBeginEditing: function(inlineEditor) {
    this._oldOpacity = this.getStyle('opacity') ;
    this.setStyle({ opacity: 0.0 }) ;
  },

  /** @private
    Could check with a validator someday...
  */
  inlineEditorShouldEndEditing: function(inlineEditor, finalValue) {
    return YES ;
  },

  /** @private
    Update the field value and make it visible again.
  */
  inlineEditorDidEndEditing: function(inlineEditor, finalValue) {
    this.setIfChanged('value', finalValue) ;
    this.setStyle({ opacity: this._oldOpacity }) ;
    this._oldOpacity = null ;
    this.set('isEditing', NO) ;
  },

  /**
    @private

    Invoked whenever the monitored value on the content object
    changes.

    The value processed is either the contentValueKey, if set, or
    it is the content object itself.
  */
  _valueDidChange: function() {

    var value = this.get('value') ;
    if (value == this._value) return; // nothing to do

    // get display value
    var value = this.get('displayValue') ;

    // Escape HTML
    if (this.getDelegateProperty(this.displayDelegate, 'escapeHTML')) {
      this.set('innerText', value || '') ;
    } else this.set('innerHTML', value || '') ;

  }.observes('value')

});
<commit_msg>Label view was not properly caching its display value, which caused problems when updating with null display values.<commit_after>// ========================================================================
// SproutCore
// copyright 2006-2008 Sprout Systems, Inc.
// ========================================================================

require('views/view') ;
require('mixins/control') ;
require('mixins/delegate_support');
require('views/inline_text_field');
require('mixins/inline_editor_delegate');

/**
  @class

  Displays a static string of text.

  You use a label view anytime you need to display a static string of text
  or to display text that may need to be edited using only an inline control.

  @extends SC.View
  @extends SC.Control
  @extends SC.DelegateSupport
  @extends SC.InlineEditorDelegate
  @extends SC.Editable
  @since SproutCore 1.0
*/
SC.LabelView = SC.View.extend(SC.DelegateSupport, SC.Control, SC.InlineEditorDelegate,
/** @scope SC.LabelView.prototype */ {

  emptyElement: '',

  /**
    If true, value will be escaped to avoid scripting attacks.

    This is a default value that can be overridden by the
    settings on the owner view.
  */
  escapeHTML: true,

  /**
    If true, then the value will be localized.

    This is a default default that can be overidden by the
    settings in the owner view.
  */
  localize: false,

  /**
    Set this to a validator or to a function and the value
    will be passed through it before being set.

    This is a default default that can be overidden by the
    settings in the owner view.
  */
  formatter: null,

  /**
    The value of the label.

    You may also set the value using a content object and a contentValueKey.

    @field {String}
  */
  value: '',

  /**
    [RO] The value that will actually be displayed.

    This property is dynamically computed by applying localization,
    string conversion and other normalization utilities.

    @field
  */
  displayValue: function() {
    var value = this.get('value') ;

    // 1. apply the formatter
    var formatter = this.getDelegateProperty(this.displayDelegate, 'formatter') ;
    if (formatter) {
      var formattedValue = ($type(formatter) == T_FUNCTION) ? formatter(value, this) : formatter.fieldValueForObject(value, this) ;
      if (formattedValue != null) value = formattedValue ;
    }

    // 2. If the returned value is an array, convert items to strings and
    // join with commas.
    if ($type(value) == T_ARRAY) {
      var ary = [];
      for(var idx=0;idx<value.get('length');idx++) {
        var x = value.objectAt(idx) ;
        if (x != null && x.toString) x = x.toString() ;
        ary.push(x) ;
      }
      value = ary.join(',') ;
    }

    // 3. If value is not a string, convert to string. (handles 0)
    if (value != null && value.toString) value = value.toString() ;

    // 4. Localize
    if (value && this.getDelegateProperty(this.displayDelegate, 'localize')) value = value.loc() ;

    return value ;
  }.property('value'),

  /**
    enables editing using the inline editor
  */
  isEditable: NO,

  /**
    YES if currently editing label view.
  */
  isEditing: NO,

  /**
    set to true to have the value you set automatically localized.
  */
  localize: false,

  /**
    Validator to use during inline editing.

    If you have set isEditing to YES, then any validator you set on this
    property will be used when the label view is put into edit mode.

    @type {SC.Validator}
  */
  validator: null,

  /**
    Event dispatcher callback.
    If isEditable is set to true, opens the inline text editor view.

    @param {DOMMouseEvent} evt DOM event

  */
  doubleClick: function( evt ) { return this.beginEditing(); },

  /**
    Opens the inline text editor (closing it if it was already open for
    another view).

    @return {Boolean} YES if did begin editing
  */
  beginEditing: function()
  {
    if (this.get('isEditing')) return YES ;
    if (!this.get('isEditable')) return NO ;

    var value = this.get('value') || '' ;
    var f = this.convertFrameToView(this.get('frame'), null) ;
    var el = this.rootElement;
    SC.InlineTextFieldView.beginEditing({
      frame: f,
      delegate: this,
      exampleElement: el,
      value: value,
      multiline: NO,
      validator: this.get('validator')
    });
  },

  /**
    Cancels the current inline editor and then exits editor.

    @return {Boolean} NO if the editor could not exit.
  */
  discardEditing: function() {
    if (!this.get('isEditing')) return YES ;
    return SC.InlineTextFieldView.discardEditing() ;
  },

  /**
    Commits current inline editor and then exits editor.

    @return {Boolean} NO if the editor could not exit
  */
  commitEditing: function() {
    if (!this.get('isEditing')) return YES ;
    return SC.InlineTextFieldView.commitEditing() ;
  },

  /** @private
    Set editing to true so edits will no longer be allowed.
  */
  inlineEditorWillBeginEditing: function(inlineEditor) {
    this.set('isEditing', YES);
  },

  /** @private
    Hide the label view while the inline editor covers it.
  */
  inlineEditorDidBeginEditing: function(inlineEditor) {
    this._oldOpacity = this.getStyle('opacity') ;
    this.setStyle({ opacity: 0.0 }) ;
  },

  /** @private
    Could check with a validator someday...
  */
  inlineEditorShouldEndEditing: function(inlineEditor, finalValue) {
    return YES ;
  },

  /** @private
    Update the field value and make it visible again.
  */
  inlineEditorDidEndEditing: function(inlineEditor, finalValue) {
    this.setIfChanged('value', finalValue) ;
    this.setStyle({ opacity: this._oldOpacity }) ;
    this._oldOpacity = null ;
    this.set('isEditing', NO) ;
  },

  /**
    @private

    Invoked whenever the monitored value on the content object
    changes.

    The value processed is either the contentValueKey, if set, or
    it is the content object itself.
  */
  _valueDidChange: function() {

    var value = this.get('value') ;
    if (value === this._value) return; // nothing to do
    this._value = value ;

    // get display value
    value = this.get('displayValue') ;

    // Escape HTML
    if (this.getDelegateProperty(this.displayDelegate, 'escapeHTML')) {
      this.set('innerText', value || '') ;
    } else this.set('innerHTML', value || '') ;

  }.observes('value')

});
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow

import type { Profile } from '../../types/profile';

import * as React from 'react';
import { Provider } from 'react-redux';
import { render, fireEvent } from 'react-testing-library';
import { oneLine } from 'common-tags';

import { changeTimelineType } from '../../actions/profile-view';
import TrackThread from '../../components/timeline/TrackThread';
import { getPreviewSelection } from '../../selectors/profile';
import { selectedThreadSelectors } from '../../selectors/per-thread';
import { ensureExists } from '../../utils/flow';

import mockCanvasContext from '../fixtures/mocks/canvas-context';
import mockRaf from '../fixtures/mocks/request-animation-frame';
import { storeWithProfile } from '../fixtures/stores';
import {
  getBoundingBox,
  getMouseEvent,
  addRootOverlayElement,
  removeRootOverlayElement,
} from '../fixtures/utils';

import {
  getProfileFromTextSamples,
  getProfileWithMarkers,
} from '../fixtures/profiles/processed-profile';

import type { FileIoPayload } from '../../types/markers';

// The graph is 400 pixels wide based on the getBoundingBox mock. Each stack is 100
// pixels wide. Use the value 50 to click in the middle of this stack, and
// incrementing by steps of 100 pixels to get to the next stack.
const GRAPH_WIDTH = 400;
const GRAPH_HEIGHT = 50;
const STACK_1_X_POSITION = 50;
const STACK_2_X_POSITION = 150;
const STACK_3_X_POSITION = 250;
const STACK_4_X_POSITION = 350;

/**
 * This test is asserting behavior more for the ThreadStackGraph component. The
 * ThreadActivityGraph component was added as a new default. Currently this test
 * only checks the older behavior.
 */
describe('timeline/TrackThread', function() {
  beforeEach(addRootOverlayElement);
  afterEach(removeRootOverlayElement);

  function getSamplesProfile() {
    return getProfileFromTextSamples(`
      a  d  g  j
      b  e  h  k
      c  f  i  l
    `).profile;
  }

  function getMarkersProfile(
    testMarkers = [
      ['Marker A', 0, { startTime: 0, endTime: 1 }],
      ['Marker B', 1, { startTime: 1, endTime: 2 }],
      ['Marker C', 2, { startTime: 2, endTime: 3 }],
      ['Marker D', 3, { startTime: 3, endTime: 4 }],
    ]
  ) {
    const profile = getProfileWithMarkers(testMarkers);
    const [thread] = profile.threads;
    thread.name = 'GeckoMain';
    thread.processType = 'default';
    return profile;
  }

  function setup(profile: Profile) {
    const store = storeWithProfile(profile);
    const { getState, dispatch } = store;
    const threadIndex = 0;
    const flushRafCalls = mockRaf();
    const ctx = mockCanvasContext();
    jest
      .spyOn(HTMLCanvasElement.prototype, 'getContext')
      .mockImplementation(() => ctx);

    jest
      .spyOn(HTMLElement.prototype, 'getBoundingClientRect')
      .mockImplementation(() => getBoundingBox(GRAPH_WIDTH, GRAPH_HEIGHT));

    // Note: These tests were first written with the timeline using the ThreadStackGraph.
    // This is not the default view, so dispatch an action to change to the older default
    // view.
    store.dispatch(changeTimelineType('stack'));

    const renderResult = render(
      <Provider store={store}>
        <TrackThread threadIndex={threadIndex} />
      </Provider>
    );
    const { container } = renderResult;

    // WithSize uses requestAnimationFrame
    flushRafCalls();

    const stackGraphCanvas = () =>
      ensureExists(
        container.querySelector('.threadStackGraphCanvas'),
        `Couldn't find the stack graph canvas, with selector .threadStackGraphCanvas`
      );
    const markerCanvas = () =>
      ensureExists(
        container.querySelector(oneLine`
          .timelineMarkersGeckoMain
          .timelineMarkersCanvas
        `),
        `Couldn't find the marker canvas`
      );

    return {
      ...renderResult,
      dispatch,
      getState,
      profile,
      thread: profile.threads[0],
      store,
      threadIndex,
      stackGraphCanvas,
      markerCanvas,
      ctx,
    };
  }

  it('matches the snapshot for the component', () => {
    const { container } = setup(getSamplesProfile());
    expect(container.firstChild).toMatchSnapshot();
  });

  it('matches the 2d canvas draw snapshot', () => {
    const { ctx } = setup(getSamplesProfile());
    expect(ctx.__flushDrawLog()).toMatchSnapshot();
  });

  it('can click a stack in the stack graph in normal call trees', function() {
    const { getState, stackGraphCanvas, thread } = setup(getSamplesProfile());

    // Provide a quick helper for nicely asserting the call node path.
    const getCallNodePath = () =>
      selectedThreadSelectors
        .getSelectedCallNodePath(getState())
        .map(funcIndex =>
          thread.stringTable.getString(thread.funcTable.name[funcIndex])
        );

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_1_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['a', 'b', 'c']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_2_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['d', 'e', 'f']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_3_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['g', 'h', 'i']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_4_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['j', 'k', 'l']);
  });

  it('can click a stack in the stack graph in inverted call trees', function() {
    const { getState, stackGraphCanvas, thread } = setup(getSamplesProfile());

    // Provide a quick helper for nicely asserting the inverted call node path.
    const getInvertedCallNodePath = () =>
      selectedThreadSelectors
        .getSelectedCallNodePath(getState())
        .map(funcIndex =>
          thread.stringTable.getString(thread.funcTable.name[funcIndex])
        )
        .reverse();

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_1_X_POSITION })
    );
    expect(getInvertedCallNodePath()).toEqual(['c', 'b', 'a']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_3_X_POSITION })
    );
    expect(getInvertedCallNodePath()).toEqual(['i', 'h', 'g']);
  });

  it('can click a marker', function() {
    const { getState, markerCanvas } = setup(getMarkersProfile());

    function clickAndGetMarkerName(pageX: number) {
      fireEvent(markerCanvas(), getMouseEvent('mousedown', { pageX }));
      fireEvent(markerCanvas(), getMouseEvent('mouseup', { pageX }));
      return getPreviewSelection(getState());
    }

    expect(clickAndGetMarkerName(STACK_1_X_POSITION)).toMatchObject({
      selectionStart: 0,
      selectionEnd: 1,
    });

    expect(clickAndGetMarkerName(STACK_2_X_POSITION)).toMatchObject({
      selectionStart: 1,
      selectionEnd: 2,
    });
  });

  it('does not add disk io markers if none are present', function() {
    const noMarkers = [];
    const { queryByTestId } = setup(getMarkersProfile(noMarkers));
    expect(queryByTestId('TimelineMarkersFileIo')).toBeFalsy();
  });

  it('adds disk io markers if they are present', function() {
    const fileIoMarker = [
      [
        'FileIO',
        2,
        ({
          type: 'FileIO',
          startTime: 2,
          endTime: 3,
          source: 'PoisionOIInterposer',
          filename: '/foo/bar/',
          operation: 'read/write',
        }: FileIoPayload),
      ],
    ];
    const { getByTestId } = setup(getMarkersProfile(fileIoMarker));
    expect(getByTestId('TimelineMarkersFileIo')).toBeTruthy();
  });
});
<commit_msg>Test both "inverted" and "uninverted" mode<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow

import type { Profile } from '../../types/profile';

import * as React from 'react';
import { Provider } from 'react-redux';
import { render, fireEvent } from 'react-testing-library';
import { oneLine } from 'common-tags';

import {
  changeTimelineType,
  changeInvertCallstack,
} from '../../actions/profile-view';
import TrackThread from '../../components/timeline/TrackThread';
import { getPreviewSelection } from '../../selectors/profile';
import { selectedThreadSelectors } from '../../selectors/per-thread';
import { ensureExists } from '../../utils/flow';

import mockCanvasContext from '../fixtures/mocks/canvas-context';
import mockRaf from '../fixtures/mocks/request-animation-frame';
import { storeWithProfile } from '../fixtures/stores';
import {
  getBoundingBox,
  getMouseEvent,
  addRootOverlayElement,
  removeRootOverlayElement,
} from '../fixtures/utils';

import {
  getProfileFromTextSamples,
  getProfileWithMarkers,
} from '../fixtures/profiles/processed-profile';

import type { FileIoPayload } from '../../types/markers';

// The graph is 400 pixels wide based on the getBoundingBox mock. Each stack is 100
// pixels wide. Use the value 50 to click in the middle of this stack, and
// incrementing by steps of 100 pixels to get to the next stack.
const GRAPH_WIDTH = 400;
const GRAPH_HEIGHT = 50;
const STACK_1_X_POSITION = 50;
const STACK_2_X_POSITION = 150;
const STACK_3_X_POSITION = 250;
const STACK_4_X_POSITION = 350;

/**
 * This test is asserting behavior more for the ThreadStackGraph component. The
 * ThreadActivityGraph component was added as a new default. Currently this test
 * only checks the older behavior.
 */
describe('timeline/TrackThread', function() {
  beforeEach(addRootOverlayElement);
  afterEach(removeRootOverlayElement);

  function getSamplesProfile() {
    return getProfileFromTextSamples(`
      a  d  g  j
      b  e  h  k
      c  f  i  l
    `).profile;
  }

  function getMarkersProfile(
    testMarkers = [
      ['Marker A', 0, { startTime: 0, endTime: 1 }],
      ['Marker B', 1, { startTime: 1, endTime: 2 }],
      ['Marker C', 2, { startTime: 2, endTime: 3 }],
      ['Marker D', 3, { startTime: 3, endTime: 4 }],
    ]
  ) {
    const profile = getProfileWithMarkers(testMarkers);
    const [thread] = profile.threads;
    thread.name = 'GeckoMain';
    thread.processType = 'default';
    return profile;
  }

  function setup(profile: Profile) {
    const store = storeWithProfile(profile);
    const { getState, dispatch } = store;
    const threadIndex = 0;
    const flushRafCalls = mockRaf();
    const ctx = mockCanvasContext();
    jest
      .spyOn(HTMLCanvasElement.prototype, 'getContext')
      .mockImplementation(() => ctx);

    jest
      .spyOn(HTMLElement.prototype, 'getBoundingClientRect')
      .mockImplementation(() => getBoundingBox(GRAPH_WIDTH, GRAPH_HEIGHT));

    // Note: These tests were first written with the timeline using the ThreadStackGraph.
    // This is not the default view, so dispatch an action to change to the older default
    // view.
    store.dispatch(changeTimelineType('stack'));

    const renderResult = render(
      <Provider store={store}>
        <TrackThread threadIndex={threadIndex} />
      </Provider>
    );
    const { container } = renderResult;

    // WithSize uses requestAnimationFrame
    flushRafCalls();

    const stackGraphCanvas = () =>
      ensureExists(
        container.querySelector('.threadStackGraphCanvas'),
        `Couldn't find the stack graph canvas, with selector .threadStackGraphCanvas`
      );
    const markerCanvas = () =>
      ensureExists(
        container.querySelector(oneLine`
          .timelineMarkersGeckoMain
          .timelineMarkersCanvas
        `),
        `Couldn't find the marker canvas`
      );

    return {
      ...renderResult,
      dispatch,
      getState,
      profile,
      thread: profile.threads[0],
      store,
      threadIndex,
      stackGraphCanvas,
      markerCanvas,
      ctx,
    };
  }

  it('matches the snapshot for the component', () => {
    const { container } = setup(getSamplesProfile());
    expect(container.firstChild).toMatchSnapshot();
  });

  it('matches the 2d canvas draw snapshot', () => {
    const { ctx } = setup(getSamplesProfile());
    expect(ctx.__flushDrawLog()).toMatchSnapshot();
  });

  it('can click a stack in the stack graph in normal call trees', function() {
    const { getState, stackGraphCanvas, thread } = setup(getSamplesProfile());

    // Provide a quick helper for nicely asserting the call node path.
    const getCallNodePath = () =>
      selectedThreadSelectors
        .getSelectedCallNodePath(getState())
        .map(funcIndex =>
          thread.stringTable.getString(thread.funcTable.name[funcIndex])
        );

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_1_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['a', 'b', 'c']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_2_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['d', 'e', 'f']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_3_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['g', 'h', 'i']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_4_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['j', 'k', 'l']);
  });

  it('can click a stack in the stack graph in inverted call trees', function() {
    const { dispatch, getState, stackGraphCanvas, thread } = setup(
      getSamplesProfile()
    );

    dispatch(changeInvertCallstack(true));

    // Provide a quick helper for nicely asserting the call node path.
    const getCallNodePath = () =>
      selectedThreadSelectors
        .getSelectedCallNodePath(getState())
        .map(funcIndex =>
          thread.stringTable.getString(thread.funcTable.name[funcIndex])
        );

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_1_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['c']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_3_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['i']);

    dispatch(changeInvertCallstack(false));

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_1_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['a', 'b', 'c']);

    fireEvent(
      stackGraphCanvas(),
      getMouseEvent('mouseup', { pageX: STACK_3_X_POSITION })
    );
    expect(getCallNodePath()).toEqual(['g', 'h', 'i']);
  });

  it('can click a marker', function() {
    const { getState, markerCanvas } = setup(getMarkersProfile());

    function clickAndGetMarkerName(pageX: number) {
      fireEvent(markerCanvas(), getMouseEvent('mousedown', { pageX }));
      fireEvent(markerCanvas(), getMouseEvent('mouseup', { pageX }));
      return getPreviewSelection(getState());
    }

    expect(clickAndGetMarkerName(STACK_1_X_POSITION)).toMatchObject({
      selectionStart: 0,
      selectionEnd: 1,
    });

    expect(clickAndGetMarkerName(STACK_2_X_POSITION)).toMatchObject({
      selectionStart: 1,
      selectionEnd: 2,
    });
  });

  it('does not add disk io markers if none are present', function() {
    const noMarkers = [];
    const { queryByTestId } = setup(getMarkersProfile(noMarkers));
    expect(queryByTestId('TimelineMarkersFileIo')).toBeFalsy();
  });

  it('adds disk io markers if they are present', function() {
    const fileIoMarker = [
      [
        'FileIO',
        2,
        ({
          type: 'FileIO',
          startTime: 2,
          endTime: 3,
          source: 'PoisionOIInterposer',
          filename: '/foo/bar/',
          operation: 'read/write',
        }: FileIoPayload),
      ],
    ];
    const { getByTestId } = setup(getMarkersProfile(fileIoMarker));
    expect(getByTestId('TimelineMarkersFileIo')).toBeTruthy();
  });
});
<|endoftext|>


<commit_before>import browsers_to_saucelabs from '../tools/browsers_to_saucelabs';

describe('browsers_to_saucelabs', () => {
  let launchers;
  let browsers;

  describe('given browser entries without platforms', () => {
    beforeEach(() => {
      browsers = {
        firefox: [
          'dev',
          'beta',
          'current',
          '3.6',
        ],
      };
      launchers = browsers_to_saucelabs(browsers);
    });

    it('should return an object with the base key set to SauceLabs', () => {
      const first = Object.keys(launchers)[0];

      expect(launchers[first]).to.include.keys('base');
      expect(launchers[first].base).to.eql('SauceLabs');
    });
    it('should generate a key for each version', () => {
      const entries = Object.keys(launchers);

      expect(entries).to.have.length(browsers.firefox.length);
    });
    it('should generate a key set to that browser', () => {
      const first = Object.keys(launchers)[0];

      expect(launchers[first]).to.include.keys('browserName');
      expect(launchers[first].browserName).to.eql('firefox');
    });
  });
  describe('given browser entries with a version "current"', () => {
    beforeEach(() => {
      browsers = {
        firefox: [
          'current',
        ],
      };
      launchers = browsers_to_saucelabs(browsers);
    });

    it('should return an object without a version key', () => {
      const first = Object.keys(launchers)[0];

      expect(launchers[first].version).to.not.exist;
    });
  });

  it('given a browser entry with platforms it should generate objects with platform keys', () => {
    browsers = {
      firefox: {
        dev: ['Windows 7', 'OS X 10.11'],
      },
    };
    launchers = browsers_to_saucelabs(browsers);

    const first = Object.keys(launchers)[0];

    expect(launchers[first]).to.include.keys('platform');
    expect(launchers[first].platform).to.eql('Windows 7');
  });
});
<commit_msg>fixed a lint issue<commit_after>/* eslint no-unused-expressions: 0 */ // needed for expects
import browsers_to_saucelabs from '../tools/browsers_to_saucelabs';

describe('browsers_to_saucelabs', () => {
  let launchers;
  let browsers;

  describe('given browser entries without platforms', () => {
    beforeEach(() => {
      browsers = {
        firefox: [
          'dev',
          'beta',
          'current',
          '3.6',
        ],
      };
      launchers = browsers_to_saucelabs(browsers);
    });

    it('should return an object with the base key set to SauceLabs', () => {
      const first = Object.keys(launchers)[0];

      expect(launchers[first]).to.include.keys('base');
      expect(launchers[first].base).to.eql('SauceLabs');
    });
    it('should generate a key for each version', () => {
      const entries = Object.keys(launchers);

      expect(entries).to.have.length(browsers.firefox.length);
    });
    it('should generate a key set to that browser', () => {
      const first = Object.keys(launchers)[0];

      expect(launchers[first]).to.include.keys('browserName');
      expect(launchers[first].browserName).to.eql('firefox');
    });
  });
  describe('given browser entries with a version "current"', () => {
    beforeEach(() => {
      browsers = {
        firefox: [
          'current',
        ],
      };
      launchers = browsers_to_saucelabs(browsers);
    });

    it('should return an object without a version key', () => {
      const first = Object.keys(launchers)[0];

      expect(launchers[first].version).to.not.exist;
    });
  });

  it('given a browser entry with platforms it should generate objects with platform keys', () => {
    browsers = {
      firefox: {
        dev: ['Windows 7', 'OS X 10.11'],
      },
    };
    launchers = browsers_to_saucelabs(browsers);

    const first = Object.keys(launchers)[0];

    expect(launchers[first]).to.include.keys('platform');
    expect(launchers[first].platform).to.eql('Windows 7');
  });
});
<|endoftext|>


<commit_before>/*
    load floor image
*/
function loadFloor(floor){
    floor = typeof floor !== 'undefined' ? floor : 2;
    $('#mainContent img').attr('src','img/maps/floor'+floor+'.png');
}

/*
    dot position in percent to image
 */
function drawDot(x,y,className,name){
    className = typeof className !== 'undefined' ? className : '';
    name = typeof name !== 'undefined' ? name : '';
    $('#floorImg').append('
');
}

/*
    beacon or photo
 */

function showButton(content){
    content = typeof content !== 'undefined' ? content : 'photo';
    var icon;
    if(content=='photo'){
        button = '
Scanner l\'oeuvre
';
    }else{
        button = '';
    }
    $('#subContent').html('
'+button+'
');
}

/*
    clean main content
 */
function hideMainContent(){
    $('#mainContent').html('');
}

function transparentBackground(){
    $('html').attr('style','background:transparent;');
    $('body').attr('style','background:transparent;');
}
/*
    show image from app
 */
function loadPersonPicture(imgUrl){
    if(imgUrl != undefined){
        $('#personImg').append('')
    }
}

$.urlParam = function(name){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results==null){
        return null;
    }
    else{
        return results[1] || 0;
    }
}

$( document ).ready(function() {
    var idList = ["8oo2l8fk3pdlzy6","knliyajr8y6x0yt","bja43whspny60x2"];
    var theList;
    $('#formmuseochoix').submit(function(e) {
        e.preventDefault();
        if($('#timing .active input').val() == '30'){
            theList = idList.slice(0, 1);
        }else if($('#timing .active input').val() == '60'){
            theList = idList.slice(0, 3);
        }else if($('#timing .active input').val() == '90'){
            theList = idList.slice(0, 5);
        }else{
            theList = idList;
        }
        document.location = 'museochoix://loadContexts?ids='+theList.toString();
        return false;
    });

    $(document).on('click', '#takePic', function (e) {
        e.preventDefault();
        hideMainContent();
        transparentBackground();
        $('#subContent').html();
    });
});<commit_msg>corrections<commit_after>/*
    load floor image
*/
function loadFloor(floor){
    floor = typeof floor !== 'undefined' ? floor : 2;
    $('#mainContent img').attr('src','img/maps/floor'+floor+'.png');
}

/*
    dot position in percent to image
 */
function drawDot(x,y,className,name){
    className = typeof className !== 'undefined' ? className : '';
    name = typeof name !== 'undefined' ? name : '';
    $('#floorImg').append('
');
}

/*
    beacon or photo
 */

function showButton(content){
    content = typeof content !== 'undefined' ? content : 'photo';
    var icon;
    if(content=='photo'){
        button = '
Rendez-vous au point actif

Scanner l\'oeuvre
';
    }else{
        button = '';
    }
    $('#subContent').html('
'+button+'
');
}

/*
    clean main content
 */
function hideMainContent(){
    $('#mainContent').html('');
}

function transparentBackground(){
    $('html').attr('style','background:transparent;');
    $('body').attr('style','background:transparent;');
}
/*
    show image from app
 */
function loadPersonPicture(imgUrl){
    if(imgUrl != undefined){
        $('#personImg').append('')
    }
}

$.urlParam = function(name){
    var results = new RegExp('[\?&]' + name + '=([^&#]*)').exec(window.location.href);
    if (results==null){
        return null;
    }
    else{
        return results[1] || 0;
    }
}

$( document ).ready(function() {
    var idList = ["8oo2l8fk3pdlzy6","knliyajr8y6x0yt","bja43whspny60x2"];
    var theList;
    $('#formmuseochoix').submit(function(e) {
        e.preventDefault();
        if($('#timing .active input').val() == '30'){
            theList = idList.slice(0, 1);
        }else if($('#timing .active input').val() == '60'){
            theList = idList.slice(0, 3);
        }else if($('#timing .active input').val() == '90'){
            theList = idList.slice(0, 5);
        }else{
            theList = idList;
        }
        document.location = 'museochoix://loadContexts?ids='+theList.toString();
        return false;
    });

    $(document).on('click', '#takePic', function (e) {
        e.preventDefault();
        hideMainContent();
        transparentBackground();
        $('#subContent').html('');
    });
});<|endoftext|>


<commit_before>var sfAssetsLibrary_Engine = function(){};

sfAssetsLibrary_Engine.prototype = {
  init: function(url)
  {
    this.url = url;
  },

	load: function () {
		"use strict";
		var asset_url = document.getElementById('sf_asset_js_url'),
			asset_input = null,
			url, len, i;

		if (asset_url) {
			url = asset_url.firstChild.data;
			this.url = url;
		}

    var asset_input = document.getElementById('sf_asset_input_image');
    if (asset_input) {
      eval('var rel = ' + asset_input.getAttribute('rel'));
      var fname = asset_input.previousSibling.form.name;
      sfAssetsLibrary.addEvent(asset_input, 'click', function(e) {
        sfAssetsLibrary.openWindow({
          form_name: fname,
          field_name: rel.name,
          type: rel.type,
          url: rel.url,
          scrollbars: 'yes'
        });
        sfAssetsLibrary.prevDef(e);
        sfAssetsLibrary.stopProp(e);
      }, false);
    }
  },

  fileBrowserReturn: function(url, thumbUrl, id)
  {
    if (this.isTinyMCE)
    {
      tinyMCE.setWindowArg('editor_id', this.fileBrowserWindowArg);
      if (this.fileBrowserType == 'image')
      {
        this.callerWin.showPreviewImage(url);
      }
    }
    this.callerWin.document.forms[this.callerFormName].elements[this.callerFieldName].value = id;
    var callerId = this.callerWin.document.forms[this.callerFormName].elements[this.callerFieldName].id;
    var img = this.callerWin.document.getElementById(callerId + '_img');
    if (img)
    {
      img.src = thumbUrl;
    }
  },

  // tried to do multiple adds.
  // not working: can't add DOM elements in a window different from current one :-|
  fileBrowserAdd: function(url, id)
  {
    var ul = this.callerWin.document.getElementById('multiassets');
    if (!ul)
    {
      return;
    }
    var li = this.callerWin.document.createElement('li');
    var img = this.callerWin.document.createElement('img');
    img.setAttribute('src', url);
    li.appendChild(img);
    ul.appendChild(ul);
  },

  fileBrowserCallBack: function(field_name, url, type, win)
  {
    if (!this.url)
    {
      this.load();
      if (!this.url)
      {
        alert('error in getting asset url');
        return;
      }
    }

    var params = type == 'image' ? 'images_only=1&tiny=1' : 'tiny=1';
    tinyMCE.activeEditor.windowManager.open({
      file :      sfAssetsLibrary.addParams(this.url, params),
      title:      'Assets',
      width :     550,
      height :    600,
      inline:     'yes',
      resizable : 'yes',
      scrollbars: 'yes'
    },
    {
      input:      field_name,
      type:       type,
      window:     win
    });

    return false;
  },

  openWindow: function(options)
  {
    var width, height, x, y, resizable, scrollbars, url;

    if (!options) return;
    if (!options['field_name']) return;
    if (options['url'])
    {
      this.url = options['url'];
    }
    else if (!this.url)
    {
      return;
    }
    this.callerWin = self;
    this.callerFormName = (options['form_name'] == '') ? 0 : options['form_name'];
    this.callerFieldName = options['field_name'];
    this.fileBrowserType = options['type'];
    url = this.url;

    if (options['type'] == 'image') url = sfAssetsLibrary.addParams(url, 'images_only=1');
    if (!(width = parseInt(options['width']))) width = 1000;
    if (!(height = parseInt(options['height']))) height = 600;

    // Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!!
    if (sfAssetsLibrary.isMSIE)
      height += 40;
    else
      height += 20;

    x = parseInt(screen.width / 2.0) - (width / 2.0);
    y = parseInt(screen.height / 2.0) - (height / 2.0);

    resizable = (options && options['resizable']) ? options['resizable'] : "no";
    scrollbars = (options && options['scrollbars']) ? options['scrollbars'] : "no";

    var modal = (resizable == "yes") ? "no" : "yes";

    if (sfAssetsLibrary.isGecko && sfAssetsLibrary.isMac) modal = "no";

    if (options['close_previous'] != "no") try {sfAssetsLibrary.lastWindow.close();} catch (ex) {}

    var win = window.open(url, "sfPopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ", width=1000, height=600,resizable=" + resizable);
    this.fileBrowserWin = win;
    if (options['close_previous'] != "no") sfAssetsLibrary.lastWindow = win;

    win.focus();
  },

  addParams: function(url, params)
  {
    return url.indexOf('?') > 0 ? url + '&' + params : url + '?' + params;
  },

  // x-browser event listener
  addEvent: function(el, eType, fn, uC)
  {
    if (el.addEventListener)
    {
      el.addEventListener(eType, fn, uC);
      return true;
    }
    else if (el.attachEvent)
    {
      return el.attachEvent('on' + eType, fn);
    }
    else
    {
      el['on' + eType] = fn;
    }
  },

  // x-browser stop propagation
  stopProp: function(e)
  {
    if (e && e.stopPropogation) e.stopPropogation();
    else if (window.event && window.event.cancelBubble)
    window.event.cancelBubble = true;
  },

  // x-browser prevent default
  prevDef: function(e)
  {
    if (e && e.preventDefault) e.preventDefault();
    else if (window.event && window.event.returnValue)
    window.eventReturnValue = false;
  }

}

var sfAssetsLibrary = new sfAssetsLibrary_Engine();

window.onload = sfAssetsLibrary.load;
<commit_msg>[js] indentation<commit_after>var sfAssetsLibrary_Engine = function(){};

sfAssetsLibrary_Engine.prototype = {
  init: function(url)
  {
    this.url = url;
  },

	load: function () {
		"use strict";
		var asset_url = document.getElementById('sf_asset_js_url'),
			asset_input = null,
			url, len, i;

		if (asset_url) {
			url = asset_url.firstChild.data;
			this.url = url;
		}

		asset_input = document.getElementById('sf_asset_input_image');
		if (asset_input) {
			eval('var rel = ' + asset_input.getAttribute('rel'));
			var fname = asset_input.previousSibling.form.name;
			sfAssetsLibrary.addEvent(asset_input, 'click', function (e) {
				sfAssetsLibrary.openWindow({
					form_name: fname,
					field_name: rel.name,
					type: rel.type,
					url: rel.url,
					scrollbars: 'yes'
				});

				sfAssetsLibrary.prevDef(e);
				sfAssetsLibrary.stopProp(e);
			}, false);
		}
	},

  fileBrowserReturn: function(url, thumbUrl, id)
  {
    if (this.isTinyMCE)
    {
      tinyMCE.setWindowArg('editor_id', this.fileBrowserWindowArg);
      if (this.fileBrowserType == 'image')
      {
        this.callerWin.showPreviewImage(url);
      }
    }
    this.callerWin.document.forms[this.callerFormName].elements[this.callerFieldName].value = id;
    var callerId = this.callerWin.document.forms[this.callerFormName].elements[this.callerFieldName].id;
    var img = this.callerWin.document.getElementById(callerId + '_img');
    if (img)
    {
      img.src = thumbUrl;
    }
  },

  // tried to do multiple adds.
  // not working: can't add DOM elements in a window different from current one :-|
  fileBrowserAdd: function(url, id)
  {
    var ul = this.callerWin.document.getElementById('multiassets');
    if (!ul)
    {
      return;
    }
    var li = this.callerWin.document.createElement('li');
    var img = this.callerWin.document.createElement('img');
    img.setAttribute('src', url);
    li.appendChild(img);
    ul.appendChild(ul);
  },

  fileBrowserCallBack: function(field_name, url, type, win)
  {
    if (!this.url)
    {
      this.load();
      if (!this.url)
      {
        alert('error in getting asset url');
        return;
      }
    }

    var params = type == 'image' ? 'images_only=1&tiny=1' : 'tiny=1';
    tinyMCE.activeEditor.windowManager.open({
      file :      sfAssetsLibrary.addParams(this.url, params),
      title:      'Assets',
      width :     550,
      height :    600,
      inline:     'yes',
      resizable : 'yes',
      scrollbars: 'yes'
    },
    {
      input:      field_name,
      type:       type,
      window:     win
    });

    return false;
  },

  openWindow: function(options)
  {
    var width, height, x, y, resizable, scrollbars, url;

    if (!options) return;
    if (!options['field_name']) return;
    if (options['url'])
    {
      this.url = options['url'];
    }
    else if (!this.url)
    {
      return;
    }
    this.callerWin = self;
    this.callerFormName = (options['form_name'] == '') ? 0 : options['form_name'];
    this.callerFieldName = options['field_name'];
    this.fileBrowserType = options['type'];
    url = this.url;

    if (options['type'] == 'image') url = sfAssetsLibrary.addParams(url, 'images_only=1');
    if (!(width = parseInt(options['width']))) width = 1000;
    if (!(height = parseInt(options['height']))) height = 600;

    // Add to height in M$ due to SP2 WHY DON'T YOU GUYS IMPLEMENT innerWidth of windows!!
    if (sfAssetsLibrary.isMSIE)
      height += 40;
    else
      height += 20;

    x = parseInt(screen.width / 2.0) - (width / 2.0);
    y = parseInt(screen.height / 2.0) - (height / 2.0);

    resizable = (options && options['resizable']) ? options['resizable'] : "no";
    scrollbars = (options && options['scrollbars']) ? options['scrollbars'] : "no";

    var modal = (resizable == "yes") ? "no" : "yes";

    if (sfAssetsLibrary.isGecko && sfAssetsLibrary.isMac) modal = "no";

    if (options['close_previous'] != "no") try {sfAssetsLibrary.lastWindow.close();} catch (ex) {}

    var win = window.open(url, "sfPopup" + new Date().getTime(), "top=" + y + ",left=" + x + ",scrollbars=" + scrollbars + ",dialog=" + modal + ",minimizable=" + resizable + ",modal=" + modal + ", width=1000, height=600,resizable=" + resizable);
    this.fileBrowserWin = win;
    if (options['close_previous'] != "no") sfAssetsLibrary.lastWindow = win;

    win.focus();
  },

  addParams: function(url, params)
  {
    return url.indexOf('?') > 0 ? url + '&' + params : url + '?' + params;
  },

  // x-browser event listener
  addEvent: function(el, eType, fn, uC)
  {
    if (el.addEventListener)
    {
      el.addEventListener(eType, fn, uC);
      return true;
    }
    else if (el.attachEvent)
    {
      return el.attachEvent('on' + eType, fn);
    }
    else
    {
      el['on' + eType] = fn;
    }
  },

  // x-browser stop propagation
  stopProp: function(e)
  {
    if (e && e.stopPropogation) e.stopPropogation();
    else if (window.event && window.event.cancelBubble)
    window.event.cancelBubble = true;
  },

  // x-browser prevent default
  prevDef: function(e)
  {
    if (e && e.preventDefault) e.preventDefault();
    else if (window.event && window.event.returnValue)
    window.eventReturnValue = false;
  }

}

var sfAssetsLibrary = new sfAssetsLibrary_Engine();

window.onload = sfAssetsLibrary.load;
<|endoftext|>


<commit_before>/*
 *	by Tofran 			: 	https://github.com/ToFran
 *	PortugalWebBlocking	: 	https://github.com/ToFran/PortugalWebBlocking
 */

var stats = {};
var domainCount = {'domains': 0, 'hosts': 0};

$.getJSON('blockList.json', function(jsonData) {
	var header = document.querySelectorAll("#mainTable tr");
	for(var eachIsp in jsonData.info.isps){
		header[0].innerHTML += "" + eachIsp + "	";
		header[1].innerHTML += "S	" +
								"IP	";
		stats[eachIsp] = {"-2": 0, "-1": 0, "0": 0, "1": 0, "2": 0};

	};
	for(var fqdn in jsonData.domains){
		domainCount.domains++;
		for(var host in jsonData.domains[fqdn].hosts){
			domainCount.hosts++;
			var domain = ((host == '@') ? '': host + '.') + fqdn;
			var current = jsonData.domains[fqdn].hosts[host];
			var newTr = document.createElement('tr');
			newTr.innerHTML +=	"" + domain + "	"+
								"" + current.ip[0] + "	" +
								"" + current.blockDate + "	" +
								"" + current.reason + "	";
			var ispPos = 0;
			for(var eachIsp in jsonData.info.isps){
				if(!(eachIsp in current.isp)){
					current.isp[eachIsp] = {"dnsResponse": [], "status": -1 };
				};
				newTr.innerHTML += "" +
									"" + current.isp[eachIsp].status +
									"</spam>	";
				newTd = document.createElement('td');
				newTd.innerHTML = current.isp[eachIsp].dnsResponse[0];
				newTr.appendChild(newTd);
				stats[eachIsp][current.isp[eachIsp].status]++;
			};
			document.getElementById('tableBody').appendChild(newTr);
		};
	};

	//stats
	document.getElementById('domainCount').innerHTML = domainCount.domains + ' domains (' + domainCount.hosts + ' hosts)';
	document.getElementById('referenceDns').innerHTML =
			jsonData.info.reference.name + ' (Last Scan: ' +
			new Date(jsonData.info.reference.lastScan).toString().slice(0, 24) + ')';
	statsTable = document.querySelector("#statsTable tbody");
	for(var eachIsp in jsonData.info.isps){
		var newTr = document.createElement('tr');
		newTr.innerHTML = "" + eachIsp + "	";
		for (var i = -2; i <= 2; i++) {
			newTr.innerHTML += "" + stats[eachIsp][i] + "	";
		};
		var date = new Date(jsonData.info.isps[eachIsp].lastScan);
		console.log(date.getMonth());
		newTr.innerHTML += "" + date.toString().slice(0, 24) + "	"; //date.getFullYear() + '/' + date.getMonth() + 1 + '/' + date.getDate();
		statsTable.appendChild(newTr);

	};

	$('#statsTable').tablesorter();
	$('#mainTable').tablesorter();
});<commit_msg>Fixed status bug and removed debugging code<commit_after>/*
 *	by Tofran 			: 	https://github.com/ToFran
 *	PortugalWebBlocking	: 	https://github.com/ToFran/PortugalWebBlocking
 */

var stats = {};
var domainCount = {'domains': 0, 'hosts': 0};

$.getJSON('blockList.json', function(jsonData) {
	var header = document.querySelectorAll("#mainTable tr");
	for(var eachIsp in jsonData.info.isps){
		header[0].innerHTML += "" + eachIsp + "	";
		header[1].innerHTML += "S	" +
								"IP	";
		stats[eachIsp] = {"-2": 0, "-1": 0, "0": 0, "1": 0, "2": 0};

	};
	for(var fqdn in jsonData.domains){
		domainCount.domains++;
		for(var host in jsonData.domains[fqdn].hosts){
			domainCount.hosts++;
			var domain = ((host == '@') ? '': host + '.') + fqdn;
			var current = jsonData.domains[fqdn].hosts[host];
			var newTr = document.createElement('tr');
			newTr.innerHTML +=	"" + domain + "	"+
								"" + current.ip[0] + "	" +
								"" + current.blockDate + "	" +
								"" + current.reason + "	";
			var ispPos = 0;
			for(var eachIsp in jsonData.info.isps){
				if(!(eachIsp in current.isp)){
					current.isp[eachIsp] = {"dnsResponse": [], "status": -2 };
				};
				newTr.innerHTML += "" +
									"" + current.isp[eachIsp].status +
									"</spam>	";
				newTd = document.createElement('td');
				newTd.innerHTML = current.isp[eachIsp].dnsResponse[0];
				newTr.appendChild(newTd);
				stats[eachIsp][current.isp[eachIsp].status]++;
			};
			document.getElementById('tableBody').appendChild(newTr);
		};
	};

	//stats
	document.getElementById('domainCount').innerHTML = domainCount.domains + ' domains (' + domainCount.hosts + ' hosts)';
	document.getElementById('referenceDns').innerHTML =
			jsonData.info.reference.name + ' (Last Scan: ' +
			new Date(jsonData.info.reference.lastScan).toString().slice(0, 24) + ')';
	statsTable = document.querySelector("#statsTable tbody");
	for(var eachIsp in jsonData.info.isps){
		var newTr = document.createElement('tr');
		newTr.innerHTML = "" + eachIsp + "	";
		for (var i = -2; i <= 2; i++) {
			newTr.innerHTML += "" + stats[eachIsp][i] + "	";
		};
		var date = new Date(jsonData.info.isps[eachIsp].lastScan);
		newTr.innerHTML += "" + date.toString().slice(0, 24) + "	";
	};

	$('#statsTable').tablesorter();
	$('#mainTable').tablesorter();
});<|endoftext|>


<commit_before>/**
 * Created by ahindle on 08/11/14.
 */
var msiofApp = angular.module('msiofApp', []).config(function($interpolateProvider){
		  $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
});

msiofApp.controller('HomeCtrl', function ($scope, $http, $interval) {
		  $scope.servers = {};

		  $scope.updateServers = function() {
					 $http({
								method: 'GET',
								url: '/servers/cheese',
					 }).then(function(response){
								var data = response.data;
								$scope.servers = data;
					 });
		  };

		  $scope.updateServers();
		  $interval(function() {
					 $scope.updateServers();
		  }, 30000);
});
<commit_msg>only get servers when we have an apiKey<commit_after>/**
 * Created by ahindle on 08/11/14.
 */
var msiofApp = angular.module('msiofApp', []).config(function($interpolateProvider){
		  $interpolateProvider.startSymbol('{[{').endSymbol('}]}');
});

msiofApp.controller('HomeCtrl', function ($scope, $http, $interval) {
		  $scope.servers = {};

		  $scope.updateServers = function() {
					 $http({
								method: 'GET',
								url: '/servers/' + $scope.apiKey,
					 }).then(function(response){
								var data = response.data;
								$scope.servers = data;
					 });
		  };

		  $scope.$watch("apiKey", function(){
					 $scope.updateServers();
					 $interval(function() {
								$scope.updateServers();
					 }, 30000);
		  });
});
<|endoftext|>