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

var features =
{
  open_items:
  {
    id: "open_mult_items",
    class:"item Open",
    title: "Open selected items"
  },
  publish_items:
  {
    id: "publihs_mult_items",
    class:"item Publish disabled",
    title: "Publish selected items"
  }
};

class DashboardMenuFeature
{
  constructor(feature, listeners)
  {
    var _self = this;
    this.element = document.createElement("li");
    this.element.className  = feature.class;
    this.element.id = feature.id;

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

    var element_span = document.createElement("span");
    element_span.innerHTML = feature.title;

    this.element.appendChild(element_div);
    this.element.appendChild(element_span);

    this.element.addEventListener("mouseover",function(){
        Tridion.Controls.ContextMenu.prototype._hightlightItem(this);
      });
    this.element.addEventListener("click",function(){
        // Close DashboardMenu after clicking the feature
        //Tridion.Controls.ContextMenu.prototype._hightlightItem(this);
      });

    listeners.forEach(function(listener) {
      _self.element.addEventListener(listener.type, listener.callback);
    });

    return this.element;
  }
}

new class Tridion_Ext
{
  constructor()
  {
    this._v = 1.0;
    this.dashboard_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.replace(/ \(tcm.*\)/g, "");  // lvl   remove what is between parenthesis
          _self.lvls[id] = unescape(lvl);
        });

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

/* Actions*/
  enable_publish_items()
  {
    var listeners = [];
    var callback;

    callback = function(){
      console.log("Publishing items");
    }
    listeners.push({ "type": "click", "callback" : callback });
    this.feature_wr(this.pro_publishing, features.publish_items, listeners);
  }

  enable_open_mult_items()
  {
    var _self = this;
    var listeners = [];
    var callback;

    callback = 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 = document.location.origin +"/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
    }
    listeners.push({ "type": "click", "callback" : callback });
    this.feature_wr(this.mult_open, features.open_items, listeners);
  }

/* 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();
    };
  }

  feature_wr(element, feature, listeners)
  {
    element = new DashboardMenuFeature(feature, listeners);
    this.dashboard_menu.appendChild(element);
  }

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

    this.enable_publish_items();
    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>Fixes #2<commit_after>// Author: Daniel G (oscar-daniel.gonzalez@hp.com)

var features =
{
  open_items:
  {
    id: "open_mult_items",
    class:"item Open",
    title: "Open selected items"
  },
  publish_items:
  {
    id: "publihs_mult_items",
    class:"item Publish disabled",
    title: "Publish selected items"
  }
};

class DashboardMenuFeature
{
  constructor(feature, listeners)
  {
    var _self = this;
    this.element = document.createElement("li");
    this.element.className  = feature.class;
    this.element.id = feature.id;

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

    var element_span = document.createElement("span");
    element_span.innerHTML = feature.title;

    this.element.appendChild(element_div);
    this.element.appendChild(element_span);

    this.element.addEventListener("mouseover",function(){
        Tridion.Controls.ContextMenu.prototype._hightlightItem(this);
      });
    this.element.addEventListener("click",function(){
        // Close DashboardMenu after clicking the feature
        //Tridion.Controls.ContextMenu.prototype._hightlightItem(this);
      });

    listeners.forEach(function(listener) {
      _self.element.addEventListener(listener.type, listener.callback);
    });

    return this.element;
  }
}

new class Tridion_Ext
{
  constructor()
  {
    this._v = 1.0;
    this.dashboard_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.replace(/ \(tcm.*\)/g, "");  // lvl   remove what is between parenthesis
          _self.lvls[id] = unescape(lvl);
        });

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

/* Actions*/
  enable_publish_items()
  {
    var listeners = [];
    var callback;

    callback = function(){
      console.log("Publishing items");
    }
    listeners.push({ "type": "click", "callback" : callback });
    this.feature_wr(this.pro_publishing, features.publish_items, listeners);
  }

  enable_open_mult_items()
  {
    var _self = this;
    var listeners = [];
    var callback;

    callback = 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 = document.location.origin +"/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
    }
    listeners.push({ "type": "click", "callback" : callback });
    this.feature_wr(this.mult_open, features.open_items, listeners);
  }

/* 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();
    };
  }

  feature_wr(element, feature, listeners)
  {
    element = new DashboardMenuFeature(feature, listeners);
    this.dashboard_menu.appendChild(element);
  }

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

    this.enable_publish_items();
    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 = (txt_lvl == "" || txt_lvl == "(Local copy)")?
          row.id.split(':')[1].split('-')[0] : _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>/**
 * Twig.js 0.8.2
 *
 * @copyright 2011-2015 John Roepke and the Twig.js Contributors
 * @license   Available under the BSD 2-Clause License
 * @link      https://github.com/justjohn/twig.js
 */

var Twig = (function (Twig) {

    Twig.VERSION = "0.8.2";

    return Twig;
})(Twig || {});
<commit_msg>Bump internal Twig.js version to "0.8.2-1"<commit_after>/**
 * Twig.js 0.8.2-1
 *
 * @copyright 2011-2015 John Roepke and the Twig.js Contributors
 * @license   Available under the BSD 2-Clause License
 * @link      https://github.com/justjohn/twig.js
 */

var Twig = (function (Twig) {

    Twig.VERSION = "0.8.2-1";

    return Twig;
})(Twig || {});
<|endoftext|>


<commit_before>//     Twig.js
//     Copyright (c) 2011-2013 John Roepke
//     Available under the BSD 2-Clause License
//     https://github.com/justjohn/twig.js

// ## twig.module.js
// Provide a CommonJS module export.

if (typeof module !== 'undefined' && module.declare) {
    // Provide a CommonJS Modules/2.0 draft 8 module
    module.declare([], function(require, exports, module) {
        // Add exports from the Twig exports
        for (key in Twig.exports) {
            if (Twig.exports.hasOwnProperty(key)) {
                exports[key] = Twig.exports[key];
            }
        }
    });
} else if (typeof define == 'function' && define.amd) {
    define(function() {
        return Twig.exports;
    });
} else if (typeof module !== 'undefined' && module.exports) {
    // Provide a CommonJS Modules/1.1 module
    module.exports = Twig.exports;
} else {
    // Export for browser use
    window.twig = Twig.exports.twig;
    window.Twig = Twig.exports;
}

<commit_msg>Working in module export file<commit_after>//     Twig.js
//     Copyright (c) 2011-2013 John Roepke
//     Available under the BSD 2-Clause License
//     https://github.com/justjohn/twig.js

// ## twig.module.js
// Provide a CommonJS/AMD/Node module export.

if (typeof module !== 'undefined' && module.declare) {
    // Provide a CommonJS Modules/2.0 draft 8 module
    module.declare([], function(require, exports, module) {
        // Add exports from the Twig exports
        for (key in Twig.exports) {
            if (Twig.exports.hasOwnProperty(key)) {
                exports[key] = Twig.exports[key];
            }
        }
    });
} else if (typeof define == 'function' && define.amd) {
    define(function() {
        return Twig.exports;
    });
} else if (typeof module !== 'undefined' && module.exports) {
    // Provide a CommonJS Modules/1.1 module
    module.exports = Twig.exports;
} else {
    // Export for browser use
    window.twig = Twig.exports.twig;
    window.Twig = Twig.exports;
}

<|endoftext|>


<commit_before>var _ = require('lodash')
var LRU = require('lru-cache')
var Q = require('q')

var bitcoin = require('../cclib').bitcoin
var verify = require('../verify')

var RecheckInterval = 60 * 1000

/**
 * @class BaseTxDb
 *
 * @param {Wallet} wallet
 * @param {TxStorage} storage
 */
// Todo: blockchain reorg and double-spending
function BaseTxDb(wallet, storage) {
  verify.Wallet(wallet)
  verify.TxStorage(storage)

  this.wallet = wallet
  this.storage = storage

  this.lastStatusCheck = LRU({ maxAge: RecheckInterval })
}

BaseTxDb.TxStatusUnknown = 0
BaseTxDb.TxStatusUnconfirmed = 1
BaseTxDb.TxStatusConfirmed = 2
BaseTxDb.TxStatusInvalid = 3

/**
 * @callback BaseTxDb~errorCallback
 * @param {?Error} error
 */

/**
 * @param {Object} data
 * @param {bitcoinjs-lib.Transaction} data.tx
 * @param {number} [data.timestamp]
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.addUnconfirmedTx = function(data, cb) {
  verify.object(data)

  data = _.extend(data, { status: BaseTxDb.TxStatusUnconfirmed })
  this.addTx(data, cb)
}

/**
 * @param {Object} data
 * @param {bitcoinjs-lib.Transaction} data.tx
 * @param {number} [data.status]
 * @param {number} [data.timestamp]
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.addTx = function(data, cb) {
  verify.object(data)
  verify.Transaction(data.tx)
  if (data.status) verify.number(data.status)
  if (data.timestamp) verify.number(data.timestamp)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    var txId = data.tx.getId()

    var record = self.storage.getByTxId(txId)
    if (record !== null)
      return Q.ninvoke(self, 'maybeRecheckTxStatus', record.txId, record.status)

    return Q.fcall(function() {
      if (_.isUndefined(data.status))
        return Q.ninvoke(self, 'identifyTxStatus', txId)
      return data.status

    }).then(function(status) {
      self.storage.addTx(txId, data.tx.toHex(), status, data.timestamp)
      return Q.ninvoke(self, 'updateTxInfo', txId, status)

    }).then(function() {
      self.lastStatusCheck.set(txId, true)
      return Q.ninvoke(self.wallet.getCoinManager(), 'applyTx', data.tx)

    })

  }).done(function() { cb(null) }, function(error) { cb(error) })
}

/**
 * @param {string} txId
 * @return {?bitcoinjs-lib.Transaction}
 */
BaseTxDb.prototype.getTxById = function(txId) {
  verify.txId(txId)

  var record = this.storage.getByTxId(txId)
  if (record === null)
    return null

  return bitcoin.Transaction.fromHex(record.rawTx)
}

/**
 * @param {string} txId
 * @return {?number}
 */
BaseTxDb.prototype.getBlockHeightByTxId = function(txId) {
  verify.txId(txId)

  var record = this.storage.getByTxId(txId)
  if (record === null)
    return null

  return record.blockHeight
}

/**
 * @param {string} txId
 * @return {?number}
 */
BaseTxDb.prototype.getTimestampByTxId = function(txId) {
  verify.txId(txId)

  var record = this.storage.getByTxId(txId)
  if (record === null)
    return null

  return record.timestamp
}

/**
 * @param {string} txId
 * @param {number} status
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.maybeRecheckTxStatus = function(txId, status, cb) {
  verify.txId(txId)
  verify.number(status)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    if (status === BaseTxDb.TxStatusConfirmed &&
        !_.isUndefined(self.storage.getByTxId(txId).timestamp))
      return

    if (!_.isUndefined(self.lastStatusCheck.get(txId)))
      return

    self.lastStatusCheck.set(txId, true)

    return Q.ninvoke(self, 'identifyTxStatus', txId).then(function(status) {
      self.storage.setTxStatus(txId, status)
      return Q.ninvoke(self, 'updateTxInfo', txId, status)

    })

  }).done(function() { cb(null) }, function(error) { cb(error) })
}

/**
 * @param {string} txId
 * @param {number} status
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.updateTxInfo = function(txId, status, cb) {
  verify.txId(txId)
  verify.number(status)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    if (status !== BaseTxDb.TxStatusConfirmed)
      return

    return Q.fcall(function() {
      return Q.ninvoke(self.wallet.getBlockchain(), 'getTxBlockHash', txId)

    }).then(function(blockHash) {
      var promise = Q()

      if (_.isUndefined(self.storage.getByTxId(txId).timestamp))
        promise = promise.then(function() {
          return Q.ninvoke(self.wallet.getBlockchain(), 'getBlockTime', blockHash)

        }).then(function(timestamp) {
          self.storage.setTimestamp(txId, timestamp)

        })

      promise = promise.then(function() {
        return Q.ninvoke(self.wallet.getBlockchain(), 'getBlockHeight', blockHash)

      }).then(function(height) {
        self.storage.setBlockHeight(txId, height)

      })

      return promise
    })

  }).done(function() { cb(null) }, function(error) { cb(error) })
}

/**
 * @callback BaseTxDb~isTxConfirmed
 * @param {Error} error
 * @param {boolean} isConfirmed
 */

/**
 * @param {string} txId
 * @param {BaseTxDb~isTxConfirmed} cb
 */
BaseTxDb.prototype.isTxConfirmed = function(txId, cb) {
  verify.txId(txId)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    var record = self.storage.getByTxId(txId)
    if (record === null)
      throw new Error('Tx not found')

    return record.status

  }).then(function(status) {
    if (status === BaseTxDb.TxStatusConfirmed)
      return status

    return Q.ninvoke(self, 'maybeRecheckTxStatus', txId, status)

  }).then(function(status) {
    return status === BaseTxDb.TxStatusConfirmed

  }).done(function(isConfirmed) { cb(null, isConfirmed) }, function(error) { cb(error) })
}

/**
 * @callback BaseTxDb~isTxValid
 * @param {Error} error
 * @param {boolean} isValid
 */

/**
 * @param {string} txId
 * @param {BaseTxDb~isTxValid} cb
 */
BaseTxDb.prototype.isTxValid = function(txId, cb) {
  verify.txId(txId)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    var record = self.storage.getTxById(txId)
    if (record === null)
      throw new Error('Tx not found')

    return record.status

  }).then(function(status) {
    if (status === BaseTxDb.TxStatusConfirmed)
      return status

    return Q.ninvoke(self, 'maybeRecheckTxStatus', txId, status)

  }).then(function(status) {
    return status !== BaseTxDb.TxStatusInvalid

  }).done(function(isValid) { cb(isValid) }, function(error) { cb(error) })
}

module.exports = BaseTxDb
<commit_msg>BaseTxDb EventEmitter<commit_after>var _ = require('lodash')
var LRU = require('lru-cache')
var Q = require('q')

var bitcoin = require('../cclib').bitcoin
var verify = require('../verify')
var inherits = require('util').inherits
var EventEmitter = require('events').EventEmitter;

var RecheckInterval = 60 * 1000

/**
 * @class BaseTxDb
 *
 * @param {Wallet} wallet
 * @param {TxStorage} storage
 */
// Todo: blockchain reorg and double-spending
function BaseTxDb(wallet, storage) {
  verify.Wallet(wallet)
  verify.TxStorage(storage)

  this.wallet = wallet
  this.storage = storage

  this.lastStatusCheck = LRU({ maxAge: RecheckInterval })
}

inherits(BaseTxDb, EventEmitter)

BaseTxDb.TxStatusUnknown = 0
BaseTxDb.TxStatusUnconfirmed = 1
BaseTxDb.TxStatusConfirmed = 2
BaseTxDb.TxStatusInvalid = 3

/**
 * @callback BaseTxDb~errorCallback
 * @param {?Error} error
 */

/**
 * @param {Object} data
 * @param {bitcoinjs-lib.Transaction} data.tx
 * @param {number} [data.timestamp]
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.addUnconfirmedTx = function(data, cb) {
  verify.object(data)

  data = _.extend(data, { status: BaseTxDb.TxStatusUnconfirmed })
  this.addTx(data, cb)
}

/**
 * @param {Object} data
 * @param {bitcoinjs-lib.Transaction} data.tx
 * @param {number} [data.status]
 * @param {number} [data.timestamp]
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.addTx = function(data, cb) {
  verify.object(data)
  verify.Transaction(data.tx)
  if (data.status) verify.number(data.status)
  if (data.timestamp) verify.number(data.timestamp)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    var txId = data.tx.getId()

    var record = self.storage.getByTxId(txId)
    if (record !== null)
      return Q.ninvoke(self, 'maybeRecheckTxStatus', record.txId, record.status)

    return Q.fcall(function() {
      if (_.isUndefined(data.status))
        return Q.ninvoke(self, 'identifyTxStatus', txId)
      return data.status

    }).then(function(status) {
      self.storage.addTx(txId, data.tx.toHex(), status, data.timestamp)
      return Q.ninvoke(self, 'updateTxInfo', txId, status)

    }).then(function() {
      self.lastStatusCheck.set(txId, true)
      return Q.ninvoke(self.wallet.getCoinManager(), 'applyTx', data.tx)

    })

  }).done(
    function() { self.emit('update'); cb(null) },
    function(error) { self.emit('error'); cb(error) }
  )
}

/**
 * @param {string} txId
 * @return {?bitcoinjs-lib.Transaction}
 */
BaseTxDb.prototype.getTxById = function(txId) {
  verify.txId(txId)

  var record = this.storage.getByTxId(txId)
  if (record === null)
    return null

  return bitcoin.Transaction.fromHex(record.rawTx)
}

/**
 * @param {string} txId
 * @return {?number}
 */
BaseTxDb.prototype.getBlockHeightByTxId = function(txId) {
  verify.txId(txId)

  var record = this.storage.getByTxId(txId)
  if (record === null)
    return null

  return record.blockHeight
}

/**
 * @param {string} txId
 * @return {?number}
 */
BaseTxDb.prototype.getTimestampByTxId = function(txId) {
  verify.txId(txId)

  var record = this.storage.getByTxId(txId)
  if (record === null)
    return null

  return record.timestamp
}

/**
 * @param {string} txId
 * @param {number} status
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.maybeRecheckTxStatus = function(txId, status, cb) {
  verify.txId(txId)
  verify.number(status)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    if (status === BaseTxDb.TxStatusConfirmed &&
        !_.isUndefined(self.storage.getByTxId(txId).timestamp))
      return

    if (!_.isUndefined(self.lastStatusCheck.get(txId)))
      return

    self.lastStatusCheck.set(txId, true)

    return Q.ninvoke(self, 'identifyTxStatus', txId).then(function(status) {
      self.storage.setTxStatus(txId, status)
      return Q.ninvoke(self, 'updateTxInfo', txId, status)
    })

  }).done(
    function() { self.emit('update'); cb(null) },
    function(error) { self.emit('error'); cb(error) }
  )
}

/**
 * @param {string} txId
 * @param {number} status
 * @param {BaseTxDb~errorCallback} cb
 */
BaseTxDb.prototype.updateTxInfo = function(txId, status, cb) {
  verify.txId(txId)
  verify.number(status)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    if (status !== BaseTxDb.TxStatusConfirmed)
      return

    return Q.fcall(function() {
      return Q.ninvoke(self.wallet.getBlockchain(), 'getTxBlockHash', txId)

    }).then(function(blockHash) {
      var promise = Q()

      if (_.isUndefined(self.storage.getByTxId(txId).timestamp))
        promise = promise.then(function() {
          return Q.ninvoke(self.wallet.getBlockchain(), 'getBlockTime', blockHash)

        }).then(function(timestamp) {
          self.storage.setTimestamp(txId, timestamp)

        })

      promise = promise.then(function() {
        return Q.ninvoke(self.wallet.getBlockchain(), 'getBlockHeight', blockHash)

      }).then(function(height) {
        self.storage.setBlockHeight(txId, height)

      })

      return promise
    })

  }).done(function() { cb(null) }, function(error) { cb(error) })
}

/**
 * @callback BaseTxDb~isTxConfirmed
 * @param {Error} error
 * @param {boolean} isConfirmed
 */

/**
 * @param {string} txId
 * @param {BaseTxDb~isTxConfirmed} cb
 */
BaseTxDb.prototype.isTxConfirmed = function(txId, cb) {
  verify.txId(txId)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    var record = self.storage.getByTxId(txId)
    if (record === null)
      throw new Error('Tx not found')

    return record.status

  }).then(function(status) {
    if (status === BaseTxDb.TxStatusConfirmed)
      return status

    return Q.ninvoke(self, 'maybeRecheckTxStatus', txId, status)

  }).then(function(status) {
    return status === BaseTxDb.TxStatusConfirmed

  }).done(function(isConfirmed) { cb(null, isConfirmed) }, function(error) { cb(error) })
}

/**
 * @callback BaseTxDb~isTxValid
 * @param {Error} error
 * @param {boolean} isValid
 */

/**
 * @param {string} txId
 * @param {BaseTxDb~isTxValid} cb
 */
BaseTxDb.prototype.isTxValid = function(txId, cb) {
  verify.txId(txId)
  verify.function(cb)

  var self = this

  Q.fcall(function() {
    var record = self.storage.getTxById(txId)
    if (record === null)
      throw new Error('Tx not found')

    return record.status

  }).then(function(status) {
    if (status === BaseTxDb.TxStatusConfirmed)
      return status

    return Q.ninvoke(self, 'maybeRecheckTxStatus', txId, status)

  }).then(function(status) {
    return status !== BaseTxDb.TxStatusInvalid

  }).done(function(isValid) { cb(isValid) }, function(error) { cb(error) })
}

module.exports = BaseTxDb
<|endoftext|>


<commit_before>
mi2JS.addCompClass('base/ListScrollbar', 'Base', '

',

// component initializer function that defines constructor and adds methods to the prototype
function(proto, superProto, comp, mi2, h, t, filters){

	var mi2 = mi2JS;

	proto.initChildren = function(){
		superProto.initChildren.call(this);

		this.allData = this.data = this.chunk = [];
		this.limit = 0;
		this.offset = 0;
		this.scrollAmount = 0;
		this.filter = null;
		this.sort = null;
		this.bar = this.el.firstElementChild;
		this.listen(this.el,'click');
		this.listen(this.el.parentNode,'mouseover', ()=>this.updateScroll);
		this.listen(this.bar,'mousedown');
		this.listen(document,'mousemove');
		this.listen(document,'mouseup');
		this.minLength = 20;
		this.endBuffer = 0;
		this.pivot = 0
	};

	proto.on_click = function(evt){
		if(evt.target == this.el){
			var rect = this.el.getBoundingClientRect();
			var len = this.data.length + this.endBuffer;
			var to = ((evt.pointerY()-rect.top)/this.el.offsetHeight);
			this.fireEvent({name:'scrollTo',pos:to});
			this.setOffset( Math.floor(to*len) );
			this.updateScroll();
		}
	};

	proto.on_show = function(evt){
		if(this.autoScroll && !this.skipResize) this.on_resize({});
	};

	proto.on_mousedown = function(evt){
		evt.stop();
		this.addClass('scroll-moving');
		this.mousedown = true;
	};

	proto.on_mousemove = function(evt){
		if(!this.mousedown) return;
		evt.stop();
		var rect = this.el.getBoundingClientRect();
		var len = this.data.length + this.endBuffer;
		var to = ((evt.pointerY()-rect.top)/this.el.offsetHeight);
		this.setOffset( Math.floor(to*len) );
	};

	proto.on_mouseup = function(evt){
		if(!this.mousedown) return;
		this.removeClass('scroll-moving');
		this.mousedown = false;
	};

	proto.setValue = function(offset,range,max){
		var hor = this.attr('direction') == 'horizontal';
		var style = this.bar.style;
		var maxSize = hor ? this.el.offsetWidth : this.el.offsetHeight;
		var len = Math.floor( (range/max)*maxSize );
		if(len<this.minLength){
			maxSize -= this.minLength;
			range = max/(maxSize)*this.minLength;
			len = this.minLength;
		}
		var pos = Math.floor( ((offset+range)/max)*(maxSize))-len;
		if(hor){
			style.width = len+'px';
			style.left = pos+'px';
		}else{
			style.height = len+'px';
			style.top = pos+'px';
		}
	};

	proto.init = function(list, scrollAmount, autoScroll){
		this.list = list;
		this.scrollAmount = scrollAmount || 1;
		// FF
		this.listen(this.list.el.parentNode,'DOMMouseScroll',this.on_mousewheel);
		// other
		this.listen(this.list.el.parentNode,'mousewheel');

		this.autoScroll = autoScroll;
		if(autoScroll){
			this.listen(MAIN_APP, 'resizeContent', this.on_resize);
		}
	};

	proto.on_resize = function(evt){
		this.skipResize = true;

		this.list.setVisible(false);
		this.attr('hidden', true);
		var h = this.list.el.parentNode.offsetHeight;
		this.list.setVisible(true);
		this.attr('hidden', false);
		var limit = Math.floor(h/this.autoScroll);
		if(limit) this.setLimit(limit);
		if(!evt.skipUpdate) this.applyLimit();

		this.skipResize = false;
	};

	proto.on_mousewheel = function(evt){
		var dir = evt.deltaY || evt.detail;
		// this.moveOffset(this.limit * (dir > 0 ? 1:-1) );
		if(this.moveOffset(this.scrollAmount * (dir > 0 ? 1:-1) ))
			evt.stop();
	};

	proto.updateScroll = function(data){
		cancelAnimationFrame(this._updateScroll_timer);
		this._updateScroll_timer = this.requestAnimationFrame(function(){
			var len = this.data.length + this.endBuffer;
			var vis = this.limit < len;
			this.skipResize = true;
			if(this.isVisible() != vis) this.setVisible(vis);
			this.skipResize = false;
			this.setValue( this.offset, this.limit, len );
		    if(data && this.list) this.list.setValue(this.chunk)
		    if(data) this.fireEvent({name: 'afterUpdate', list:this.list, listData:data})

		});
	};

	function makeAsc(column){
		return function(a,b){
			if (a[column] == b[column]) return 0;
			return a[column] > b[column] ? 1:-1;
		}
	}

	function makeDesc(column){
		return function(a,b){
			if (a[column] == b[column]) return 0;
			return a[column] > b[column] ? -1:1;
		}
	}

	proto.setOrderColumn = function(order){
		if(order){
			this.setSort( order[1] == 'DESC' ?  makeDesc(order[0]) : makeAsc(order[0]));
		}else{
			this.setSort(null);
		}
	};

	proto.newData = function(allData){
	    this.allData = allData || [];
	    this.applySort();
	    this.applyFilter();
	    this.applyLimit();
	};

	proto.moveOffset = function(move){
		return this.setOffset(this.offset + move);
	};

	proto.setOffset = function(offset, limit){
		var old = this.offset;
		this.offset = offset;
		if(limit !== void 0) this.limit = limit;
		this.applyLimit();
		return old != this.offset;
	};

	proto.setLimit = function(limit){
	  this.limit = limit;
	  this.applyLimit();
	};

	proto.setFilter = function(filter){
	  this.filter = filter;
	  this.applyFilter();
	  this.applyLimit();
	};

	proto.setSort = function(sort){
	  this.sort = sort;
	  this.applySort();
	  this.applyFilter();
	  this.applyLimit();
	};

	proto.applySort = function(){
	  if(this.sort) this.allData.sort(this.sort);
	};

	proto.applyFilter = function(){
	    if(this.filter){
	      this.data = this.allData.filter(this.filter);
	    }else{
	      this.data = this.allData;
	    }
	};

	proto.applyLimit = function(){
	    var data = this.data;
	    var len = data.length + this.endBuffer;
	    if(this.limit){
	      if(this.limit + this.offset > len) this.offset = len - this.limit;
	      if(this.offset < 0) this.offset = 0;
	      let offset = this.offset
	      var to = this.offset + this.limit
	      let chunk = this.data.slice(this.offset, to)

	      for(let i = this.pivot-1; i>=0; i--){
	      	if(i<offset) chunk.unshift(data[i])
	      }

	      if(chunk.length > this.limit){
	      	chunk.length = this.limit
	      }
	      this.chunk = chunk
	    }else{
	      this.chunk = this.data;
	    }
	    this.updateScroll(this.chunk)
	};

	proto.makeIndexVisible = function(idx){
		if(!(idx >= this.offset && idx<this.offset+this.limit)){
			this.setOffset(Math.round(idx-this.limit/2));
		}
	};

});<commit_msg>Update ListScrollbar.js<commit_after>
mi2JS.addCompClass('base/ListScrollbar', 'Base', '

',

// component initializer function that defines constructor and adds methods to the prototype
function(proto, superProto, comp, mi2, h, t, filters){

	var mi2 = mi2JS;

	proto.initChildren = function(){
		superProto.initChildren.call(this);

		this.allData = this.data = this.chunk = [];
		this.limit = 0;
		this.offset = 0;
		this.scrollAmount = 0;
		this.filter = null;
		this.sort = null;
		this.bar = this.el.firstElementChild;
		this.listen(this.el,'click');
		this.listen(this.el.parentNode,'mouseover', ()=>this.updateScroll);
		this.listen(this.bar,'mousedown');
		this.listen(document,'mousemove');
		this.listen(document,'mouseup');
		this.minLength = 20;
		this.endBuffer = 0;
		this.pivot = 0
		this.maxLimit = 50
	};

	proto.on_click = function(evt){
		if(evt.target == this.el){
			var rect = this.el.getBoundingClientRect();
			var len = this.data.length + this.endBuffer;
			var to = ((evt.pointerY()-rect.top)/this.el.offsetHeight);
			this.fireEvent({name:'scrollTo',pos:to});
			this.setOffset( Math.floor(to*len) );
			this.updateScroll();
		}
	};

	proto.on_show = function(evt){
		if(this.autoScroll && !this.skipResize) this.on_resize({});
	};

	proto.on_init = function(evt){
		this.setTimeout(()=>this.on_resize({}),100);
	};

	proto.on_mousedown = function(evt){
		evt.stop();
		this.addClass('scroll-moving');
		this.mousedown = true;
	};

	proto.on_mousemove = function(evt){
		if(!this.mousedown) return;
		evt.stop();
		var rect = this.el.getBoundingClientRect();
		var len = this.data.length + this.endBuffer;
		var to = ((evt.pointerY()-rect.top)/this.el.offsetHeight);
		this.setOffset( Math.floor(to*len) );
	};

	proto.on_mouseup = function(evt){
		if(!this.mousedown) return;
		this.removeClass('scroll-moving');
		this.mousedown = false;
	};

	proto.setValue = function(offset,range,max){
		var hor = this.attr('direction') == 'horizontal';
		var style = this.bar.style;
		var maxSize = hor ? this.el.offsetWidth : this.el.offsetHeight;
		var len = Math.floor( (range/max)*maxSize );
		if(len<this.minLength){
			maxSize -= this.minLength;
			range = max/(maxSize)*this.minLength;
			len = this.minLength;
		}
		var pos = Math.floor( ((offset+range)/max)*(maxSize))-len;
		if(hor){
			style.width = len+'px';
			style.left = pos+'px';
		}else{
			style.height = len+'px';
			style.top = pos+'px';
		}
	};

	proto.init = function(list, scrollAmount, autoScroll){
		this.list = list;
		this.scrollAmount = scrollAmount || 1;
		// FF
		this.listen(this.list.el.parentNode,'DOMMouseScroll',this.on_mousewheel);
		// other
		this.listen(this.list.el.parentNode,'mousewheel');

		this.autoScroll = autoScroll;
		if(autoScroll){
			this.listen(MAIN_APP, 'resizeContent', this.on_resize);
		}
	};

	proto.setPivot = function(pivot){
		this.pivot = pivot
		this.on_resize({skipUpdate:true})
	};

	proto.on_resize = function(evt){
		this.skipResize = true;

		this.list.setVisible(false);
		this.attr('hidden', true);
		var h = this.list.el.parentNode.offsetHeight;
		this.list.setVisible(true);
		this.attr('hidden', false);
		var limit = Math.min(Math.floor(h/this.autoScroll),this.maxLimit)
		if(this.autoScroll){
			this.el.style.height = ((limit-this.pivot)*this.autoScroll)+'px'
			this.el.style.marginTop = (this.pivot*this.autoScroll)+'px'
		}
		if(limit) this.setLimit(limit);
		if(!evt.skipUpdate) this.applyLimit();

		this.skipResize = false;
	};

	proto.on_mousewheel = function(evt){
		var dir = evt.deltaY || evt.detail;
		// this.moveOffset(this.limit * (dir > 0 ? 1:-1) );
		if(this.moveOffset(this.scrollAmount * (dir > 0 ? 1:-1) ))
			evt.stop();
	};

	proto.updateScroll = function(data){
		cancelAnimationFrame(this._updateScroll_timer);
		this._updateScroll_timer = this.requestAnimationFrame(function(){
			var len = this.data.length + this.endBuffer;
			var vis = this.limit < len;
			this.skipResize = true;
			if(this.isVisible() != vis) this.setVisible(vis);
			this.skipResize = false;
			this.setValue( this.offset, this.limit, len );
		    if(data && this.list) this.list.setValue(this.chunk)
		    if(data) this.fireEvent({name: 'afterUpdate', list:this.list, listData:data})

		});
	};

	function makeAsc(column){
		return function(a,b){
			if (a[column] == b[column]) return 0;
			return a[column] > b[column] ? 1:-1;
		}
	}

	function makeDesc(column){
		return function(a,b){
			if (a[column] == b[column]) return 0;
			return a[column] > b[column] ? -1:1;
		}
	}

	proto.setOrderColumn = function(order){
		if(order){
			this.setSort( order[1] == 'DESC' ?  makeDesc(order[0]) : makeAsc(order[0]));
		}else{
			this.setSort(null);
		}
	};

	proto.newData = function(allData){
	    this.allData = allData || [];
	    this.applySort();
	    this.applyFilter();
	    this.applyLimit();
	};

	proto.moveOffset = function(move){
		return this.setOffset(this.offset + move);
	};

	proto.setOffset = function(offset, limit){
		var old = this.offset;
		this.offset = offset;
		if(limit !== void 0) this.limit = limit;
		this.applyLimit();
		return old != this.offset;
	};

	proto.setLimit = function(limit){
	  this.limit = limit;
	  this.applyLimit();
	};

	proto.setFilter = function(filter){
	  this.filter = filter;
	  this.applyFilter();
	  this.applyLimit();
	};

	proto.setSort = function(sort){
	  this.sort = sort;
	  this.applySort();
	  this.applyFilter();
	  this.applyLimit();
	};

	proto.applySort = function(){
	  if(this.sort) this.allData.sort(this.sort);
	};

	proto.applyFilter = function(){
	    if(this.filter){
	      this.data = this.allData.filter(this.filter);
	    }else{
	      this.data = this.allData;
	    }
	};

	proto.applyLimit = function(){
	    var data = this.data;
	    var len = data.length + this.endBuffer
	    if(len > this.maxLimit){
	    	this.limit = this.maxLimit
	    }
	    if(this.limit){
	      if(this.limit + this.offset > len) this.offset = len - this.limit;
	      if(this.offset < 0) this.offset = 0;
	      let offset = this.offset
	      var to = this.offset + this.limit
	      let chunk = this.data.slice(this.offset, to)

	      for(let i = this.pivot-1; i>=0; i--){
	      	if(i<offset) chunk.unshift(data[i])
	      }

	      if(chunk.length > this.limit){
	      	chunk.length = this.limit
	      }
	      this.chunk = chunk
	    }else{
	      this.chunk = this.data;
	    }
	    this.updateScroll(this.chunk)
	};

	proto.makeIndexVisible = function(idx){
		if(!(idx >= this.offset && idx<this.offset+this.limit)){
			this.setOffset(Math.round(idx-this.limit/2));
		}
	};

});<|endoftext|>


<commit_before>// Created: 04/13/2006
// Updated: 04/13/2006

// file_info class
// Keeps track of the information for the currently displayed image
// and fetches the information via dirlists or from the URL.
function file_info() {

  // *******************************************
  // Private variables:
  // *******************************************

  this.page_in_use = 0; // Describes if we already see an image.
  this.dir_name = null;
  this.im_name = null;
  //added mov_name to support video mode 12.12.06 jmejia
  this.mov_name = null;
  this.collection = 'LabelMe';
  this.mode = 'i'; //initialize to picture mode
  this.hitId = null;
  this.assignmentId = null;
  this.workerId = null;
  this.mt_instructions = null;

  // *******************************************
  // Public methods:
  // *******************************************

  // Parses the URL and gets the collection, directory, and filename
  // information of the image to be annotated.  Returns true if the
  // URL has collection, directory, and filename information.
  this.ParseURL = function () {
    var labelme_url = document.URL;
    var idx = labelme_url.indexOf('?');
    if((idx != -1) && (this.page_in_use == 0)) {
      this.page_in_use = 1;
      var par_str = labelme_url.substring(idx+1,labelme_url.length);
      var isMT = false; // In MT mode?
      var default_view_ObjList = false;
      do {
        idx = par_str.indexOf('&');
	var par_tag;
	if(idx == -1) par_tag = par_str;
	else par_tag = par_str.substring(0,idx);
	var par_field = this.GetURLField(par_tag);
	var par_value = this.GetURLValue(par_tag);
	if(par_field=='movie'){
	  this.mov_name = par_value;
	}
	if(par_field=='mode'){
	  this.mode = par_value;
	  if(this.mode=='im' || this.mode=='mt') view_ObjList = false;
	  if(this.mode=='mt') isMT = true;
	}
	if(par_field=='username') {
          username = par_value;
	}
	if(par_field=='collection') {
          this.collection = par_value;
	}
	if(par_field=='folder') {
          this.dir_name = par_value;
	}
	if(par_field=='image') {
          this.im_name = par_value;
	  if(this.im_name.indexOf('.jpg')==-1 && this.im_name.indexOf('.png')==-1) {
	    this.im_name = this.im_name + '.jpg';
	  }
        }
	if(par_field=='hitId') {
	  this.hitId = par_value;
	  isMT = true;
	}
	if(par_field=='turkSubmitTo') {
	  isMT = true;
	}
	if(par_field=='assignmentId') {
	  this.assignmentId = par_value;
	  isMT = true;
	}
	if((par_field=='mt_sandbox') && (par_value=='true')) {
	  externalSubmitURL = externalSubmitURLsandbox;
	}
	if(par_field=='N') {
	  mt_N = par_value;
	}
	if(par_field=='workerId') {
	  this.workerId = par_value;
	  isMT = true;

	  // Get second-half of workerId:
	  var len = Math.round(this.workerId.length/2);
	  username = 'MT_' + this.workerId.substring(len-1,this.workerId.length);
	}
	if(par_field=='mt_intro') {
	  MThelpPage = par_value;
	}
	if(par_field=='actions') {
	  // Get allowable actions:
	  var actions = par_value;
	  action_CreatePolygon = 0;
	  action_RenameExistingObjects = 0;
	  action_ModifyControlExistingObjects = 0;
	  action_DeleteExistingObjects = 0;
	  if(actions.indexOf('n')!=-1) action_CreatePolygon = 1;
	  if(actions.indexOf('r')!=-1) action_RenameExistingObjects = 1;
	  if(actions.indexOf('m')!=-1) action_ModifyControlExistingObjects = 1;
	  if(actions.indexOf('d')!=-1) action_DeleteExistingObjects = 1;
	  if(actions.indexOf('a')!=-1) {
	    action_CreatePolygon = 1;
	    action_RenameExistingObjects = 1;
	    action_ModifyControlExistingObjects = 1;
	    action_DeleteExistingObjects = 1;
	  }
	  if(actions.indexOf('v')!=-1) {
	    action_CreatePolygon = 0;
	    action_RenameExistingObjects = 0;
	    action_ModifyControlExistingObjects = 0;
	    action_DeleteExistingObjects = 0;
	  }
	}
	if(par_field=='viewobj') {
	  // Get option for which polygons to see:
	  var viewobj = par_value;
	  view_Existing = 0;
	  view_Deleted = 0;
	  if(viewobj.indexOf('e')!=-1) view_Existing = 1;
	  if(viewobj.indexOf('d')!=-1) view_Deleted = 1;
	  if(viewobj.indexOf('a')!=-1) {
	    view_Deleted = 1;
	    view_Existing = 1;
	  }
	}
	if(par_field=='objlist') {
	  if(par_value=='visible') {
	    view_ObjList = true;
	    default_view_ObjList = true;
	  }
	  if(par_value=='hidden') {
	    view_ObjList = false;
	    default_view_ObjList = false;
	  }
	}
	if(par_field=='mt_instructions') {
	  // One line MT instructions:
	  this.mt_instructions = par_value;
	  this.mt_instructions = this.mt_instructions.replace(/_/g,' ');
	}
	if(par_field=='objects') {
	  // Set drop-down list of object to label:
	  object_choices = par_value.replace('_',' ');
	  object_choices = object_choices.split(/,/);
	}
        par_str = par_str.substring(idx+1,par_str.length);
      } while(idx != -1);
      if((!this.dir_name) || (!this.im_name)) return this.SetURL(labelme_url);

      if(isMT) {
	this.mode='mt'; // Ensure that we are in MT mode
	view_ObjList = default_view_ObjList;
      }

      if((this.mode=='i') || (this.mode=='v') || (this.mode=='c') || (this.mode=='f')) {
	document.getElementById('body').style.visibility = 'visible';
      }
      else if((this.mode=='im') || (this.mode=='mt')) {
	var p = document.getElementById('header');
	p.parentNode.removeChild(p);
	var p = document.getElementById('username_main_div');
	p.parentNode.removeChild(p);
	var p = document.getElementById('counter_div');
	p.parentNode.removeChild(p);
	var p = document.getElementById('img_xml_download_div');
	p.parentNode.removeChild(p);
	document.getElementById('body').style.visibility = 'visible';
      }
      else {
	this.mode = 'i';
	document.getElementById('body').style.visibility = 'visible';
      }

      if(!view_ObjList) {
	var p = document.getElementById('right_side');
	p.parentNode.removeChild(p);
      }

      if(this.assignmentId=='ASSIGNMENT_ID_NOT_AVAILABLE') {
	window.location = MThelpPage;
	return false;
      }
      if(this.mode=='mt') {
	if(!this.mt_instructions) {
	  if(mt_N=='inf') this.mt_instructions = 'Please label as many objects as you want in this image.';
	  else if(mt_N==1) this.mt_instructions = 'Please label at least ' + mt_N + ' object in this image.';
	  else this.mt_instructions = 'Please label at least ' + mt_N + ' objects in this image.';
	}
	if(mt_N=='inf') mt_N = 1;

	var html_str = '

' + this.mt_instructions + '  Scroll down to see the entire image.     	<form action="' + externalSubmitURL + '"><input type="hidden" id="assignmentId" name="assignmentId" value="'+ this.assignmentId +'" /><input type="hidden" id="number_objects" name="number_objects" value="" /><input type="hidden" id="object_name" name="object_name" value="" /><input type="hidden" id="LMurl" name="LMurl" value="" /><input type="hidden" id="mt_comments" name="mt_comments" value="" /><input disabled="true" type="submit" id="mt_submit" name="Submit" value="Submit HIT" onmousedown="javascript:document.getElementById(\'mt_comments\').value=document.getElementById(\'mt_comments_textbox\').value;" /></form>

';

	InsertAfterDiv(html_str,'mt_submit_form');

	var html_str2 = 'Scroll up to see the entire image   (Optional) Do you wish to provide any feedback on this HIT?
<textarea id="mt_comments_textbox" name="mt_comments_texbox" cols="94" nrows="5" />';
	InsertAfterDiv(html_str2,'mt_feedback');

	if(global_count >= mt_N) document.getElementById('mt_submit').disabled=false;
      }
    }
    else {
      return this.SetURL(labelme_url);
    }
    return 1;
  };

  //get video or picture mode 12.12.06 jmejia
  this.GetMode = function() {
    return this.mode;
  };

  this.GetCollection = function () {
    return this.collection;
  };

  this.GetDirName = function () {
    return this.dir_name;
  };

  this.GetImName = function () {
    return this.im_name;
  };

  this.SetImName = function (newImName){
    this.im_name = newImName;
  };

  //get the movie name 12.12.06 jmejia
  this.GetMovName = function () {
    return this.mov_name;
  };

  //change to support video mode
  this.GetImagePath = function () {
    if((this.mode=='i') || (this.mode=='c') || (this.mode=='f') || (this.mode=='im') || (this.mode=='mt')) return 'Images/' + this.dir_name + '/' + this.im_name;
    if(this.mode == 'v') return 'Video/Frames/' + this.dir_name + '/' + this.mov_name + '/' + this.im_name;
  };

  this.GetAnnotationPath = function () {
    if((this.mode=='i') || (this.mode=='c') || (this.mode=='f') || (this.mode=='im') || (this.mode=='mt')) return 'Annotations/' + this.dir_name + '/' + this.im_name.substr(0,this.im_name.length-4) + '.xml';
    if(this.mode =='v') return 'Video/Annotations/' + this.dir_name + '/' + this.mov_name + '.xml';
  };

  this.GetFullName = function () {
    if((this.mode=='i') || (this.mode=='c') || (this.mode=='f') || (this.mode=='im') || (this.mode=='mt')) return this.dir_name + '/' + this.im_name;
    if(this.mode == 'v') return this.dir_name + '/' + this.mov_name;
  };

  this.GetTemplatePath = function () {
    if(!this.dir_name) return 'annotationCache/XMLTemplates/labelme.xml';
    return 'annotationCache/XMLTemplates/' + this.dir_name + '.xml';
  };

  // *******************************************
  // Private methods:
  // *******************************************

  // String is assumed to have field=value form.  Parses string to
  // return the field.
  this.GetURLField = function (str) {
    var idx = str.indexOf('=');
    return str.substring(0,idx);
  };

  // String is assumed to have field=value form.  Parses string to
  // return the value.
  this.GetURLValue = function (str) {
    var idx = str.indexOf('=');
    return str.substring(idx+1,str.length);
  };

  // Changes current URL to include collection, directory, and image
  // name information.  Returns false.
  this.SetURL = function (url) {
    this.FetchImage();

    var idx = url.indexOf('?');
    var tail = '';
    if(idx != -1) {
      tail = url.substring(idx+1,url.length);
      url = url.substring(0,idx);
    }

    // Include username in URL:
    var extra_field = '';
    if(username != 'anonymous') extra_field = '&username=' + username;

    if(this.mode=='i') window.location = url + '?collection=' + this.collection + '&mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
    else if(this.mode=='im') window.location = url + '?collection=' + this.collection + '&mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
    else if(this.mode=='mt') window.location = url + '?collection=' + this.collection + '&mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
    else if(this.mode=='c') window.location = url + '?mode=' + this.mode + '&username=' + username + '&collection=' + this.collection + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
    else if(this.mode=='f') window.location = url + '?mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
    return false;
  };

  // Fetch next image.
  this.FetchImage = function () {
    var url = 'annotationTools/perl/fetch_image.cgi?mode=' + this.mode + '&username=' + username + '&collection=' + this.collection.toLowerCase() + '&folder=' + this.dir_name + '&image=' + this.im_name;
    var im_req;
    // branch for native XMLHttpRequest object
    if (window.XMLHttpRequest) {
      im_req = new XMLHttpRequest();
      im_req.open("GET", url, false);
      im_req.send('');
    }
    else if (window.ActiveXObject) {
      im_req = new ActiveXObject("Microsoft.XMLHTTP");
      if (im_req) {
        im_req.open("GET", url, false);
	im_req.send('');
      }
    }

    if(im_req.status==200) {
      this.dir_name = im_req.responseXML.getElementsByTagName("dir")[0].firstChild.nodeValue;
      this.im_name = im_req.responseXML.getElementsByTagName("file")[0].firstChild.nodeValue;
    }
    else {
      alert('Fatal: there are problems with fetch_image.cgi');
    }
  };
}
<commit_msg>zoom fixed<commit_after>// Created: 04/13/2006
// Updated: 04/13/2006

// file_info class
// Keeps track of the information for the currently displayed image
// and fetches the information via dirlists or from the URL.
function file_info() {

    // *******************************************
    // Private variables:
    // *******************************************

    this.page_in_use = 0; // Describes if we already see an image.
    this.dir_name = null;
    this.im_name = null;
    //added mov_name to support video mode 12.12.06 jmejia
    this.mov_name = null;
    this.collection = 'LabelMe';
    this.mode = 'i'; //initialize to picture mode
    this.hitId = null;
    this.assignmentId = null;
    this.workerId = null;
    this.mt_instructions = null;

    // *******************************************
    // Public methods:
    // *******************************************

    // Parses the URL and gets the collection, directory, and filename
    // information of the image to be annotated.  Returns true if the
    // URL has collection, directory, and filename information.
    this.ParseURL = function () {
        var labelme_url = document.URL;
        var idx = labelme_url.indexOf('?');
        if((idx != -1) && (this.page_in_use == 0)) {
            this.page_in_use = 1;
            var par_str = labelme_url.substring(idx+1,labelme_url.length);
            var isMT = false; // In MT mode?
            var default_view_ObjList = false;
            do {
                idx = par_str.indexOf('&');
                var par_tag;
                if(idx == -1) par_tag = par_str;
                else par_tag = par_str.substring(0,idx);
                var par_field = this.GetURLField(par_tag);
                var par_value = this.GetURLValue(par_tag);
                if(par_field=='movie'){
                    this.mov_name = par_value;
                }
                if(par_field=='mode'){
                    this.mode = par_value;
                    if(this.mode=='im' || this.mode=='mt') view_ObjList = false;
                    if(this.mode=='mt') isMT = true;
                }
                if(par_field=='username') {
                    username = par_value;
                }
                if(par_field=='collection') {
                    this.collection = par_value;
                }
                if(par_field=='folder') {
                    this.dir_name = par_value;
                }
                if(par_field=='image') {
                    this.im_name = par_value;
                    if(this.im_name.indexOf('.jpg')==-1 && this.im_name.indexOf('.png')==-1) {
                        this.im_name = this.im_name + '.jpg';
                    }
                }
                if(par_field=='hitId') {
                    this.hitId = par_value;
                    isMT = true;
                }
                if(par_field=='turkSubmitTo') {
                    isMT = true;
                }
                if(par_field=='assignmentId') {
                    this.assignmentId = par_value;
                    isMT = true;
                }
                if((par_field=='mt_sandbox') && (par_value=='true')) {
                    externalSubmitURL = externalSubmitURLsandbox;
                }
                if(par_field=='N') {
                    mt_N = par_value;
                }
                if(par_field=='workerId') {
                    this.workerId = par_value;
                    isMT = true;

                    // Get second-half of workerId:
                    var len = Math.round(this.workerId.length/2);
                    username = 'MT_' + this.workerId.substring(len-1,this.workerId.length);
                }
                if(par_field=='mt_intro') {
                    MThelpPage = par_value;
                }
                if(par_field=='actions') {
                    // Get allowable actions:
                    var actions = par_value;
                    action_CreatePolygon = 0;
                    action_RenameExistingObjects = 0;
                    action_ModifyControlExistingObjects = 0;
                    action_DeleteExistingObjects = 0;
                    if(actions.indexOf('n')!=-1) action_CreatePolygon = 1;
                    if(actions.indexOf('r')!=-1) action_RenameExistingObjects = 1;
                    if(actions.indexOf('m')!=-1) action_ModifyControlExistingObjects = 1;
                    if(actions.indexOf('d')!=-1) action_DeleteExistingObjects = 1;
                    if(actions.indexOf('a')!=-1) {
                        action_CreatePolygon = 1;
                        action_RenameExistingObjects = 1;
                        action_ModifyControlExistingObjects = 1;
                        action_DeleteExistingObjects = 1;
                    }
                    if(actions.indexOf('v')!=-1) {
                        action_CreatePolygon = 0;
                        action_RenameExistingObjects = 0;
                        action_ModifyControlExistingObjects = 0;
                        action_DeleteExistingObjects = 0;
                    }
                }
                if(par_field=='viewobj') {
                    // Get option for which polygons to see:
                    var viewobj = par_value;
                    view_Existing = 0;
                    view_Deleted = 0;
                    if(viewobj.indexOf('e')!=-1) view_Existing = 1;
                    if(viewobj.indexOf('d')!=-1) view_Deleted = 1;
                    if(viewobj.indexOf('a')!=-1) {
                        view_Deleted = 1;
                        view_Existing = 1;
                    }
                }
                if(par_field=='objlist') {
                    if(par_value=='visible') {
                        view_ObjList = true;
                        default_view_ObjList = true;
                    }
                    if(par_value=='hidden') {
                        view_ObjList = false;
                        default_view_ObjList = false;
                    }
                }
                if(par_field=='mt_instructions') {
                    // One line MT instructions:
                    this.mt_instructions = par_value;
                    this.mt_instructions = this.mt_instructions.replace(/_/g,' ');
                }
                if(par_field=='objects') {
                    // Set drop-down list of object to label:
                    object_choices = par_value.replace('_',' ');
                    object_choices = object_choices.split(/,/);
                }
                par_str = par_str.substring(idx+1,par_str.length);
            } while(idx != -1);
            if((!this.dir_name) || (!this.im_name)) return this.SetURL(labelme_url);

            if(isMT) {
                this.mode='mt'; // Ensure that we are in MT mode
                view_ObjList = default_view_ObjList;
            }

            if((this.mode=='i') || (this.mode=='v') || (this.mode=='c') || (this.mode=='f')) {
                document.getElementById('body').style.visibility = 'visible';
            }
            else if((this.mode=='im') || (this.mode=='mt')) {
                var p = document.getElementById('header');
                p.parentNode.removeChild(p);
                //var p = document.getElementById('username_main_div');
                //p.parentNode.removeChild(p);
                //var p = document.getElementById('counter_div');
                //p.parentNode.removeChild(p);
                var p = document.getElementById('tool_buttons');
                p.parentNode.removeChild(p);
                document.getElementById('body').style.visibility = 'visible';
            }
            else {
                this.mode = 'i';
                document.getElementById('body').style.visibility = 'visible';
            }

            if(!view_ObjList) {
                var p = document.getElementById('anno_anchor');
                p.parentNode.removeChild(p);
            }

            if(this.assignmentId=='ASSIGNMENT_ID_NOT_AVAILABLE') {
                window.location = MThelpPage;
                return false;
            }
            if(this.mode=='mt') {
                if(!this.mt_instructions) {
                    if(mt_N=='inf') this.mt_instructions = 'Please label as many objects as you want in this image.';
                    else if(mt_N==1) this.mt_instructions = 'Please label at least ' + mt_N + ' object in this image.';
                    else this.mt_instructions = 'Please label at least ' + mt_N + ' objects in this image.';
                }
                if(mt_N=='inf') mt_N = 1;

                var html_str = '

' + this.mt_instructions + '  Scroll down to see the entire image.     	<form action="' + externalSubmitURL + '"><input type="hidden" id="assignmentId" name="assignmentId" value="'+ this.assignmentId +'" /><input type="hidden" id="number_objects" name="number_objects" value="" /><input type="hidden" id="object_name" name="object_name" value="" /><input type="hidden" id="LMurl" name="LMurl" value="" /><input type="hidden" id="mt_comments" name="mt_comments" value="" /><input disabled="true" type="submit" id="mt_submit" name="Submit" value="Submit HIT" onmousedown="javascript:document.getElementById(\'mt_comments\').value=document.getElementById(\'mt_comments_textbox\').value;" /></form>

';

                InsertAfterDiv(html_str,'mt_submit_form');

                var html_str2 = 'Scroll up to see the entire image   (Optional) Do you wish to provide any feedback on this HIT?
<textarea id="mt_comments_textbox" name="mt_comments_texbox" cols="94" nrows="5" />';
                InsertAfterDiv(html_str2,'mt_feedback');

                if(global_count >= mt_N) document.getElementById('mt_submit').disabled=false;
            }
        }
        else {
            return this.SetURL(labelme_url);
        }

        return 1;
    };

    //get video or picture mode 12.12.06 jmejia
    this.GetMode = function() {
        return this.mode;
    };

    this.GetCollection = function () {
        return this.collection;
    };

    this.GetDirName = function () {
        return this.dir_name;
    };

    this.GetImName = function () {
        return this.im_name;
    };

    this.SetImName = function (newImName){
        this.im_name = newImName;
    };

    //get the movie name 12.12.06 jmejia
    this.GetMovName = function () {
        return this.mov_name;
    };

    //change to support video mode
    this.GetImagePath = function () {
        if((this.mode=='i') || (this.mode=='c') || (this.mode=='f') || (this.mode=='im') || (this.mode=='mt')) return 'Images/' + this.dir_name + '/' + this.im_name;
        if(this.mode == 'v') return 'Video/Frames/' + this.dir_name + '/' + this.mov_name + '/' + this.im_name;
    };

    this.GetAnnotationPath = function () {
        if((this.mode=='i') || (this.mode=='c') || (this.mode=='f') || (this.mode=='im') || (this.mode=='mt')) return 'Annotations/' + this.dir_name + '/' + this.im_name.substr(0,this.im_name.length-4) + '.xml';
        if(this.mode =='v') return 'Video/Annotations/' + this.dir_name + '/' + this.mov_name + '.xml';
    };

    this.GetFullName = function () {
        if((this.mode=='i') || (this.mode=='c') || (this.mode=='f') || (this.mode=='im') || (this.mode=='mt')) return this.dir_name + '/' + this.im_name;
        if(this.mode == 'v') return this.dir_name + '/' + this.mov_name;
    };

    this.GetTemplatePath = function () {
        if(!this.dir_name) return 'annotationCache/XMLTemplates/labelme.xml';
        return 'annotationCache/XMLTemplates/' + this.dir_name + '.xml';
    };

    // *******************************************
    // Private methods:
    // *******************************************

    // String is assumed to have field=value form.  Parses string to
    // return the field.
    this.GetURLField = function (str) {
        var idx = str.indexOf('=');
        return str.substring(0,idx);
    };

    // String is assumed to have field=value form.  Parses string to
    // return the value.
    this.GetURLValue = function (str) {
        var idx = str.indexOf('=');
        return str.substring(idx+1,str.length);
    };

    // Changes current URL to include collection, directory, and image
    // name information.  Returns false.
    this.SetURL = function (url) {
        this.FetchImage();

        var idx = url.indexOf('?');
        var tail = '';
        if(idx != -1) {
            tail = url.substring(idx+1,url.length);
            url = url.substring(0,idx);
        }

        // Include username in URL:
        var extra_field = '';
        if(username != 'anonymous') extra_field = '&username=' + username;

        if(this.mode=='i') window.location = url + '?collection=' + this.collection + '&mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
        else if(this.mode=='im') window.location = url + '?collection=' + this.collection + '&mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
        else if(this.mode=='mt') window.location = url + '?collection=' + this.collection + '&mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
        else if(this.mode=='c') window.location = url + '?mode=' + this.mode + '&username=' + username + '&collection=' + this.collection + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
        else if(this.mode=='f') window.location = url + '?mode=' + this.mode + '&folder=' + this.dir_name + '&image=' + this.im_name + extra_field;
        return false;
    };

    // Fetch next image.
    this.FetchImage = function () {
        var url = 'annotationTools/perl/fetch_image.cgi?mode=' + this.mode + '&username=' + username + '&collection=' + this.collection.toLowerCase() + '&folder=' + this.dir_name + '&image=' + this.im_name;
        var im_req;
        // branch for native XMLHttpRequest object
        if (window.XMLHttpRequest) {
            im_req = new XMLHttpRequest();
            im_req.open("GET", url, false);
            im_req.send('');
        }
        else if (window.ActiveXObject) {
            im_req = new ActiveXObject("Microsoft.XMLHTTP");
            if (im_req) {
                im_req.open("GET", url, false);
                im_req.send('');
            }
        }

        if(im_req.status==200) {
            this.dir_name = im_req.responseXML.getElementsByTagName("dir")[0].firstChild.nodeValue;
            this.im_name = im_req.responseXML.getElementsByTagName("file")[0].firstChild.nodeValue;
        }
        else {
            alert('Fatal: there are problems with fetch_image.cgi');
        }
    };
}
<|endoftext|>


<commit_before>/**
 * 表示当前对象
 *
 * Created by GUY on 2017/5/23.
 * @class BI.ListView
 * @extends BI.Widget
 */
BI.ListView = BI.inherit(BI.Widget, {
    props: function () {
        return {
            baseCls: "bi-list-view",
            overscanHeight: 100,
            blockSize: 10,
            scrollTop: 0,
            el: {},
            items: []
        };
    },

    init: function () {
        var self = this;
        this.renderedIndex = -1;
        this.cache = {};
    },

    render: function () {
        var self = this, o = this.options;
        return {
            type: "bi.vertical",
            items: [BI.extend({
                type: "bi.vertical",
                scrolly: false,
                ref: function () {
                    self.container = this;
                }
            }, o.el)],
            element: this
        };
    },

    mounted: function () {
        var self = this, o = this.options;
        this._populate();
        this.element.scroll(function (e) {
            o.scrollTop = self.element.scrollTop();
            self._calculateBlocksToRender();
        });
        var lastWidth = this.element.width(),
            lastHeight = this.element.height();
        BI.ResizeDetector.addResizeListener(this, function () {
            var width = self.element.width(),
                height = self.element.height();
            if (width !== lastWidth || height !== lastHeight) {
                self._calculateBlocksToRender();
                lastWidth = width;
                lastHeight = height;
            }
        });
    },

    _renderMoreIf: function () {
        var self = this, o = this.options;
        var height = this.element.height();
        var minContentHeight = o.scrollTop + height + o.overscanHeight;
        var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0,
            cnt = this.renderedIndex + 1;
        var lastHeight;
        var getElementHeight = function () {
            return self.container.element.height();
        };
        while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) {
            var items = o.items.slice(index, index + o.blockSize);
            this.container.addItems(items, this);
            var addedHeight = getElementHeight() - lastHeight;
            this.cache[cnt] = {
                index: index,
                scrollTop: lastHeight,
                height: addedHeight
            };
            this.renderedIndex = cnt;
            cnt++;
            index += o.blockSize;
        }
    },

    _calculateBlocksToRender: function () {
        var o = this.options;
        this._renderMoreIf();
    },

    _populate: function (items) {
        var o = this.options;
        if (items && this.options.items !== items) {
            this.options.items = items;
        }
        this._calculateBlocksToRender();
        this.element.scrollTop(o.scrollTop);
    },

    restore: function () {
        this.renderedIndex = -1;
        this.container.empty();
        this.cache = {};
    },

    populate: function (items) {
        if (items && this.options.items !== items) {
            this.restore();
        }
        this._populate(items);
    },

    destroyed: function () {
        this.restore();
    }
});
BI.shortcut("bi.list_view", BI.ListView);

<commit_msg>交换下顺序<commit_after>/**
 * 表示当前对象
 *
 * Created by GUY on 2017/5/23.
 * @class BI.ListView
 * @extends BI.Widget
 */
BI.ListView = BI.inherit(BI.Widget, {
    props: function () {
        return {
            baseCls: "bi-list-view",
            overscanHeight: 100,
            blockSize: 10,
            scrollTop: 0,
            el: {},
            items: []
        };
    },

    init: function () {
        var self = this;
        this.renderedIndex = -1;
        this.cache = {};
    },

    render: function () {
        var self = this, o = this.options;
        return {
            type: "bi.vertical",
            items: [BI.extend({
                type: "bi.vertical",
                scrolly: false,
                ref: function () {
                    self.container = this;
                }
            }, o.el)],
            element: this
        };
    },

    mounted: function () {
        var self = this, o = this.options;
        this._populate();
        this.element.scroll(function (e) {
            o.scrollTop = self.element.scrollTop();
            self._calculateBlocksToRender();
        });
        var lastWidth = this.element.width(),
            lastHeight = this.element.height();
        BI.ResizeDetector.addResizeListener(this, function () {
            var width = self.element.width(),
                height = self.element.height();
            if (width !== lastWidth || height !== lastHeight) {
                lastWidth = width;
                lastHeight = height;
                self._calculateBlocksToRender();
            }
        });
    },

    _renderMoreIf: function () {
        var self = this, o = this.options;
        var height = this.element.height();
        var minContentHeight = o.scrollTop + height + o.overscanHeight;
        var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0,
            cnt = this.renderedIndex + 1;
        var lastHeight;
        var getElementHeight = function () {
            return self.container.element.height();
        };
        while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) {
            var items = o.items.slice(index, index + o.blockSize);
            this.container.addItems(items, this);
            var addedHeight = getElementHeight() - lastHeight;
            this.cache[cnt] = {
                index: index,
                scrollTop: lastHeight,
                height: addedHeight
            };
            this.renderedIndex = cnt;
            cnt++;
            index += o.blockSize;
        }
    },

    _calculateBlocksToRender: function () {
        var o = this.options;
        this._renderMoreIf();
    },

    _populate: function (items) {
        var o = this.options;
        if (items && this.options.items !== items) {
            this.options.items = items;
        }
        this._calculateBlocksToRender();
        this.element.scrollTop(o.scrollTop);
    },

    restore: function () {
        this.renderedIndex = -1;
        this.container.empty();
        this.cache = {};
    },

    populate: function (items) {
        if (items && this.options.items !== items) {
            this.restore();
        }
        this._populate(items);
    },

    destroyed: function () {
        this.restore();
    }
});
BI.shortcut("bi.list_view", BI.ListView);

<|endoftext|>


<commit_before>/*global console, Math:true, bespoke:true */

(function(global, console, Math, bespoke, ns, pluginName, undefined) {
    "use strict";

    var cv,

        // This is the default for a plugin that is activated for a deck, and no particular options are passed.
        defaultPluginActivationOptions = true,

        // The defaults object is passed as a reference, and can be modified by global.convenientInit
        defaults = {
            logger: {
                log: function() {
                    // Workaround for phantom-polyfill.js problems binding console.log (window.console.log)
                    console.log.apply(console, arguments);
                }
            }
        },

        initOptions = function() {
            var merged = {};

            // Only merge known options
            merged.logger = {};
            merged.logger.log = (global.convenientOptions && global.convenientOptions.logger && global.convenientOptions.logger.log) || defaults.logger.log;

            global.convenientOptions = merged;
        },

        pluginOptions = {},

        decksStorages = [],

        storeDeck = function(deck) {
            if (!decksStorages.some(function(deckStorage) {
                return deckStorage.deck === deck;
            })) {
                decksStorages.push({
                    deck: deck,
                    storage: {}
                });
            }
        },

        plugin = function() {},

        isNumber = function(n) {
            // http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
            // From http://stackoverflow.com/a/1830844
            return !isNaN(parseFloat(n)) && isFinite(n);
        },

        init = function() {
            initOptions();
        };

    // For plugins themselves
    plugin.builder = function self(options) {
        if (typeof options === "string") {
            options = {
                pluginName: options
            };
        }

        if (typeof options.pluginName !== "string") {
            throw cv.generateErrorObject("The plugin name was not properly defined.");
        }

        options.dependencies = options.dependencies || [];

        pluginOptions[options.pluginName] = options;

        var external = {},

            tag = "bespoke." + options.pluginName,

            generateErrorObject = function(message) {
                return new Error(tag + ": " + message);
            },

            eventNamespace = options.pluginName,

            eventInNamespace = function(eventName) {
                return eventNamespace + "." + eventName;
            },

            // Plugin functions expect to be executed in a deck context
            // Mimicing, and extending,the internal createEventData bespoke uses
            createEventData = function(deck, eventNamespace, eventName, innerEvent, slide, eventData) {
                eventData = eventData || {};

                eventData.eventNamespace = eventNamespace || null;

                eventData.eventName = eventName || null;

                // Can be either a DOM/browser event or a bespoke event
                eventData.innerEvent = innerEvent || null;

                if (isNumber(slide)) {
                    eventData.index = slide;
                    eventData.slide = deck.slides[slide];
                } else {
                    eventData.index = deck.slides.indexOf(slide);
                    eventData.slide = slide;
                }

                return eventData;
            },

            // TODO: create a second object bound to both this external object and the deck,
            // to avoid passing the deck parameter every time. (Which can be alleviated with simpler function binding though.)
            fire = function(deck, eventName, innerEvent, slide, customData) {
                return deck.fire(eventInNamespace(eventName), createEventData(deck, eventNamespace, eventName, innerEvent, slide, customData));
            },

            copyArray = function(arr) {
                return [].slice.call(arr, 0);
            },

            log = function() {
                var prefixes = [tag];

                // global.convenientOptions.logger.log is dynamic, so can't bind directly to it
                global.convenientOptions.logger.log.apply(global.convenientOptions.logger.log, prefixes.concat(copyArray(arguments)));
            },

            checkIfPluginWasAlreadyLoaded = function() {
                if (ns[options.pluginName] !== undefined) {
                    throw cv.generateErrorObject("The " + options.pluginName + " plugin has already been loaded, can't load it twice.");
                }
            },

            checkIfDependenciesHaveBeenLoaded = function() {
                options.dependencies.forEach(function(dependency) {
                    if (ns[dependency] === undefined) {
                        throw cv.generateErrorObject("The " + options.pluginName + " plugin requires the " + dependency + " plugin to be loaded.");
                    }
                });
            },

            prepareDeckDependencyCheck = function(deck) {
                var storage = cv.getStorage(deck);

                storage.activatedPlugins = storage.activatedPlugins || [];
            },

            activatePluginForDeck = function(pluginNameToActivate, deck) {
                var storage = cv.getStorage(deck);

                // TODO: perform this activation/load order check at load instead?
                if (storage.activatedPlugins.indexOf(pluginNameToActivate) !== -1) {
                    cv.log("The " + pluginNameToActivate + " plugin has already been activated for this deck, can't activate it twice. This might indicate a circular plugin dependency, but dependency graph traversal hasn't been implemented into convenient, so maybe not.");
                } else {
                    bespoke.plugins[pluginNameToActivate](deck, defaultPluginActivationOptions);

                    storage.activatedPlugins.push(pluginNameToActivate);
                }
            },

            activateDependenciesForDeck = function(pluginNameToActivateDependenciesFor, deck) {
                var storage = cv.getStorage(deck),
                    dependencyOptions = pluginOptions[pluginNameToActivateDependenciesFor];

                // Only check for dependencies for plugins convenient knows about
                if (dependencyOptions) {
                    dependencyOptions.dependencies.forEach(function(dependency) {
                        if (storage.activatedPlugins.indexOf(dependency) === -1) {
                            activatePluginForDeck(dependency, deck);
                            activateDependenciesForDeck(dependency, deck);
                        }
                    });
                }

                storage.activatedPlugins.push(pluginNameToActivateDependenciesFor);
            },

            activateDeck = function(deck) {
                storeDeck(deck);
                prepareDeckDependencyCheck(deck);
                activateDependenciesForDeck(options.pluginName, deck);
            },

            bindExternal = function() {
                external.createEventData = createEventData.bind(this);
                external.generateErrorObject = generateErrorObject.bind(this);
                external.fire = fire.bind(this);
                external.copyArray = copyArray.bind(this);
                external.log = log.bind(this);
                external.activateDeck = activateDeck.bind(this);
                external.getStorage = plugin.getDeckPluginStorage.bind(this, options.pluginName);
            },

            init = function() {
                checkIfPluginWasAlreadyLoaded();
                checkIfDependenciesHaveBeenLoaded();
                bindExternal();
            };

        init();

        return external;
    };

    plugin.getDeckStorage = function(deck) {
        if (deck === undefined) {
            throw cv.generateErrorObject("deck must be defined.");
        }

        var storage = null;

        decksStorages.forEach(function(deckStorage) {
            if (deckStorage.deck === deck) {
                storage = deckStorage.storage;
                return false;
            }
        });

        return storage;
    };

    plugin.getDeckPluginStorage = function(pluginName, deck) {
        if (pluginName === undefined) {
            throw cv.generateErrorObject("pluginName must be defined.");
        }

        var storage = plugin.getDeckStorage(deck);

        if (storage[pluginName] === undefined) {
            storage[pluginName] = {};
        }

        return storage[pluginName];
    };

    // Plugin functions expect to be executed in a deck context
    // Mimicing, and extending,the internal createEventData bespoke uses
    plugin.createEventData = function(eventNamespace, eventName, innerEvent, slide, eventData) {
        eventData = eventData || {};

        eventData.eventNamespace = eventNamespace || null;

        eventData.eventName = eventName || null;

        // Can be either a DOM/browser event or a bespoke event
        eventData.innerEvent = innerEvent || null;

        if (isNumber(slide)) {
            eventData.index = slide;
            eventData.slide = this.slides[slide];
        } else {
            eventData.index = this.slides.indexOf(slide);
            eventData.slide = slide;
        }

        return eventData;
    };

    cv = plugin.builder(pluginName);

    init();

    ns[pluginName] = plugin;
}(this, console, Math, bespoke, bespoke.plugins, "convenient"));
<commit_msg>Remove reference to Math<commit_after>/*global console:true, bespoke:true */

(function(global, console, bespoke, ns, pluginName, undefined) {
    "use strict";

    var cv,

        // This is the default for a plugin that is activated for a deck, and no particular options are passed.
        defaultPluginActivationOptions = true,

        // The defaults object is passed as a reference, and can be modified by global.convenientInit
        defaults = {
            logger: {
                log: function() {
                    // Workaround for phantom-polyfill.js problems binding console.log (window.console.log)
                    console.log.apply(console, arguments);
                }
            }
        },

        initOptions = function() {
            var merged = {};

            // Only merge known options
            merged.logger = {};
            merged.logger.log = (global.convenientOptions && global.convenientOptions.logger && global.convenientOptions.logger.log) || defaults.logger.log;

            global.convenientOptions = merged;
        },

        pluginOptions = {},

        decksStorages = [],

        storeDeck = function(deck) {
            if (!decksStorages.some(function(deckStorage) {
                return deckStorage.deck === deck;
            })) {
                decksStorages.push({
                    deck: deck,
                    storage: {}
                });
            }
        },

        plugin = function() {},

        isNumber = function(n) {
            // http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric
            // From http://stackoverflow.com/a/1830844
            return !isNaN(parseFloat(n)) && isFinite(n);
        },

        init = function() {
            initOptions();
        };

    // For plugins themselves
    plugin.builder = function self(options) {
        if (typeof options === "string") {
            options = {
                pluginName: options
            };
        }

        if (typeof options.pluginName !== "string") {
            throw cv.generateErrorObject("The plugin name was not properly defined.");
        }

        options.dependencies = options.dependencies || [];

        pluginOptions[options.pluginName] = options;

        var external = {},

            tag = "bespoke." + options.pluginName,

            generateErrorObject = function(message) {
                return new Error(tag + ": " + message);
            },

            eventNamespace = options.pluginName,

            eventInNamespace = function(eventName) {
                return eventNamespace + "." + eventName;
            },

            // Plugin functions expect to be executed in a deck context
            // Mimicing, and extending,the internal createEventData bespoke uses
            createEventData = function(deck, eventNamespace, eventName, innerEvent, slide, eventData) {
                eventData = eventData || {};

                eventData.eventNamespace = eventNamespace || null;

                eventData.eventName = eventName || null;

                // Can be either a DOM/browser event or a bespoke event
                eventData.innerEvent = innerEvent || null;

                if (isNumber(slide)) {
                    eventData.index = slide;
                    eventData.slide = deck.slides[slide];
                } else {
                    eventData.index = deck.slides.indexOf(slide);
                    eventData.slide = slide;
                }

                return eventData;
            },

            // TODO: create a second object bound to both this external object and the deck,
            // to avoid passing the deck parameter every time. (Which can be alleviated with simpler function binding though.)
            fire = function(deck, eventName, innerEvent, slide, customData) {
                return deck.fire(eventInNamespace(eventName), createEventData(deck, eventNamespace, eventName, innerEvent, slide, customData));
            },

            copyArray = function(arr) {
                return [].slice.call(arr, 0);
            },

            log = function() {
                var prefixes = [tag];

                // global.convenientOptions.logger.log is dynamic, so can't bind directly to it
                global.convenientOptions.logger.log.apply(global.convenientOptions.logger.log, prefixes.concat(copyArray(arguments)));
            },

            checkIfPluginWasAlreadyLoaded = function() {
                if (ns[options.pluginName] !== undefined) {
                    throw cv.generateErrorObject("The " + options.pluginName + " plugin has already been loaded, can't load it twice.");
                }
            },

            checkIfDependenciesHaveBeenLoaded = function() {
                options.dependencies.forEach(function(dependency) {
                    if (ns[dependency] === undefined) {
                        throw cv.generateErrorObject("The " + options.pluginName + " plugin requires the " + dependency + " plugin to be loaded.");
                    }
                });
            },

            prepareDeckDependencyCheck = function(deck) {
                var storage = cv.getStorage(deck);

                storage.activatedPlugins = storage.activatedPlugins || [];
            },

            activatePluginForDeck = function(pluginNameToActivate, deck) {
                var storage = cv.getStorage(deck);

                // TODO: perform this activation/load order check at load instead?
                if (storage.activatedPlugins.indexOf(pluginNameToActivate) !== -1) {
                    cv.log("The " + pluginNameToActivate + " plugin has already been activated for this deck, can't activate it twice. This might indicate a circular plugin dependency, but dependency graph traversal hasn't been implemented into convenient, so maybe not.");
                } else {
                    bespoke.plugins[pluginNameToActivate](deck, defaultPluginActivationOptions);

                    storage.activatedPlugins.push(pluginNameToActivate);
                }
            },

            activateDependenciesForDeck = function(pluginNameToActivateDependenciesFor, deck) {
                var storage = cv.getStorage(deck),
                    dependencyOptions = pluginOptions[pluginNameToActivateDependenciesFor];

                // Only check for dependencies for plugins convenient knows about
                if (dependencyOptions) {
                    dependencyOptions.dependencies.forEach(function(dependency) {
                        if (storage.activatedPlugins.indexOf(dependency) === -1) {
                            activatePluginForDeck(dependency, deck);
                            activateDependenciesForDeck(dependency, deck);
                        }
                    });
                }

                storage.activatedPlugins.push(pluginNameToActivateDependenciesFor);
            },

            activateDeck = function(deck) {
                storeDeck(deck);
                prepareDeckDependencyCheck(deck);
                activateDependenciesForDeck(options.pluginName, deck);
            },

            bindExternal = function() {
                external.createEventData = createEventData.bind(this);
                external.generateErrorObject = generateErrorObject.bind(this);
                external.fire = fire.bind(this);
                external.copyArray = copyArray.bind(this);
                external.log = log.bind(this);
                external.activateDeck = activateDeck.bind(this);
                external.getStorage = plugin.getDeckPluginStorage.bind(this, options.pluginName);
            },

            init = function() {
                checkIfPluginWasAlreadyLoaded();
                checkIfDependenciesHaveBeenLoaded();
                bindExternal();
            };

        init();

        return external;
    };

    plugin.getDeckStorage = function(deck) {
        if (deck === undefined) {
            throw cv.generateErrorObject("deck must be defined.");
        }

        var storage = null;

        decksStorages.forEach(function(deckStorage) {
            if (deckStorage.deck === deck) {
                storage = deckStorage.storage;
                return false;
            }
        });

        return storage;
    };

    plugin.getDeckPluginStorage = function(pluginName, deck) {
        if (pluginName === undefined) {
            throw cv.generateErrorObject("pluginName must be defined.");
        }

        var storage = plugin.getDeckStorage(deck);

        if (storage[pluginName] === undefined) {
            storage[pluginName] = {};
        }

        return storage[pluginName];
    };

    // Plugin functions expect to be executed in a deck context
    // Mimicing, and extending,the internal createEventData bespoke uses
    plugin.createEventData = function(eventNamespace, eventName, innerEvent, slide, eventData) {
        eventData = eventData || {};

        eventData.eventNamespace = eventNamespace || null;

        eventData.eventName = eventName || null;

        // Can be either a DOM/browser event or a bespoke event
        eventData.innerEvent = innerEvent || null;

        if (isNumber(slide)) {
            eventData.index = slide;
            eventData.slide = this.slides[slide];
        } else {
            eventData.index = this.slides.indexOf(slide);
            eventData.slide = slide;
        }

        return eventData;
    };

    cv = plugin.builder(pluginName);

    init();

    ns[pluginName] = plugin;
}(this, console, bespoke, bespoke.plugins, "convenient"));
<|endoftext|>