<commit_before>"use strict";
/*jshint eqnull:true */
/*jshint node:true */

(function codenautasModuleDefinition(root, name, factory) {
    /* global define */
    /* istanbul ignore next */
    if(typeof root.globalModuleName !== 'string'){
        root.globalModuleName = name;
    }
    /* istanbul ignore next */
    if(typeof exports === 'object' && typeof module === 'object'){
        module.exports = factory();
    }else if(typeof define === 'function' && define.amd){
        define(factory);
    }else if(typeof exports === 'object'){
        exports[root.globalModuleName] = factory();
    }else{
        root[root.globalModuleName] = factory();
    }
    root.globalModuleName = null;
})(/*jshint -W040 */this, 'myOwn', function() {
/*jshint +W040 */

/*jshint -W004 */
var myOwn = {};
/*jshint +W004 */

myOwn.messages = {
    notLogged: "Not logged in",
    noServer : "The server inaccessible",
    noNetwork: "Not connected to the network",
    reLogin  : "sign in"
};

myOwn.es = {
    notLogged: "Sin sesión activa",
    noServer : "No se puede acceder al servidor",
    noNetwork: "No se detecta conexión de red",
    reLogin  : "Iniciar sesión",
};

var bestGlobals = require('best-globals');

var coalesce = bestGlobals.coalesce;
var changing = bestGlobals.changing;

var jsYaml = require('js-yaml');

function id(x){return x;}

myOwn.debugging = false;
myOwn.statusDivName = 'reconnection_div';

myOwn.autoSetup = function autoSetup(){
    var my = this;
    var readProcedureDefinitions = function readProcedureDefinitions(){
        return my.ajaxPromise({
            action:'def-procedures',
            method:'get',
            encoding:'JSON',
            parameters:[],
        }).then(function(defSource){
            my.proceduresDef=eval(defSource);
            my.proceduresDef.forEach(function(procedureDef){
                var target;
                var lastName = null;
                var partsNames=procedureDef.action.split('/').filter(id).forEach(function(name){
                    if(lastName){
                        if(!target[lastName]){
                            target[lastName]={"dont-use":lastName};
                        }else if(target[lastName]["dont-use"]!==lastName){
                            throw new Error("Bad nesting of procedures");
                        }
                        target=target[lastName];
                    }else{
                        target=my.ajax;
                    }
                    lastName=name;
                });
                target[lastName]=my.ajaxPromise.bind(my,procedureDef);
            });
        });
    };
    setInterval(function(){
        my.testKeepAlive();
    },my.debugging?6*1000:60*1000);
    return readProcedureDefinitions();
};

myOwn["log-severities"] = {
    error:{permanent:true },
    log  :{permanent:false},
};

myOwn.log = function log(severity, message){
    var my=this;
    var consoleMessage;
    var clientMessage;
    if(!message){
        if(severity instanceof Error){
            clientMessage=severity.message;
            consoleMessage=severity;
            severity='error';
        }else{
            clientMessage=severity;
            severity='log';
        }
    }else{
        clientMessage = message;
    }
    consoleMessage = consoleMessage || clientMessage;
    var status = document.getElementById('status');
    console.log(severity, consoleMessage);
    status = status||document.body;
    var divMessage = html.div({"class": ["status-"+severity]}, clientMessage).create();
    status.appendChild(divMessage);
    if(!this["log-severities"][severity].permanent){
        setTimeout(function(){
            my.fade(divMessage);
        },3000);
    }
};

myOwn.fade = function fade(element){
    element.parentNode.removeChild(element);
};

myOwn.adaptData = function adaptData(tableDef, rows){
    rows.forEach(function(row){
        tableDef.fields.forEach(function(fieldDef){
            if(fieldDef.typeName=='number' && fieldDef.exact && fieldDef.decimals){
                if(row[fieldDef.name]){
                    row[fieldDef.name] = row[fieldDef.name]-0;
                }
            }
            if(fieldDef.typeName=='date'){
                if(row[fieldDef.name] && !(row[fieldDef.name] instanceof Date)){
                    row[fieldDef.name] = bestGlobals.date.iso(row[fieldDef.name]);
                }
            }
        });
    });
};

Object.defineProperty(myOwn, 'ajax', {
    get: function ajax(){
        if(!this.proceduresDef){
            throw new Error("before use myOwn.ajax, myOwn.autoSetup() must be called");
        }else{
            return this.ajaxPromise;
        }
    }
});

myOwn.encoders = {
    'JSON': { parse: JSON.parse, stringify: JSON.stringify },
    'plain': {
        parse: function(x){return x;},
        stringify: function(x){
            if(typeof x === "object"){
                throw new Error("Invalid plain type "+(x==null?value:typeof x)+" detected");
            }
            return x;
        }
    },
    'yaml': {
        parse: jsYaml.load.bind(jsYaml),
        parse: jsYaml.load.bind(jsYaml),
        stringify: jsYaml.dump.bind(jsYaml),
        // parse: function(x){
        //     var c=jsYaml.load(x);
        //     return c;
        // },
        // stringify:  function(x){
        //     var c=jsYaml.safeDump(x);
        //     return c;
        // }
    }
};

myOwn.ajaxPromise = function(procedureDef,data,opts){
    opts = opts || {};
    if(!('visiblyLogErrors' in opts)){
        opts.visiblyLogErrors=true;
    }
    var my = this;
    return Promise.resolve().then(function(){
        var params={};
        procedureDef.parameters.forEach(function(paramDef){
            var value=coalesce(data[paramDef.name],paramDef.def,coalesce.throwErrorIfUndefined("lack of parameter "+paramDef.name));
            value = my.encoders[paramDef.encoding].stringify(value);
            params[paramDef.name]=value;
        });
        var notLogged='NOT LOGGED';
        var conStat = my["connection-status"];
        return AjaxBestPromise[procedureDef.method]({
            url:procedureDef.action,
            data:params
        }).then(function(result){
            if(result && result[0]=="<" && result.match(/login/m)){
                my.createOrReplaceConnectionStatus(conStat.notLogged);
                throw changing(new Error(notLogged),{displayed:true});
            }
            my.removeConnectionStatus();
            return my.encoders[procedureDef.encoding].parse(result);
        }).catch(function(err){
            if(err.message != notLogged) {
                if(! window.navigator.onLine) {
                    my.createOrReplaceConnectionStatus(conStat.noNetwork);
                }
                else if(!!err.originalError) {
                    my.createOrReplaceConnectionStatus(conStat.noServer);
                } else {
                    my.removeConnectionStatus();
                }
            }
            if(!err.displayed && opts.visiblyLogErrors || err.status==403){
                my.log(err);
            }
            throw err;
        });
    });
};

myOwn.testKeepAlive = function testKeepAlive(){
    var my = this;
    var element = document.getElementById('keep-alive-signal') || my.debugging && document.body.appendChild(html.div({id:'keep-alive-signal'}).create());
    if(element){
        element.textContent='t';
        element.style.backgroundColor='#4DD';
        element.style.display='';
    }
    return my.ajaxPromise({
        parameters:[],
        method:'post',
        action:'keep-alive',
        encoding:'plain'
    }).then(function(){
        if(element){
            element.textContent='ok';
            element.style.backgroundColor='lightgreen';
        }
    },function(){
        if(element){
            element.textContent='E!';
            element.style.backgroundColor='#F88';
        }
    }).then(function(){
        if(element){
            setTimeout(function(){
                element.style.display='none';
            }, 2000);
        }
    })
};

myOwn.showQuestion = function showQuestion(message){
    return confirmPromise(message);
};

myOwn.easeInOut = function easeInOut(currentTime, start, change, duration) {
    currentTime /= duration / 2;
    if (currentTime < 1) {
        return change / 2 * currentTime * currentTime + start;
    }
    currentTime -= 1;
    return -change / 2 * (currentTime * (currentTime - 2) - 1) + start;
};

myOwn.scrollToTop = function(element, to, duration) {
    var start = element.scrollTop,
        change = to - start,
        increment = 20;
    var me = this;
    var animateScroll = function(elapsedTime) {
        elapsedTime += increment;
        var position = me.easeInOut(elapsedTime, start, change, duration);
        element.scrollTop = position;
        if (elapsedTime < duration) {
            setTimeout(function() {
                animateScroll(elapsedTime);
            }, increment);
        } else {
            element.scrollTop = document.documentElement.scrollTop = 0; // cross browser scrolling to top
        }
    };
    animateScroll(0);
};

myOwn["connection-status"] = {
    notLogged:myOwn.messages.notLogged,
    noServer :myOwn.messages.noServer,
    noNetwork:myOwn.messages.noNetwork,
};

myOwn.createOrReplaceConnectionStatus = function createOrReplaceConnectionStatus(status) {
    var recDiv = document.getElementById(this.statusDivName);
    this.scrollToTop(document.body, 0, 500);
    var statusMsg = status+"!!!! ";
    var msgID = 'recMsg';
    if(! recDiv) {
        recDiv = html.div({id:this.statusDivName}).create();
        recDiv.appendChild(html.span({id:msgID}, statusMsg).create());
        var body = document.body;
        body.insertBefore(recDiv, body.firstChild);
    } else {
        document.getElementById(msgID).innerHTML = statusMsg;
    }
    var recID = 'recID';
    var recLink = document.getElementById(recID);
    if(status !== my["connection-status"].notLogged) {
        if(recLink) { recDiv.removeChild(recLink); }
    } else {
        var attrToSet = 'blink';
        if(! recLink) {
            attrToSet = 'pulse';
            recLink = html.a({id:recID, href:'login'}, myOwn.messages.reLogin).create();
            recDiv.appendChild(recLink);
        }
        recLink.setAttribute('rec-status', attrToSet);
    }
};

myOwn.removeConnectionStatus = function removeConnectionStatus() {
    var recDiv = document.getElementById(this.statusDivName);
    if(recDiv) { document.body.removeChild(recDiv); }
};

return myOwn;

});<commit_msg>Comentario<commit_after>"use strict";
/*jshint eqnull:true */
/*jshint node:true */

(function codenautasModuleDefinition(root, name, factory) {
    /* global define */
    /* istanbul ignore next */
    if(typeof root.globalModuleName !== 'string'){
        root.globalModuleName = name;
    }
    /* istanbul ignore next */
    if(typeof exports === 'object' && typeof module === 'object'){
        module.exports = factory();
    }else if(typeof define === 'function' && define.amd){
        define(factory);
    }else if(typeof exports === 'object'){
        exports[root.globalModuleName] = factory();
    }else{
        root[root.globalModuleName] = factory();
    }
    root.globalModuleName = null;
})(/*jshint -W040 */this, 'myOwn', function() {
/*jshint +W040 */

/*jshint -W004 */
var myOwn = {};
/*jshint +W004 */

myOwn.messages = {
    notLogged: "Not logged in",
    noServer : "The server inaccessible",
    noNetwork: "Not connected to the network",
    reLogin  : "sign in"
};

myOwn.es = {
    notLogged: "Sin sesión activa",
    noServer : "No se puede acceder al servidor",
    noNetwork: "No se detecta conexión de red",
    reLogin  : "Iniciar sesión",
};

var bestGlobals = require('best-globals');

var coalesce = bestGlobals.coalesce;
var changing = bestGlobals.changing;

var jsYaml = require('js-yaml');

function id(x){return x;}

myOwn.debugging = false;
myOwn.statusDivName = 'reconnection_div';

myOwn.autoSetup = function autoSetup(){
    var my = this;
    var readProcedureDefinitions = function readProcedureDefinitions(){
        return my.ajaxPromise({
            action:'def-procedures',
            method:'get',
            encoding:'JSON',
            parameters:[],
        }).then(function(defSource){
            my.proceduresDef=eval(defSource);
            my.proceduresDef.forEach(function(procedureDef){
                var target;
                var lastName = null;
                var partsNames=procedureDef.action.split('/').filter(id).forEach(function(name){
                    if(lastName){
                        if(!target[lastName]){
                            target[lastName]={"dont-use":lastName};
                        }else if(target[lastName]["dont-use"]!==lastName){
                            throw new Error("Bad nesting of procedures");
                        }
                        target=target[lastName];
                    }else{
                        target=my.ajax;
                    }
                    lastName=name;
                });
                target[lastName]=my.ajaxPromise.bind(my,procedureDef);
            });
        });
    };
    setInterval(function(){
        my.testKeepAlive();
    },my.debugging?6*1000:60*1000);
    return readProcedureDefinitions();
};

myOwn["log-severities"] = {
    error:{permanent:true },
    log  :{permanent:false},
};

myOwn.log = function log(severity, message){
    var my=this;
    var consoleMessage;
    var clientMessage;
    if(!message){
        if(severity instanceof Error){
            clientMessage=severity.message;
            consoleMessage=severity;
            severity='error';
        }else{
            clientMessage=severity;
            severity='log';
        }
    }else{
        clientMessage = message;
    }
    consoleMessage = consoleMessage || clientMessage;
    var status = document.getElementById('status');
    console.log(severity, consoleMessage);
    status = status||document.body;
    var divMessage = html.div({"class": ["status-"+severity]}, clientMessage).create();
    status.appendChild(divMessage);
    if(!this["log-severities"][severity].permanent){
        setTimeout(function(){
            my.fade(divMessage);
        },3000);
    }
};

myOwn.fade = function fade(element){
    element.parentNode.removeChild(element);
};

myOwn.adaptData = function adaptData(tableDef, rows){
    rows.forEach(function(row){
        tableDef.fields.forEach(function(fieldDef){
            if(fieldDef.typeName=='number' && fieldDef.exact && fieldDef.decimals){
                if(row[fieldDef.name]){
                    row[fieldDef.name] = row[fieldDef.name]-0;
                }
            }
            if(fieldDef.typeName=='date'){
                if(row[fieldDef.name] && !(row[fieldDef.name] instanceof Date)){
                    row[fieldDef.name] = bestGlobals.date.iso(row[fieldDef.name]);
                }
            }
        });
    });
};

Object.defineProperty(myOwn, 'ajax', {
    get: function ajax(){
        if(!this.proceduresDef){
            throw new Error("before use myOwn.ajax, myOwn.autoSetup() must be called");
        }else{
            return this.ajaxPromise;
        }
    }
});

myOwn.encoders = {
    'JSON': { parse: JSON.parse, stringify: JSON.stringify },
    'plain': {
        parse: function(x){return x;},
        stringify: function(x){
            if(typeof x === "object"){
                throw new Error("Invalid plain type "+(x==null?value:typeof x)+" detected");
            }
            return x;
        }
    },
    'yaml': {
        parse: jsYaml.load.bind(jsYaml),
        parse: jsYaml.load.bind(jsYaml),
        stringify: jsYaml.dump.bind(jsYaml),
        // parse: function(x){
        //     var c=jsYaml.load(x);
        //     return c;
        // },
        // stringify:  function(x){
        //     var c=jsYaml.safeDump(x);
        //     return c;
        // }
    }
};

myOwn.ajaxPromise = function(procedureDef,data,opts){
    opts = opts || {};
    if(!('visiblyLogErrors' in opts)){
        opts.visiblyLogErrors=true;
    }
    var my = this;
    return Promise.resolve().then(function(){
        var params={};
        procedureDef.parameters.forEach(function(paramDef){
            var value=coalesce(data[paramDef.name],paramDef.def,coalesce.throwErrorIfUndefined("lack of parameter "+paramDef.name));
            value = my.encoders[paramDef.encoding].stringify(value);
            params[paramDef.name]=value;
        });
        var notLogged='NOT LOGGED';
        var conStat = my["connection-status"];
        return AjaxBestPromise[procedureDef.method]({
            url:procedureDef.action,
            data:params
        }).then(function(result){
            if(result && result[0]=="<" && result.match(/login/m)){
                my.createOrReplaceConnectionStatus(conStat.notLogged);
                throw changing(new Error(notLogged),{displayed:true});
            }
            my.removeConnectionStatus();
            return my.encoders[procedureDef.encoding].parse(result);
        }).catch(function(err){
            if(err.message != notLogged) {
                if(! window.navigator.onLine) {
                    my.createOrReplaceConnectionStatus(conStat.noNetwork);
                }
                else if(!!err.originalError) {
                    my.createOrReplaceConnectionStatus(conStat.noServer);
                } else {
                    my.removeConnectionStatus();
                }
            }
            if(!err.displayed && opts.visiblyLogErrors || err.status==403){
                my.log(err);
            }
            throw err;
        });
    });
};

myOwn.testKeepAlive = function testKeepAlive(){
    var my = this;
    var element = document.getElementById('keep-alive-signal') || my.debugging && document.body.appendChild(html.div({id:'keep-alive-signal'}).create());
    if(element){
        element.textContent='t';
        element.style.backgroundColor='#4DD';
        element.style.display='';
    }
    return my.ajaxPromise({
        parameters:[],
        method:'post',
        action:'keep-alive',
        encoding:'plain'
    }).then(function(){
        if(element){
            element.textContent='ok';
            element.style.backgroundColor='lightgreen';
        }
    },function(){
        if(element){
            element.textContent='E!';
            element.style.backgroundColor='#F88';
        }
    }).then(function(){
        if(element){
            setTimeout(function(){
                element.style.display='none';
            }, 2000);
        }
    })
};

myOwn.showQuestion = function showQuestion(message){
    return confirmPromise(message);
};

myOwn.easeInOut = function easeInOut(currentTime, start, change, duration) {
    currentTime /= duration / 2;
    if (currentTime < 1) {
        return change / 2 * currentTime * currentTime + start;
    }
    currentTime -= 1;
    return -change / 2 * (currentTime * (currentTime - 2) - 1) + start;
};

myOwn.scrollToTop = function(element, to, duration) {
    var start = element.scrollTop,
        change = to - start,
        increment = 20;
    var me = this;
    var animateScroll = function(elapsedTime) {
        elapsedTime += increment;
        var position = me.easeInOut(elapsedTime, start, change, duration);
        element.scrollTop = position;
        if (elapsedTime < duration) {
            setTimeout(function() {
                animateScroll(elapsedTime);
            }, increment);
        } else {
            element.scrollTop = document.documentElement.scrollTop = 0; // cross browser scrolling to top
        }
    };
    animateScroll(0);
};

myOwn["connection-status"] = {
    notLogged:myOwn.messages.notLogged,
    noServer :myOwn.messages.noServer,
    noNetwork:myOwn.messages.noNetwork,
};

// creo <div> para los mensajes, si no existe.
// en base a status, genero etiqueta y link, si corresponde
myOwn.createOrReplaceConnectionStatus = function createOrReplaceConnectionStatus(status) {
    var recDiv = document.getElementById(this.statusDivName);
    this.scrollToTop(document.body, 0, 500);
    var statusMsg = status+"!!!! ";
    var msgID = 'recMsg';
    if(! recDiv) {
        recDiv = html.div({id:this.statusDivName}).create();
        recDiv.appendChild(html.span({id:msgID}, statusMsg).create());
        var body = document.body;
        body.insertBefore(recDiv, body.firstChild);
    } else {
        document.getElementById(msgID).innerHTML = statusMsg;
    }
    var recID = 'recID';
    var recLink = document.getElementById(recID);
    if(status !== my["connection-status"].notLogged) {
        if(recLink) { recDiv.removeChild(recLink); }
    } else {
        var attrToSet = 'blink';
        if(! recLink) {
            attrToSet = 'pulse';
            recLink = html.a({id:recID, href:'login'}, myOwn.messages.reLogin).create();
            recDiv.appendChild(recLink);
        }
        recLink.setAttribute('rec-status', attrToSet);
    }
};

myOwn.removeConnectionStatus = function removeConnectionStatus() {
    var recDiv = document.getElementById(this.statusDivName);
    if(recDiv) { document.body.removeChild(recDiv); }
};

return myOwn;

});<|endoftext|>


<commit_before>// @flow

import Output from 'cli-engine-command/lib/output'
import UserPlugins from './user'
import LinkedPlugins from './linked'
import PluginCache from './cache'
import path from 'path'
import fs from 'fs-extra'
import Lock from '../lock'

const debug = require('debug')('cli-engine:migrator')

export default class {
  userPlugins: UserPlugins
  linkedPlugins: LinkedPlugins
  out: Output
  lock: Lock

  constructor (out: Output) {
    let cache = new PluginCache(out)
    this.userPlugins = new UserPlugins({out, config: out.config, cache})
    this.linkedPlugins = new LinkedPlugins({out, config: out.config, cache})
    this.out = out
    this.lock = new Lock(this.out)
  }

  async run () {
    // short circuit quickly without having to aquire the writer lock
    if (fs.existsSync(this.userPlugins.userPluginsPJSONPath)) return
    if (!fs.existsSync(path.join(this.userPlugins.userPluginsDir, 'plugins.json'))) return

    let pljson = await this._readPluginsJSON()
    if (!pljson) return false

    let downgrade = await this.lock.upgrade()
    await this._run(pljson)
    await downgrade()
  }

  async _run (pljson: any) {
    // prevent two parallel migrations from happening in case of a race
    if (fs.existsSync(this.userPlugins.userPluginsPJSONPath)) return

    debug('has existing plugins')
    this.out.action.start('Migrating Heroku CLI v5 plugins')
    debug('removing existing node_modules')
    for (let p of pljson) {
      debug(`installing ${p.name}`)
      await this._installPlugin(p.name, p.tag)
    }
    this.out.action.stop()
  }

  async _readPluginsJSON () {
    try {
      let pljsonPath = path.join(this.userPlugins.userPluginsDir, 'plugins.json')
      return fs.readJSONSync(pljsonPath)
    } catch (err) {
      this.out.debug(err.message)
    }
  }

  async _installPlugin (name: string, tag: string) {
    try {
      if (tag === 'symlink') {
        await this._reinstallViaSymlink(name)
      } else {
        if (tag === '') tag = 'latest'
        await this.userPlugins.install(name)
      }
    } catch (err) {
      this.out.warn(err)
    }
  }

  async _reinstallViaSymlink (name: string) {
    debug(`Installing via symlink: ${name}`)
    let pluginPath = fs.realpathSync(this.userPlugins.userPluginPath(name))
    await this.linkedPlugins.add(pluginPath)
  }
}
<commit_msg>do not migrate salesforcedx<commit_after>// @flow

import Output from 'cli-engine-command/lib/output'
import UserPlugins from './user'
import LinkedPlugins from './linked'
import PluginCache from './cache'
import path from 'path'
import fs from 'fs-extra'
import Lock from '../lock'

const debug = require('debug')('cli-engine:migrator')

export default class {
  userPlugins: UserPlugins
  linkedPlugins: LinkedPlugins
  out: Output
  lock: Lock

  constructor (out: Output) {
    let cache = new PluginCache(out)
    this.userPlugins = new UserPlugins({out, config: out.config, cache})
    this.linkedPlugins = new LinkedPlugins({out, config: out.config, cache})
    this.out = out
    this.lock = new Lock(this.out)
  }

  async run () {
    // short circuit quickly without having to aquire the writer lock
    if (fs.existsSync(this.userPlugins.userPluginsPJSONPath)) return
    if (!fs.existsSync(path.join(this.userPlugins.userPluginsDir, 'plugins.json'))) return

    let pljson = await this._readPluginsJSON()
    if (!pljson) return false

    let downgrade = await this.lock.upgrade()
    await this._run(pljson)
    await downgrade()
  }

  async _run (pljson: any) {
    // prevent two parallel migrations from happening in case of a race
    if (fs.existsSync(this.userPlugins.userPluginsPJSONPath)) return

    debug('has existing plugins')
    this.out.action.start('Migrating Heroku CLI v5 plugins')
    debug('removing existing node_modules')
    for (let p of pljson) {
      if (p.name === 'salesforcedx') continue
      debug(`installing ${p.name}`)
      await this._installPlugin(p.name, p.tag)
    }
    this.out.action.stop()
  }

  async _readPluginsJSON () {
    try {
      let pljsonPath = path.join(this.userPlugins.userPluginsDir, 'plugins.json')
      return fs.readJSONSync(pljsonPath)
    } catch (err) {
      this.out.debug(err.message)
    }
  }

  async _installPlugin (name: string, tag: string) {
    try {
      if (tag === 'symlink') {
        await this._reinstallViaSymlink(name)
      } else {
        if (tag === '') tag = 'latest'
        await this.userPlugins.install(name)
      }
    } catch (err) {
      this.out.warn(err)
    }
  }

  async _reinstallViaSymlink (name: string) {
    debug(`Installing via symlink: ${name}`)
    let pluginPath = fs.realpathSync(this.userPlugins.userPluginPath(name))
    await this.linkedPlugins.add(pluginPath)
  }
}
<|endoftext|>


<commit_before>import forEach from 'lodash/forEach';

/**
 * pluginRegistry module. Used to create pluginRegistry objects.
 *
 * @module plugins/registry
 */

/**
 * Creates a plugin registry
 *
 * @param  {...Object} [initialPlugins]               - Plugins for initial registration.
 * @return {module:plugins/registry~pluginRegistry} - pluginRegistry
 */
export function createPluginRegistry(...initialPlugins) {
  // Register initial plugins if passed in
  if (initialPlugins) {
    registerPlugins(...initialPlugins);
  }

  const hooks = {
    addRuleHook: [],
    transformDeclarationHook: []
  };

  const hookFns = {};

  Object.keys(hooks).forEach((hook) => {
    hookFns[hook] = applyPlugins(hook);
  });

  /**
   * pluginRegistry description
   *
   * @name pluginRegistry
   * @type {Object}
   */
  const pluginRegistry = { ...hookFns, registerPlugins, hooks };

  /**
   * Register plugins
   *
   * @memberOf module:plugins/registry~pluginRegistry
   * @param  {...Object} plugins - Plugins to register
   */
  function registerPlugins(...plugins) {
    plugins.forEach((plugin) => {
      Object.keys(plugin).forEach((key) => {
        if (hooks[key]) {
          hooks[key].push(plugin[key]);
        }
      });
    });
  }

  /**
   * Create a function for running the given hook
   *
   * @private
   * @param  {string}   hook
   * @return {Function}
   */
  function applyPlugins(hook) {
    return function runHook(...args) {
      forEach(hooks[hook], ((callback) => callback(...args))); // use lodash forEach to exit early
    };
  }

  return pluginRegistry;
}
<commit_msg>Silly test issue<commit_after>import forEach from 'lodash/forEach';

/**
 * pluginRegistry module. Used to create pluginRegistry objects.
 *
 * @module plugins/registry
 */

/**
 * Creates a plugin registry
 *
 * @param  {...Object} [initialPlugins]               - Plugins for initial registration.
 * @return {module:plugins/registry~pluginRegistry} - pluginRegistry
 */
export function createPluginRegistry(...initialPlugins) {
  const hooks = {
    addRuleHook: [],
    transformDeclarationHook: []
  };

  const hookFns = {};

  Object.keys(hooks).forEach((hook) => {
    hookFns[hook] = applyPlugins(hook);
  });

  // Register initial plugins if passed in
  if (initialPlugins) {
    registerPlugins(...initialPlugins);
  }

  /**
   * pluginRegistry description
   *
   * @name pluginRegistry
   * @type {Object}
   */
  const pluginRegistry = { ...hookFns, registerPlugins, hooks };

  /**
   * Register plugins
   *
   * @memberOf module:plugins/registry~pluginRegistry
   * @param  {...Object} plugins - Plugins to register
   */
  function registerPlugins(...plugins) {
    plugins.forEach((plugin) => {
      Object.keys(plugin).forEach((key) => {
        if (hooks[key]) {
          hooks[key].push(plugin[key]);
        }
      });
    });
  }

  /**
   * Create a function for running the given hook
   *
   * @private
   * @param  {string}   hook
   * @return {Function}
   */
  function applyPlugins(hook) {
    return function runHook(...args) {
      forEach(hooks[hook], ((callback) => callback(...args))); // use lodash forEach to exit early
    };
  }

  return pluginRegistry;
}
<|endoftext|>


<commit_before>/* jshint node:true */

var fs          = require('fs');
var path        = require('path');
var bower       = require(path.resolve(__dirname, '../../bower.json'));
var VersionChecker = require('ember-cli-version-checker');

module.exports = {
  description: 'install ember-cli-foundation-6-sass into a typical project',
  normalizeEntityName: function() {},

  beforeInstall: function () {
    // return this.addBowerPackageToProject('foundation-sites', bower.dependencies['foundation-sites']);
  },

  afterInstall: function () {
    // Copy the _settings.scss file
    var stylePath = path.join(process.cwd(), 'app', 'styles');
    var foundationPath = path.join(process.cwd(), 'bower_components', 'foundation-sites', 'scss');
    var settingsPath = path.join(foundationPath, 'settings', '_settings.scss');
    var checker = new VersionChecker(this);
    var isGTE6_3_0 = checker.for('foundation-sites', 'bower').satisfies('>=6.3.0');
    var settingsFile = fs.readFileSync(settingsPath);
    var settingsFilePath = path.join(stylePath, '_settings.scss');
    var appFile, appFilePath;

    if (isGTE6_3_0) {
      //edit app.scss to change @import 'foundation'; with @import 'foundation-sites/foundation';
      appFilePath = path.join(stylePath, 'app.scss');
      appFile = fs.readFileSync(appFilePath, 'utf-8');

      appFile = appFile.replace('@import \'foundation\';', '@import \'foundation-sites/foundation\';');

      fs.writeFileSync(appFilePath, appFile);

      //edit settingsFile contents to replace @import 'util/util'; with @import 'foundation-sites/util/util';
      settingsFile = settingsFile.toString('utf-8').replace('@import \'util/util\';', '@import \'foundation-sites/util/util\';');

      this._writeInfoLine('Updated ' + appFilePath + ' with correct foundation import path (see https://github.com/acoustep/ember-cli-foundation-6-sass/issues/40).');
      this._writeInfoLine('Updated ' + settingsFilePath + ' with correct foundation import path (see https://github.com/acoustep/ember-cli-foundation-6-sass/issues/40).');
    }

    fs.writeFileSync(settingsFilePath, settingsFile);

    return this.addPackagesToProject([
      { name: 'ember-cli-sass', target: '^5.1.0' },
      { name: 'broccoli-clean-css', target: '~1.1.0' }
    ]);
  },

  /**
   A wrapper method to write a message with writeWarnLine or writeLine, depending on which version
   of ember-cli is used

   @param {string} msg Message to print
   */
    _writeInfoLine: function(msg) {
        if (this.ui.writeWarnLine) {
            this.ui.writeWarnLine(msg);
        } else {
            this.ui.writeLine(msg, 'INFO');
        }
    }
};
<commit_msg>Accidentally commented a line.<commit_after>/* jshint node:true */

var fs          = require('fs');
var path        = require('path');
var bower       = require(path.resolve(__dirname, '../../bower.json'));
var VersionChecker = require('ember-cli-version-checker');

module.exports = {
  description: 'install ember-cli-foundation-6-sass into a typical project',
  normalizeEntityName: function() {},

  beforeInstall: function () {
    return this.addBowerPackageToProject('foundation-sites', bower.dependencies['foundation-sites']);
  },

  afterInstall: function () {
    // Copy the _settings.scss file
    var stylePath = path.join(process.cwd(), 'app', 'styles');
    var foundationPath = path.join(process.cwd(), 'bower_components', 'foundation-sites', 'scss');
    var settingsPath = path.join(foundationPath, 'settings', '_settings.scss');
    var checker = new VersionChecker(this);
    var isGTE6_3_0 = checker.for('foundation-sites', 'bower').satisfies('>=6.3.0');
    var settingsFile = fs.readFileSync(settingsPath);
    var settingsFilePath = path.join(stylePath, '_settings.scss');
    var appFile, appFilePath;

    if (isGTE6_3_0) {
      //edit app.scss to change @import 'foundation'; with @import 'foundation-sites/foundation';
      appFilePath = path.join(stylePath, 'app.scss');
      appFile = fs.readFileSync(appFilePath, 'utf-8');

      appFile = appFile.replace('@import \'foundation\';', '@import \'foundation-sites/foundation\';');

      fs.writeFileSync(appFilePath, appFile);

      //edit settingsFile contents to replace @import 'util/util'; with @import 'foundation-sites/util/util';
      settingsFile = settingsFile.toString('utf-8').replace('@import \'util/util\';', '@import \'foundation-sites/util/util\';');

      this._writeInfoLine('Updated ' + appFilePath + ' with correct foundation import path (see https://github.com/acoustep/ember-cli-foundation-6-sass/issues/40).');
      this._writeInfoLine('Updated ' + settingsFilePath + ' with correct foundation import path (see https://github.com/acoustep/ember-cli-foundation-6-sass/issues/40).');
    }

    fs.writeFileSync(settingsFilePath, settingsFile);

    return this.addPackagesToProject([
      { name: 'ember-cli-sass', target: '^5.1.0' },
      { name: 'broccoli-clean-css', target: '~1.1.0' }
    ]);
  },

  /**
   A wrapper method to write a message with writeWarnLine or writeLine, depending on which version
   of ember-cli is used

   @param {string} msg Message to print
   */
    _writeInfoLine: function(msg) {
        if (this.ui.writeWarnLine) {
            this.ui.writeWarnLine(msg);
        } else {
            this.ui.writeLine(msg, 'INFO');
        }
    }
};
<|endoftext|>


<commit_before>dojo.provide("dijit.form.FilteringSelect");

dojo.require("dijit.form.ComboBox");

dojo.declare(
	"dijit.form.FilteringSelect",
	[dijit.form.MappedTextBox, dijit.form.ComboBoxMixin],
	{
		// summary
		// An enhanced version of the HTML SELECT tag, populated dynamically
		//
		// description
		// An enhanced version of the HTML SELECT tag, populated dynamically. It works
		// very nicely with very large data sets because it can load and page data as needed.
		// It also resembles ComboBox, but does not allow values outside of the provided ones.
		//
		// Similar features:
		//  - There is a drop down list of possible values.
		//	- You can only enter a value from the drop down list.  (You can't
		//	  enter an arbitrary value.)
		//	- The value submitted with the form is the hidden value (ex: CA),
		//	  not the displayed value a.k.a. label (ex: California)
		//
		//	Enhancements over plain HTML version:
		//	- If you type in some text then it will filter down the list of
		//	  possible values in the drop down list.
		//	- List can be specified either as a static list or via a javascript
		//	  function (that can get the list from a server)
		//
		// searchAttr: String
		//		Searches pattern match against this field
		//
		// labelAttr: String
		//		Optional.  The text that actually appears in the drop down.
		//		If not specified, the searchAttr text is used instead.
		labelAttr: "",

		// labelType: String
		//		"html" or "text"
		labelType: "text",

		_isvalid:true,

		_lastDisplayedValue: "",

		isValid:function(){
			return this._isvalid;
		},

		_callbackSetLabel: function(	/*Array*/ result,
						/*Object*/ dataObject,
						/*Boolean?*/ priorityChange){
			// summary:
			//		Callback function that dynamically sets the label of the
			//		ComboBox

			// setValue does a synchronous lookup,
			// so it calls _callbackSetLabel directly,
			// and so does not pass dataObject
			// dataObject==null means do not test the lastQuery, just continue
			if(dataObject && dataObject.query[this.searchAttr] != this._lastQuery){
				return;
			}
			if(!result.length){
				//#3268: do nothing on bad input
				//this._setValue("", "");
				//#3285: change CSS to indicate error
				if(!this._focused){ this.valueNode.value=""; }
				dijit.form.TextBox.superclass.setValue.call(this, undefined, !this._focused);
				this._isvalid=false;
				this.validate(this._focused);
			}else{
				this._setValueFromItem(result[0], priorityChange);
			}
		},

		_openResultList: function(/*Object*/ results, /*Object*/ dataObject){
			// #3285: tap into search callback to see if user's query resembles a match
			if(dataObject.query[this.searchAttr] != this._lastQuery){
				return;
			}
			this._isvalid = results.length != 0; // FIXME: should this be greater-than?
			this.validate(true);
			dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
		},

		getValue:function(){
			// don't get the textbox value but rather the previously set hidden value
			return this.valueNode.value;
		},

		_getValueField:function(){
			// used for option tag selects
			return "value";
		},

		_setValue:function(	/*String*/ value,
					/*String*/ displayedValue,
					/*Boolean?*/ priorityChange){
			this.valueNode.value = value;
			dijit.form.FilteringSelect.superclass.setValue.call(this, value, priorityChange, displayedValue);
			this._lastDisplayedValue = displayedValue;
		},

		setValue: function(/*String*/ value, /*Boolean?*/ priorityChange){
			// summary
			//	Sets the value of the select.
			//	Also sets the label to the corresponding value by reverse lookup.

			//#3347: fetchItemByIdentity if no keyAttr specified
			var self=this;
			var handleFetchByIdentity = function(item, priorityChange){
				if(item){
					if(self.store.isItemLoaded(item)){
						self._callbackSetLabel([item], undefined, priorityChange);
					}else{
						self.store.loadItem({
							item: item,
							onItem: function(result, dataObject){
								self._callbackSetLabel(result, dataObject, priorityChange);
							}
						});
					}
				}else{
					self._isvalid=false;
					// prevent errors from Tooltip not being created yet
					self.validate(false);
				}
			}
			this.store.fetchItemByIdentity({
				identity: value,
				onItem: function(item){
					handleFetchByIdentity(item, priorityChange);
				}
			});
		},

		_setValueFromItem: function(/*item*/ item, /*Boolean?*/ priorityChange){
			//	summary:
			//		Set the displayed valued in the input box, based on a
			//		selected item.
			//	description:
			//		Users shouldn't call this function; they should be calling
			//		setDisplayedValue() instead
			this._isvalid=true;
			this._setValue(	this.store.getIdentity(item),
							this.labelFunc(item, this.store),
							priorityChange);
		},

		labelFunc: function(/*item*/ item, /*dojo.data.store*/ store){
			// summary: Event handler called when the label changes
			// return: the label that the ComboBox should display
			return store.getValue(item, this.searchAttr);
		},

		_doSelect: function(/*Event*/ tgt){
			// summary:
			//		ComboBox's menu callback function
			//	description:
			//		FilteringSelect overrides this to set both the visible and
			//		hidden value from the information stored in the menu
			this.item = tgt.item;
			this._setValueFromItem(tgt.item, true);
		},

		setDisplayedValue:function(/*String*/ label, /*Boolean?*/ priorityChange){
			// summary:
			//		Set textbox to display label. Also performs reverse lookup
			//		to set the hidden value. Used in InlineEditBox

			if(this.store){
				var query = {};
				this._lastQuery = query[this.searchAttr] = label;
				// if the label is not valid, the callback will never set it,
				// so the last valid value will get the warning textbox set the
				// textbox value now so that the impending warning will make
				// sense to the user
				this.textbox.value = label;
				this._lastDisplayedValue = label;
				var _this = this;
				this.store.fetch({
					query: query,
					queryOptions: {
						ignoreCase: this.ignoreCase,
						deep: true
					},
					onComplete: function(result, dataObject){
						        dojo.hitch(_this, "_callbackSetLabel")(result, dataObject, priorityChange);
					},
					onError: function(errText){
						console.error('dijit.form.FilteringSelect: ' + errText);
						dojo.hitch(_this, "_setValue")(undefined, label, false);
					}
				});
			}
		},

		_getMenuLabelFromItem:function(/*Item*/ item){
			// internal function to help ComboBoxMenu figure out what to display
			if(this.labelAttr){
				return {
					html: this.labelType=="html",
					label: this.store.getValue(item, this.labelAttr)
				};
			}else{
				// because this function is called by ComboBoxMenu,
				// this.inherited tries to find the superclass of ComboBoxMenu
				return dijit.form.ComboBoxMixin.prototype._getMenuLabelFromItem.apply(this, arguments);
			}
		},

		postMixInProperties: function(){
			// FIXME: shouldn't this just be a call to inherited?
			dijit.form.ComboBoxMixin.prototype.postMixInProperties.apply(this, arguments);
			dijit.form.MappedTextBox.prototype.postMixInProperties.apply(this, arguments);
		},

		postCreate: function(){
			dijit.form.ComboBoxMixin.prototype._postCreate.apply(this, arguments);
			dijit.form.MappedTextBox.prototype.postCreate.apply(this, arguments);
		},

		setAttribute: function(/*String*/ attr, /*anything*/ value){
			dijit.form.MappedTextBox.prototype.setAttribute.apply(this, arguments);
			dijit.form.ComboBoxMixin.prototype._setAttribute.apply(this, arguments);
		},

		undo: function(){
			this.setDisplayedValue(this._lastDisplayedValue);
		},

		_valueChanged: function(){
			return this.getDisplayedValue()!=this._lastDisplayedValue;
		}
	}
);
<commit_msg>Fixes #6196.  Mixin the user-supplied query.<commit_after>dojo.provide("dijit.form.FilteringSelect");

dojo.require("dijit.form.ComboBox");

dojo.declare(
	"dijit.form.FilteringSelect",
	[dijit.form.MappedTextBox, dijit.form.ComboBoxMixin],
	{
		// summary
		// An enhanced version of the HTML SELECT tag, populated dynamically
		//
		// description
		// An enhanced version of the HTML SELECT tag, populated dynamically. It works
		// very nicely with very large data sets because it can load and page data as needed.
		// It also resembles ComboBox, but does not allow values outside of the provided ones.
		//
		// Similar features:
		//  - There is a drop down list of possible values.
		//	- You can only enter a value from the drop down list.  (You can't
		//	  enter an arbitrary value.)
		//	- The value submitted with the form is the hidden value (ex: CA),
		//	  not the displayed value a.k.a. label (ex: California)
		//
		//	Enhancements over plain HTML version:
		//	- If you type in some text then it will filter down the list of
		//	  possible values in the drop down list.
		//	- List can be specified either as a static list or via a javascript
		//	  function (that can get the list from a server)
		//
		// searchAttr: String
		//		Searches pattern match against this field
		//
		// labelAttr: String
		//		Optional.  The text that actually appears in the drop down.
		//		If not specified, the searchAttr text is used instead.
		labelAttr: "",

		// labelType: String
		//		"html" or "text"
		labelType: "text",

		_isvalid:true,

		_lastDisplayedValue: "",

		isValid:function(){
			return this._isvalid;
		},

		_callbackSetLabel: function(	/*Array*/ result,
						/*Object*/ dataObject,
						/*Boolean?*/ priorityChange){
			// summary:
			//		Callback function that dynamically sets the label of the
			//		ComboBox

			// setValue does a synchronous lookup,
			// so it calls _callbackSetLabel directly,
			// and so does not pass dataObject
			// dataObject==null means do not test the lastQuery, just continue
			if(dataObject && dataObject.query[this.searchAttr] != this._lastQuery){
				return;
			}
			if(!result.length){
				//#3268: do nothing on bad input
				//this._setValue("", "");
				//#3285: change CSS to indicate error
				if(!this._focused){ this.valueNode.value=""; }
				dijit.form.TextBox.superclass.setValue.call(this, undefined, !this._focused);
				this._isvalid=false;
				this.validate(this._focused);
			}else{
				this._setValueFromItem(result[0], priorityChange);
			}
		},

		_openResultList: function(/*Object*/ results, /*Object*/ dataObject){
			// #3285: tap into search callback to see if user's query resembles a match
			if(dataObject.query[this.searchAttr] != this._lastQuery){
				return;
			}
			this._isvalid = results.length != 0; // FIXME: should this be greater-than?
			this.validate(true);
			dijit.form.ComboBoxMixin.prototype._openResultList.apply(this, arguments);
		},

		getValue:function(){
			// don't get the textbox value but rather the previously set hidden value
			return this.valueNode.value;
		},

		_getValueField:function(){
			// used for option tag selects
			return "value";
		},

		_setValue:function(	/*String*/ value,
					/*String*/ displayedValue,
					/*Boolean?*/ priorityChange){
			this.valueNode.value = value;
			dijit.form.FilteringSelect.superclass.setValue.call(this, value, priorityChange, displayedValue);
			this._lastDisplayedValue = displayedValue;
		},

		setValue: function(/*String*/ value, /*Boolean?*/ priorityChange){
			// summary
			//	Sets the value of the select.
			//	Also sets the label to the corresponding value by reverse lookup.

			//#3347: fetchItemByIdentity if no keyAttr specified
			var self=this;
			var handleFetchByIdentity = function(item, priorityChange){
				if(item){
					if(self.store.isItemLoaded(item)){
						self._callbackSetLabel([item], undefined, priorityChange);
					}else{
						self.store.loadItem({
							item: item,
							onItem: function(result, dataObject){
								self._callbackSetLabel(result, dataObject, priorityChange);
							}
						});
					}
				}else{
					self._isvalid=false;
					// prevent errors from Tooltip not being created yet
					self.validate(false);
				}
			}
			this.store.fetchItemByIdentity({
				identity: value,
				onItem: function(item){
					handleFetchByIdentity(item, priorityChange);
				}
			});
		},

		_setValueFromItem: function(/*item*/ item, /*Boolean?*/ priorityChange){
			//	summary:
			//		Set the displayed valued in the input box, based on a
			//		selected item.
			//	description:
			//		Users shouldn't call this function; they should be calling
			//		setDisplayedValue() instead
			this._isvalid=true;
			this._setValue(	this.store.getIdentity(item),
							this.labelFunc(item, this.store),
							priorityChange);
		},

		labelFunc: function(/*item*/ item, /*dojo.data.store*/ store){
			// summary: Event handler called when the label changes
			// return: the label that the ComboBox should display
			return store.getValue(item, this.searchAttr);
		},

		_doSelect: function(/*Event*/ tgt){
			// summary:
			//		ComboBox's menu callback function
			//	description:
			//		FilteringSelect overrides this to set both the visible and
			//		hidden value from the information stored in the menu
			this.item = tgt.item;
			this._setValueFromItem(tgt.item, true);
		},

		setDisplayedValue:function(/*String*/ label, /*Boolean?*/ priorityChange){
			// summary:
			//		Set textbox to display label. Also performs reverse lookup
			//		to set the hidden value. Used in InlineEditBox

			if(this.store){
				var query = dojo.clone(this.query); // #6196: populate query with user-specifics
				this._lastQuery = query[this.searchAttr] = label;
				// if the label is not valid, the callback will never set it,
				// so the last valid value will get the warning textbox set the
				// textbox value now so that the impending warning will make
				// sense to the user
				this.textbox.value = label;
				this._lastDisplayedValue = label;
				var _this = this;
				this.store.fetch({
					query: query,
					queryOptions: {
						ignoreCase: this.ignoreCase,
						deep: true
					},
					onComplete: function(result, dataObject){
						        dojo.hitch(_this, "_callbackSetLabel")(result, dataObject, priorityChange);
					},
					onError: function(errText){
						console.error('dijit.form.FilteringSelect: ' + errText);
						dojo.hitch(_this, "_setValue")(undefined, label, false);
					}
				});
			}
		},

		_getMenuLabelFromItem:function(/*Item*/ item){
			// internal function to help ComboBoxMenu figure out what to display
			if(this.labelAttr){
				return {
					html: this.labelType=="html",
					label: this.store.getValue(item, this.labelAttr)
				};
			}else{
				// because this function is called by ComboBoxMenu,
				// this.inherited tries to find the superclass of ComboBoxMenu
				return dijit.form.ComboBoxMixin.prototype._getMenuLabelFromItem.apply(this, arguments);
			}
		},

		postMixInProperties: function(){
			// FIXME: shouldn't this just be a call to inherited?
			dijit.form.ComboBoxMixin.prototype.postMixInProperties.apply(this, arguments);
			dijit.form.MappedTextBox.prototype.postMixInProperties.apply(this, arguments);
		},

		postCreate: function(){
			dijit.form.ComboBoxMixin.prototype._postCreate.apply(this, arguments);
			dijit.form.MappedTextBox.prototype.postCreate.apply(this, arguments);
		},

		setAttribute: function(/*String*/ attr, /*anything*/ value){
			dijit.form.MappedTextBox.prototype.setAttribute.apply(this, arguments);
			dijit.form.ComboBoxMixin.prototype._setAttribute.apply(this, arguments);
		},

		undo: function(){
			this.setDisplayedValue(this._lastDisplayedValue);
		},

		_valueChanged: function(){
			return this.getDisplayedValue()!=this._lastDisplayedValue;
		}
	}
);
<|endoftext|>


<commit_before>/* ==========================================================================
	 Trak - Universal event tracking API
	 https://github.com/tmwagency/trak.js/
	 ========================================================================== */

function Trak() {
	console.log('Trak loaded');

	var trakElements = document.querySelectorAll('[data-trak]');
	// console.log(trakElements);
	for (var i = 0; i < trakElements.length ; i++) {
		trakElements[i].addEventListener('click', dataAttrEvent, true);
	}

	function dataAttrEvent() {
		var _options = JSON.parse(this.getAttribute("data-trak"));
		var _category;
		var _action;
		var _label;

		switch(_options.category) {
			case 'page.title':
				_category = document.title;
				break;
			case 'page.href':
				_category = window.location.href;
				break;
			case 'link.href':
				_category = this.href;
				break;
			case 'link.title':
				_category = this.title;
				break;
			default:
				_category = Trak.clean(_options.category);
				break;
		}

		switch(_options.action) {
			case 'page.title':
				_action = document.title;
				break;
			case 'page.href':
				_action = window.location.href;
				break;
			case 'link.href':
				_action = this.href;
				break;
			case 'link.title':
				_action = this.title;
				break;
			default:
				_action = Trak.clean(_options.action);
				break;
		}

		switch(_options.label) {
			case 'page.title':
				_label = document.title;
				break;
			case 'page.href':
				_label = window.location.href;
				break;
			case 'link.href':
				_label = this.href;
				break;
			case 'link.title':
				_label = this.title;
				break;
			default:
				_label = Trak.clean(_options.label);
				break;
		}
		// console.log(_category, _action, _label);
		Trak.event(_category, _action, _label);
	}
}

Trak.clean = function(str) {
	return str.toString().replace(/\s|'|"/g, this.options.delimeter).toLowerCase();
};

Trak.event = function(category, action, label, value, nonInteraction) {
	value          = 0 || value;
	nonInteraction = false || nonInteraction;

	if (Trak.options.trackType === 'ga' && typeof ga !== 'undefined') {
		ga('send', 'event', Trak.clean(category), Trak.clean(action), Trak.clean(label), value, {'nonInteraction': nonInteraction});

		/**
		 * Could use the below instead:
		 *
		ga('send', {
			'hitType': 'event',
			'eventCategory': Trak.clean(category),
			'eventAction': Trak.clean(action),
			'eventLabel': Trak.clean(label),
			'eventValue': value,
			{
				'nonInteraction': nonInteraction
			}
		});
		*/
	}

	if (Trak.options.trackType === '_gaq' && typeof _gaq !== 'undefined') {
		_gaq.push(['_trackEvent', Trak.clean(category), Trak.clean(action), Trak.clean(label), value]);
	}

	/**
	 * Add any others that you would like here:
	 */
};

Trak.options = {
	delimeter : '_', // Trak.options.delimeter = '-'
	trackType : 'ga' // Trak.options.trackType = 'ga' Options
};

document.addEventListener('DOMContentLoaded', function(e) {
	Trak();
});<commit_msg>Vast improvements: - added wildcard function for dealing with wildcards nicely - comment descriptions added throughout<commit_after>/**
 * @preserve Trak - Universal event tracking API
 *
 * @version 0.1.0
 * @license MIT License (see LICENSE)
 */

function Trak() {
	var trakElements = document.querySelectorAll('[data-trak]');
	for (var i = 0; i < trakElements.length ; i++) {
		trakElements[i].addEventListener('click', dataAttrEvent, true);
	}

	/**
	 * Function to convert wildcards into real values
	 * @param  string str
	 * @return string     The converted ouput from str
	 */
	function wildcard(str) {
		switch(str) {
			case 'page.title':
				output = document.title;
				break;
			case 'page.href':
				output = window.location.href;
				break;
			case 'link.href':
				output = this.href;
				break;
			case 'link.title':
				output = this.title;
				break;
			default:
				output = Trak.clean(str);
				break;
		}
		return output;
	}

	/**
	 * dataAttrEvent
	 * This is called when any element with the [data-trak] attribute is clicked.
	 * It calls Trak.event()
	 */
	function dataAttrEvent() {
		var _options  = JSON.parse(this.getAttribute("data-trak"));
		var _category = wildcard(_options.category);
		var _action   = wildcard(_options.action);
		var _label    = wildcard(_options.label);
		Trak.event(_category, _action, _label);
	}
}
/**
 * Trak.clean()
 * Cleans the input replacing spaces with a specified delimeter (see Trak.options) and converts to lower case
 * @param  string str
 * @return string cleaned string
 */
Trak.clean = function(str) {
	return str.toString().replace(/\s|'|"/g, this.options.delimeter).toLowerCase();
};

/**
 * Trak.event()
 * Wrapper function for various analytics APIs.
 * Enables you to add more than one, or change mid-project without changing anything else in your code
 * @param  string category        The category of the tracking event
 * @param  string action          The action of the tracking event
 * @param  string label           The label of the tracking event
 * @param  number value           Use this to assign a numerical value to a tracked page object
 * @param  boolean nonInteraction Used if Trak.options.trackType = 'ga': you might want to send an event, but not impact your bounce rate.
 */
Trak.event = function(category, action, label, value, nonInteraction) {
	value          = value || 0;
	nonInteraction = nonInteraction || false;

	if (Trak.options.trackType === 'ga' && typeof ga !== 'undefined') {
		ga('send', 'event', Trak.clean(category), Trak.clean(action), Trak.clean(label), value, {'nonInteraction': nonInteraction});

		/**
		 * Could use the below instead:
		 *
		ga('send', {
			'hitType': 'event',
			'eventCategory': Trak.clean(category),
			'eventAction': Trak.clean(action),
			'eventLabel': Trak.clean(label),
			'eventValue': value,
			{
				'nonInteraction': nonInteraction
			}
		});
		*/
	} else if (Trak.options.trackType === '_gaq' && typeof _gaq !== 'undefined') {
		_gaq.push(['_trackEvent', Trak.clean(category), Trak.clean(action), Trak.clean(label), value]);
	}

	/**
	 * Add any others that you would like here:
	 */

};

/**
 * Trak.options
 * These are the default options for trak.js.
 * To override these, you have to reassign the values to
 * @type {Object}
 */
Trak.options = {
	delimeter : '_', // Trak.options.delimeter = '-'
	trackType : 'ga' // Trak.options.trackType = 'ga' Available options: ga, _gaq
};

document.addEventListener('DOMContentLoaded', function(e) {
	Trak();
});<|endoftext|>


<commit_before>import React from 'react'
import PokemonPreview from '../components/PokemonPreview'
import PlaceholderPreview from '../components/PlaceholderPreview'
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'

class Pokedex extends React.Component {

  static propTypes = {
    data: React.PropTypes.object.isRequired,
  }

  render () {
    if (this.props.data.loading) {
      return (
Loading
)
    }

    return (

          Hey {this.props.data.Trainer.name}, there are {this.props.data.Trainer.ownedPokemons.length} Pokemons in your pokedex

          {this.props.data.Trainer.ownedPokemons.map((pokemon) =>
            <PokemonPreview key={pokemon.id} pokemon={pokemon} />
          )}
          <PlaceholderPreview key={this.props.data.Trainer.id} trainerId={this.props.data.Trainer.id}/>

    )
  }
}

const TrainerQuery = gql`query($name: String!) {
  Trainer(name: $name) {
    id
    name
    ownedPokemons {
      id
      name
      imageUrl
    }
  }
}`

const PokemonPageWithData = graphql(TrainerQuery, {
  options: {
      variables: {
        name: "<your name>"
      }
    }
  }
)(withRouter(PokemonPage))

export default PokedexWithData
<commit_msg>fix Pokedex typos<commit_after>import React from 'react'
import PokemonPreview from '../components/PokemonPreview'
import PlaceholderPreview from '../components/PlaceholderPreview'
import { graphql } from 'react-apollo'
import gql from 'graphql-tag'

class Pokedex extends React.Component {

  static propTypes = {
    data: React.PropTypes.object.isRequired,
  }

  render () {
    if (this.props.data.loading) {
      return (
Loading
)
    }

    return (

          Hey {this.props.data.Trainer.name}, there are {this.props.data.Trainer.ownedPokemons.length} Pokemons in your pokedex

          {this.props.data.Trainer.ownedPokemons.map((pokemon) =>
            <PokemonPreview key={pokemon.id} pokemon={pokemon} />
          )}
          <PlaceholderPreview key={this.props.data.Trainer.id} trainerId={this.props.data.Trainer.id}/>

    )
  }
}

const TrainerQuery = gql`query($name: String!) {
  Trainer(name: $name) {
    id
    name
    ownedPokemons {
      id
      name
      imageUrl
    }
  }
}`

const PokedexWithData = graphql(TrainerQuery, {
  options: {
      variables: {
        name: "<your name>"
      }
    }
  }
)(Pokedex)

export default PokedexWithData
<|endoftext|>


<commit_before>/* See license.txt for terms of usage */

FBL.ns(function() { with (FBL) {

/**

Problems
    - cross-browser compatibily (addEventListener versus attachEvent, event object differences)
    - performance (we need to reduce the number of events attached to elements --> event delegation)

Related-problems
    - memory leak (we need to avoid circular references between DOM and JS worlds --> cache)
    - remote object identification (we can't use XPATH for JavaScript objects)

Goals
  - Define an API to handle event-related problems (event handling, event delegation, key listening)

Questions

Using expando property to cache elements
  - we need this to optimize cache lookup time and avoid attaching JavaScript objects into DOM Elements (no circular references problem, less prone to memory leaks)
  - Is this ok in Firebug code? Firebug Lite currently uses this

Controller definition using CSS selectors or classes-only
  - How to verify if a particular element matches a CSS selector in FF?

Control is an visual component that respond to user actions

Controller is a special kind of Control that operates several sub-components (internal Controls)
using a single Control component

Event

Action

Controller

http://docwiki.embarcadero.com/VCL/en/Controls.TControl

API

Firebug.Inspector::click

----------------------------------------------------------------------------------------------------
Lib/Event Module
----------------------------------------------------------------------------------------------------
    Lib.addEvent(element, namespace-type, callback, capture)
    Lib.removeEvent(element, namespace-type, callback, capture)
    Lib.removeEvents(namespace)

    Lib.cancelEvent(event, preventDefault) ?

    // KeyEvent object for non-FF browsers
    Lib.KeyEvent = window.KeyEvent ||
    {
        DOM_VK_CANCEL: 3,
        DOM_VK_HELP: 6,
        DOM_VK_BACK_SPACE: 8,
        DOM_VK_TAB: 9,
        DOM_VK_CLEAR: 12,
        DOM_VK_RETURN: 13,
        DOM_VK_ENTER: 14,
        ...
    }

----------------------------------------------------------------------------------------------------
Lib/Event Module (currently in Lib)
----------------------------------------------------------------------------------------------------
    Lib.noKeyModifiers(event)

    Lib.isControl(event)
    Lib.isShift(event)
    Lib.isAlt(event)
    Lib.isControlShift(event)

    Lib.isLeftClick(event)
    Lib.isMiddleClick(event)
    Lib.isRightClick(event)
    Lib.isControlClick(event)
    Lib.isShiftClick(event)
    Lib.isAltClick(event)

----------------------------------------------------------------------------------------------------
Firebug.Control(context?, element)
----------------------------------------------------------------------------------------------------
    addEvent(namespace-type, callback, capture)
    removeEvent(namespace-type, callback, capture)
    removeEvents(namespace)

----------------------------------------------------------------------------------------------------
Firebug.Controller(context?, element)
----------------------------------------------------------------------------------------------------
    addController(selector, namespace-type, callback, capture)
    removeController(selector, namespace-type, callback, capture)
    removeControllers(namespace)

    addKeyController(key, filter, listener, capture, priority?)
    removeKeyController(key)
    removeKeyControllers()

    addCharController(character, filter, listener, capture, priority?)
    removeCharController(character)
    removeCharControllers()

    ++filters
    ++keyConstants

    - all mouse events should be delegated
    - all keyboard events should be delegated
    - all resize events should be delegated
    - all scroll events should be delegated

    - avoid using addEvent directly. Use it only for specific cases such as:
        - load
        - focus
        - blur

*/

// ************************************************************************************************
// Globals

var EventCache = Firebug.Lite.Cache.Event;

window.addEvent = function(element, type, callback, capture)
{
    var id = EventCache(element);

    if (!id) return;

    // read namespaces
    var info = readEventNamespace(type);
    var namespaces = info.namespaces;
    type = info.type;

    // event data
    var eventMap = EventCache.data(element, "eventMap");

    if (!eventMap)
    {
        eventMap = EventCache.data(element, "eventMap", {});
    }

    var eventData = eventMap[type];

    if (!eventData)
    {
        eventMap = eventMap[type] = {
            callbacks: [],
            handler: null
        };
    }

    // callback queue
    var eventCallbacks = eventData.callbacks;

    // event handler
    var eventHandler = eventData.handler;

    if (!eventHandler)
    {
        eventHandler = eventData.handler = function(event)
        {
            event = fixEvent(event);

            for (var i = 0, length = eventCallbacks.length; i < length; i++)
            {
                var item = eventCallbacks[i];

                item.callback.call(element, event);
            }
        };
    }

    // add event to the queue
    eventCallbacks.push({
        type: type, // redundant.... remove this?
        callback: callback,
        capture: capture,
        namespaces: namespaces
    });

    if (eventCallbacks.length == 1)
    {
        if (element.addEventListener)
            element.addEventListener(type, eventHandler, capture);
        else
            element.attachEvent("on"+type, eventHandler);
    }
};

window.removeEvent = function(element, type, callback, capture)
{
    var id = EventCache(element);

    if (!id) return;

    // read namespaces
    var info = readEventNamespace(type);
    var namespaces = info.namespaces;
    type = info.type;

    // event map data
    var eventMap = EventCache.data(element, "eventMap");
    if (!eventMap) return;

    var types = [];

    if (type)
    {
        types = [type];
    }
    else
    {
        for (var name in eventData)
        {
            types.push(name);
        }
    }

    for (var t = 0, tlength = types.length; t < tlength; t++)
    {
        type = types[t];

        // event data
        var eventData = eventMap[type];

        // callback queue
        var eventCallbacks = eventData.callbacks;
        if (!eventCallbacks) return;

        // event handler
        var eventHandler = eventData.handler;

        for (var i = 0;
            // we cannot store the length as a way to improve the performance because
            // we're removing elements from the array, so we need to actually read
            // the length in every loop iteration to make sure we have reached the end
            i < eventCallbacks.length;
            )
        {
            var item = eventCallbacks[i];

            /*

            cases
                - click
                - click.namespace
                - click.namespace.plus
                - .namespace

            has type --> look for 1 type
            has no type --> look for all types

                has namespace --> compare

                has callback --> compare

                no namespace, no callback (case removeEvent(el, "click")) --> remove all events with the given type

            */

            if (
              (callback && item.callback == callback || !callback) &&
              (namespaces && compareEventNamespace(namespaces, item.namespaces) || !namespaces)
            )
            {
                eventCallbacks.splice(i, 1);
            }
            else
            {
                // we must advance the cursor only if current item wasn't removed
                i++;
            }
        }

        if (eventCallbacks.length == 0)
        {
            if (element.removeEventListener)
                element.removeEventListener(type, eventHandler, capture);
            else
                element.detachEvent("on"+type, eventHandler);
        }

    }
};

// ************************************************************************************************
// Locals

var readEventNamespace = function(type)
{
    var info = {};

    if (type.indexOf(".") != -1)
    {
        var parts = type.split(".");

        // type is the first name
        info.type = parts.shift();
        // namespaces are all remaining parts (eg: click.MyPanel.MyPanelAction)
        info.namespaces = parts.length > 0 ? parts : null;
    }
    else
    {
        info.type = type;
    }

    return info;
};

var compareEventNamespace = function(namespaces, baseNamespaces)
{
    if (!namespaces || !baseNamespaces) return false;

    var base = " " + baseNamespaces.join(" ") + " ";
    var count = 0;
    var ns;

    for (var i = 0, length = namespaces.length; i < length; i++)
    {
        ns = namespaces[i];

        if ( base.indexOf(" " + ns + " ") != -1 )
        {
            count++;
        }
    }

    return count == length;
};

// ************************************************************************************************

/**
 * Support for cross-browser compatible event.
 */
var expando = "helloModule";
var fixEvent = function(event)
{
    if ( event[expando] == true )
        return event;

    // store a copy of the original event object
    // and "clone" to set read-only properties
    var originalEvent = event;
    event = { originalEvent: originalEvent };
    var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");
    for ( var i=props.length; i; i-- )
        event[ props[i] ] = originalEvent[ props[i] ];

    // Mark it as fixed
    event[expando] = true;

    // add preventDefault and stopPropagation since
    // they will not work on the clone
    event.preventDefault = function() {
        // if preventDefault exists run it on the original event
        if (originalEvent.preventDefault)
            originalEvent.preventDefault();
        // otherwise set the returnValue property of the original event to false (IE)
        originalEvent.returnValue = false;
    };
    event.stopPropagation = function() {
        // if stopPropagation exists run it on the original event
        if (originalEvent.stopPropagation)
            originalEvent.stopPropagation();
        // otherwise set the cancelBubble property of the original event to true (IE)
        originalEvent.cancelBubble = true;
    };

    // Fix timeStamp
    event.timeStamp = event.timeStamp || this.now();

    // Fix target property, if necessary
    if ( !event.target )
        event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either

    // check if target is a textnode (safari)
    if ( event.target.nodeType == 3 )
        event.target = event.target.parentNode;

    // Add relatedTarget, if necessary
    if ( !event.relatedTarget && event.fromElement )
        event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;

    // Calculate pageX/Y if missing and clientX/Y available
    if ( event.pageX == null && event.clientX != null ) {
        var doc = document.documentElement, body = document.body;
        event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
        event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
    }

    // Add which for key events
    if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
        event.which = event.charCode || event.keyCode;

    // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
    if ( !event.metaKey && event.ctrlKey )
        event.metaKey = event.ctrlKey;

    // Add which for click: 1 == left; 2 == middle; 3 == right
    // Note: button is not normalized, so don't use it
    if ( !event.which && event.button )
        event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));

    return event;
};

// ************************************************************************************************

}});
<commit_msg>[flexBox &lite1.4] Several improvements in the eventDelegator implementation. Implemented Control and Controller classes (which will be later in a separate file)<commit_after>/* See license.txt for terms of usage */

FBL.ns(function() {

/*

  TODO:
    - API
            Event.add versus Event.addEvent

    - do not store objects in cache variables, use key instead

    - priority?
    - sort controller callbacks based on rule specificity?
    - cancel propagation for controllers?

    - use it for internal events?
        - need to attach "key" attribute to individual objects

*/

/**

Problems
    - cross-browser compatibily (addEventListener versus attachEvent, event object differences)
    - performance (we need to reduce the number of events attached to elements --> event delegation)

Related-problems
    - memory leak (we need to avoid circular references between DOM and JS worlds --> cache)
    - remote object identification (we can't use XPATH for JavaScript objects)

Goals
    - Define an API to handle event-related problems (event handling, event delegation, key listening)

Tips for avoiding problem with events
    - avoid adding events to elements. Use controls/controllers instead.

    - Chrome controller
        - all mouse events should be delegated
        - all keyboard events should be delegated
        - all resize events should be delegated
        - all scroll events should be delegated

~~~~~~~~~

Questions

Using expando property to cache elements
  - we need this to optimize cache lookup time and avoid attaching JavaScript objects into DOM Elements (no circular references problem, less prone to memory leaks)
  - Is this ok in Firebug code? Firebug Lite currently uses this

Controller definition using CSS selectors or classes-only
  - How to verify if a particular element matches a CSS selector in FF?

~~~~~~~~~

Control is an visual component that responds to user actions

Controller is a special kind of Control that operates several sub-components (internal Controls)
using a single Control component

http://docwiki.embarcadero.com/VCL/en/Controls.TControl

~~~~~~~~~

API - draft

----------------------------------------------------------------------------------------------------
Lib/Event Module
----------------------------------------------------------------------------------------------------
    Lib.addEvent(element, namespace-type, callback, capture)
    Lib.removeEvent(element, namespace-type, callback, capture)
    Lib.removeEvents(namespace)

    Lib.cancelEvent(event, preventDefault) ?

    // KeyEvent object for non-FF browsers
    Lib.KeyEvent = window.KeyEvent ||
    {
        DOM_VK_CANCEL: 3,
        DOM_VK_HELP: 6,
        DOM_VK_BACK_SPACE: 8,
        DOM_VK_TAB: 9,
        DOM_VK_CLEAR: 12,
        DOM_VK_RETURN: 13,
        DOM_VK_ENTER: 14,
        ...
    }

----------------------------------------------------------------------------------------------------
Lib/Event Module (currently in Lib)
----------------------------------------------------------------------------------------------------
    Lib.noKeyModifiers(event)

    Lib.isControl(event)
    Lib.isShift(event)
    Lib.isAlt(event)
    Lib.isControlShift(event)

    Lib.isLeftClick(event)
    Lib.isMiddleClick(event)
    Lib.isRightClick(event)
    Lib.isControlClick(event)
    Lib.isShiftClick(event)
    Lib.isAltClick(event)

----------------------------------------------------------------------------------------------------
Firebug.Control(context?, element)
----------------------------------------------------------------------------------------------------
    addEvent(namespace-type, callback, capture)
    removeEvent(namespace-type, callback, capture)
    removeEvents(namespace)

----------------------------------------------------------------------------------------------------
Firebug.Controller(context?, element)
----------------------------------------------------------------------------------------------------
    addController(selector, namespace-type, callback, capture)
    removeController(selector, namespace-type, callback, capture)
    removeControllers(namespace)

    addKeyController(key, filter, listener, capture, priority?)
    removeKeyController(key)
    removeKeyControllers()

    addCharController(character, filter, listener, capture, priority?)
    removeCharController(character)
    removeCharControllers()

*/

// ************************************************************************************************
// Globals

var EventCache = new Cache();

window.addEvent = function(element, type, callback, capture, owner, validator, data, bubble)
{
    var id = EventCache.set(element);

    if (!id) return;

    // the "owner" is which object means "this" inside the callback function
    owner = owner || element;

    // read type and namespaces
    var info = readEventNamespace(type);
    var namespaces = info.namespaces;
    type = info.type;

    // read eventMap, which will hold data for all types of event
    var eventMap = EventCache.data(element, "eventMap");

    // if there's no eventMap, create one
    if (!eventMap)
    {
        eventMap = EventCache.data(element, "eventMap", {});
    }

    // read eventData
    var eventData = eventMap[type];

    // if there's no eventData, create one
    if (!eventData)
    {
        eventData = eventMap[type] = {
            listeners: [],
            handler: null
        };
    }

    // callback queue
    var eventListeners = eventData.listeners;

    // event handler
    var eventHandler = eventData.handler;

    // if there's no handler, create one
    if (!eventHandler)
    {
        eventHandler = eventData.handler = function(event)
        {
            //console.time("handling "+type);

            event = fixEvent(event);

            var target = event.target;

            do
            {
                for (var i = 0, length = eventListeners.length; i < length; i++)
                {
                    var listener = eventListeners[i];

                    if (validator && validator.call(owner, event, listener) || !validator)
                        listener.callback.call(owner, event);
                }

                target = event.target = bubble && // if should bubble up
                        !event.isPropagationStopped() && // and propagation is not stopped
                        target.parentNode; // then we must look for the parent node
                        // otherwise target variable will be set to null
            }
            while(target);

            //console.timeEnd("handling "+type);
        };
    }

    // add event to the queue
    eventListeners.push({
        //type: type, // redundant.... remove this?
        callback: callback,
        capture: capture,
        namespaces: namespaces,
        data: data
    });

    if (eventListeners.length == 1)
    {
        if (element.addEventListener)
            element.addEventListener(type, eventHandler, capture);
        else
            element.attachEvent("on"+type, eventHandler);
    }
};

window.removeEvent = function(element, type, callback, capture, owner, validator)
{
    var id = EventCache.key(element);

    if (!id) return;

    // read namespaces
    var info = readEventNamespace(type);
    var namespaces = info.namespaces;
    type = info.type;

    // event map data
    var eventMap = EventCache.data(element, "eventMap");
    if (!eventMap) return;

    var eventData;

    var types = [];

    if (type)
    {
        types = [type];
    }
    else
    {
        for (var name in eventMap)
        {
            types.push(name);
        }
    }

    for (var t = 0, tlength = types.length; t < tlength; t++)
    {
        type = types[t];

        // event data
        var eventData = eventMap[type];

        // callback queue
        var eventListeners = eventData.listeners;
        if (!eventListeners) return;

        // event handler
        var eventHandler = eventData.handler;

        for (var i = 0;
            // we cannot store the length as a way to improve the performance because
            // we're removing elements from the array, so we need to actually read
            // the length in every loop iteration to make sure we have reached the end
            i < eventListeners.length;
            )
        {
            var listener = eventListeners[i];

            /*
            cases
                - click
                - click.namespace
                - click.namespace.plus
                - .namespace

            has type --> look for 1 type
            has no type --> look for all types

                has namespace --> compare
                has callback --> compare
                no namespace, no callback (case removeEvent(el, "click")) --> remove all events with the given type
            */

            if (
              (callback && listener.callback == callback || !callback) &&
              (namespaces && compareEventNamespace(namespaces, listener.namespaces) || !namespaces) &&
              (validator && validator.call(owner, listener) || !validator)
            )
            {
                listener.callback = null;
                eventListeners.splice(i, 1);
                EventCache.free(element);
            }
            else
            {
                // we must advance the cursor only if current listener wasn't removed
                i++;
            }
        }

        if (eventListeners.length == 0)
        {
            if (element.removeEventListener)
                element.removeEventListener(type, eventHandler, capture);
            else
                element.detachEvent("on"+type, eventHandler);
        }

    }
};

// ************************************************************************************************
// Locals

var readEventNamespace = function(type)
{
    var info = {};

    if (type.indexOf(".") != -1)
    {
        var parts = type.split(".");

        // type is the first name
        info.type = parts.shift();
        // namespaces are all remaining parts (eg: click.MyPanel.MyPanelAction)
        info.namespaces = parts.length > 0 ? parts : null;
    }
    else
    {
        info.type = type;
    }

    return info;
};

var compareEventNamespace = function(namespaces, baseNamespaces)
{
    if (!namespaces || !baseNamespaces) return false;

    var base = " " + baseNamespaces.join(" ") + " ";
    var count = 0;
    var ns;

    for (var i = 0, length = namespaces.length; i < length; i++)
    {
        ns = namespaces[i];

        if ( base.indexOf(" " + ns + " ") != -1 )
        {
            count++;
        }
    }

    return count == length;
};

// ************************************************************************************************

/**
 * Support for cross-browser compatible event.
 */
var expando = "helloModule";
var fixEvent = function(event)
{
    if ( event[expando] == true )
        return event;

    // store a copy of the original event object
    // and "clone" to set read-only properties
    var originalEvent = event;
    event = { originalEvent: originalEvent };
    // TODO: xxxpedro any particular reason to not use "for var name in originalEvent"?
    var props = "altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target timeStamp toElement type view wheelDelta which".split(" ");
    for ( var i=props.length; i; i-- )
        event[ props[i] ] = originalEvent[ props[i] ];

    var isPropagationStopped = false;

    // Mark it as fixed
    event[expando] = true;

    // add preventDefault and stopPropagation since
    // they will not work on the clone
    event.preventDefault = function() {
        // if preventDefault exists run it on the original event
        if (originalEvent.preventDefault)
            originalEvent.preventDefault();
        // otherwise set the returnValue property of the original event to false (IE)
        originalEvent.returnValue = false;
    };
    event.stopPropagation = function() {
        // if stopPropagation exists run it on the original event
        if (originalEvent.stopPropagation)
            originalEvent.stopPropagation();
        // otherwise set the cancelBubble property of the original event to true (IE)
        originalEvent.cancelBubble = true;

        isPropagationStopped = true;
    };
    event.isPropagationStopped = function()
    {
        return isPropagationStopped;
    };

    // Fix timeStamp
    //event.timeStamp = event.timeStamp || this.now();
    // TODO: xxxpedro what is this now() function? ask honza where this fixEvent function came from
    event.timeStamp = event.timeStamp || new Date().getTime();

    // Fix target property, if necessary
    if ( !event.target )
        event.target = event.srcElement || document; // Fixes #1925 where srcElement might not be defined either

    // check if target is a textnode (safari)
    if ( event.target.nodeType == 3 )
        event.target = event.target.parentNode;

    // Add relatedTarget, if necessary
    if ( !event.relatedTarget && event.fromElement )
        event.relatedTarget = event.fromElement == event.target ? event.toElement : event.fromElement;

    // Calculate pageX/Y if missing and clientX/Y available
    if ( event.pageX == null && event.clientX != null ) {
        var doc = document.documentElement, body = document.body;
        event.pageX = event.clientX + (doc && doc.scrollLeft || body && body.scrollLeft || 0) - (doc.clientLeft || 0);
        event.pageY = event.clientY + (doc && doc.scrollTop || body && body.scrollTop || 0) - (doc.clientTop || 0);
    }

    // Add which for key events
    if ( !event.which && ((event.charCode || event.charCode === 0) ? event.charCode : event.keyCode) )
        event.which = event.charCode || event.keyCode;

    // Add metaKey to non-Mac browsers (use ctrl for PC's and Meta for Macs)
    if ( !event.metaKey && event.ctrlKey )
        event.metaKey = event.ctrlKey;

    // Add which for click: 1 == left; 2 == middle; 3 == right
    // Note: button is not normalized, so don't use it
    if ( !event.which && event.button )
        event.which = (event.button & 1 ? 1 : ( event.button & 2 ? 3 : ( event.button & 4 ? 2 : 0 ) ));

    return event;
};

// ************************************************************************************************

function Control(element)
{
    this._controlElement = element;
}

Control.prototype =
{
    addEvent: function(type, callback, capture){
        addEvent(this._controlElement, getControlType(type), callback, capture, this);
    },
    removeEvent: function(type, callback, capture){
        removeEvent(this._controlElement, getControlType(type), callback, capture);
    },
    removeEvents: function(){
        removeEvent(this._controlElement, getControlType(""));
    }
};

function getControlType(type)
{
    return type + ".{Control}";
}

// ************************************************************************************************

function Controller(element)
{
    this._controlElement = element;
}

Controller.prototype = FBL.extend(Control.prototype,
{
    addController: function(selector, type, callback, capture)
    {
        function addControllerValidator(e, listener)
        {
            return Firebug.Selector.matches(listener.data.selector, [e.target]).length > 0;
        }

        addEvent(this._controlElement, getControllerType(selector, type), callback, null,
                this, addControllerValidator, {selector: selector}, true);
    },
    removeController: function(selector, type, callback, capture)
    {
        function removeControllerValidator(listener)
        {
            return listener.data.selector == selector/* && listener.callback == callback*/;
        }

        removeEvent(this._controlElement, getControllerType(selector, type), callback, null,
                this, removeControllerValidator);
    },
    removeControllers: function()
    {
        removeEvent(this._controlElement, getControllerType("", ""));
    }
});

function getControllerType(selector, type)
{
    return (type||"")+".Controller"+(selector ? ".Selector_"+selector.replace(/\s|\./g, "_") : "");
}

// ************************************************************************************************

function WindowController(win)
{
    this._controlElement = win;
}

WindowController.prototype = FBL.extend(Controller.prototype,
{
    addKeyController: function(key, filter, listener, capture /*, priority?*/)
    {
    },

    removeKeyController: function(key)
    {
    },

    removeKeyControllers: function()
    {
    },

    addCharController: function(character, filter, listener, capture /*, priority? */ )
    {
    },

    removeCharController: function(character)
    {
    },

    removeCharControllers: function()
    {
    }
});

// ************************************************************************************************

/*
// TODO: remove test stuff
window.Control = Control;
window.Controller = Controller;

h1 = function(){ console.log("t1"); };
h2 = function(){ console.log("t2"); };

c = new Controller( document.body );

c.addController("#main", "click", function(){ console.log("main"); });
c.addController("h1", "click", function(e){ e.stopPropagation();console.log("h1"); });

c.addController("h1", "mouseover", h1);
c.addController("h1", "mouseover", h2);
c.addController("h2", "mouseover", h2);

window.c = c;
*/

// ************************************************************************************************

});
<|endoftext|>


<commit_before>//
// tree.js
//
// tree data structure in javascript
//

tree = function() {

	var pub = {}

	// creates a new node
	pub.node = function( item ) {

		var nod = make.node( item)
		return nod
	}

	// namespace
	var make = {}

	// create a new node
	make.node = function( item ) {
		// node
		var nod = {}

		// item
		// "payload" of the node
		// assign the provided item property
		nod.item = null
		if( item )
			nod.item = item

		// top node
		nod.top = null

		// prev
		nod.prev = null

		// next
		nod.next = null

		// namespace for sub nodes
		nod.sub = make.sub( nod )

		// removes the node form its tree.
		// returns the node.
		nod.rip = function() {

			if( ! nod.top ) return nod

			if( nod.next )
				nod.next.prev = nod.prev
			if( nod.prev )
				nod.prev.next = nod.next

			nod.top.sub.n--
			nod.top = null
			nod.next = null
			nod.prev = null

			return nod
		}

		// executes function func on all the tree
		// nodes below (recursively)
		nod.walk = function( do_on_each ) {

			var node = nod.sub.first

			while( node ) {
				do_on_each( node )

				if( node.sub.n > 0 )
					node.walk( do_on_each )

				node = node.next
			}

		}

		return nod
	}

	// namespace for sub operations
	make.sub = function( nod ) {

		var pub = {}

		// the owner node of this
		// "sub" namespace
		pub.nod = nod

		// first and last sub
		pub.first = null
		pub.last = null

		// number of sub nodes
		pub.n = 0

		// get subnode at index position (0 index)
		pub.at = function( index ) {

			var pik,i

			if( index > pub.n - 1 )
				return null

			pik = pub.first
			for( i=0; i<index; i++ )
				pik = pik.next

			return pik
		}

		// add sub node at last position
		// returns the added node
		pub.add = function( sub ) {

			if( pub.last ) {
				sub.prev = pub.last
				pub.last.next = sub
				pub.last = sub
			} else {
				pub.first = sub
				pub.last = sub
			}

			sub.top = pub.nod

			pub.n++
			return sub
		}

		// insert sub node at index position
		// returns the inserted node
		pub.insert = function( sub, index ) {
			var pik

			// validate index given
			if( index < 0 )
				throw "node insert failed, invalid index"
			if( index > pub.n - 1 )
				throw "node insert failed, given index exceeds valid places"

			pik = pub.at( index )

			sub.prev = pik.prev
			sub.next = pik
			pik.prev.next = sub
			pik.prev = sub

			sub.top = pub.nod

			pub.n++

			return sub
		}

		// executes function "func" on each direct
		// sub node (not recursive)
		pub.each = function( do_on_each ) {

			var node = pub.first
			while( node ) {
				do_on_each( node )
				node = node.next
			}

		}

		return pub

	}

	return pub

}()

<commit_msg>fixed method rip on last and first case, added method flat<commit_after>//
// tree.js
//
// tree data structure in javascript
//

var blue = {}

blue.tree = function() {

	var pub = {}

	// creates a new node
	pub.node = function( item ) {

		var nod = make.node( item)
		return nod
	}

	// namespace
	var make = {}

	// create a new node
	make.node = function( item ) {
		// node
		var nod = {}

		// item
		// "payload" of the node
		// assign the provided item property
		nod.item = null
		if( item )
			nod.item = item

		// top node
		nod.top = null

		// prev
		nod.prev = null

		// next
		nod.next = null

		// namespace for sub nodes
		nod.sub = make.sub( nod )

		// removes the node form its tree.
		// returns the node.
		nod.rip = function() {

			console.log('rip: ')
			console.log( nod )

			if( ! nod.top ) return nod

			if( nod.next )
				nod.next.prev = nod.prev
			if( nod.prev )
				nod.prev.next = nod.next

			if( nod.top.sub.last == nod	)
				nod.top.sub.last = nod.prev

			if( nod.top.sub.first == nod )
				nod.top.sub.first = nod.next

			nod.top.sub.n--

			nod.top = null
			nod.next = null
			nod.prev = null

			return nod
		}

		// executes function func on all the tree
		// nodes below (recursively)
		nod.walk = function( do_on_each ) {

			var node = nod.sub.first

			while( node ) {
				do_on_each( node )

				if( node.sub.n > 0 )
					node.walk( do_on_each )

				node = node.next
			}

		}

		// returns an array with references to all nodes in tree
		nod.flat = function() {

			var flat = []

			var grab = function( node ) {
				flat.push( node )
			}
			nod.walk( grab )

			return flat
		}

		return nod
	}

	// namespace for sub operations
	make.sub = function( nod ) {

		var pub = {}

		// the owner node of this
		// "sub" namespace
		pub.nod = nod

		// first and last sub
		pub.first = null
		pub.last = null

		// number of sub nodes
		pub.n = 0

		// get subnode at index position (0 index)
		pub.at = function( index ) {

			var pik,i

			if( index > pub.n - 1 )
				return null

			pik = pub.first
			for( i=0; i<index; i++ )
				pik = pik.next

			return pik
		}

		// add sub node at last position
		// returns the added node
		pub.add = function( sub ) {

			if( pub.last ) {
				sub.prev = pub.last
				pub.last.next = sub
				pub.last = sub
			} else {
				pub.first = sub
				pub.last = sub
			}

			sub.top = pub.nod

			pub.n++
			return sub
		}

		// insert sub node at index position
		// returns the inserted node
		pub.insert = function( sub, index ) {
			var pik

			// validate index given
			if( index < 0 )
				throw "node insert failed, invalid index"
			if( index > pub.n - 1 )
				throw "node insert failed, given index exceeds valid places"

			pik = pub.at( index )

			sub.prev = pik.prev
			sub.next = pik
			pik.prev.next = sub
			pik.prev = sub

			sub.top = pub.nod

			pub.n++

			return sub
		}

		// executes function "func" on each direct
		// sub node (not recursive)
		pub.each = function( do_on_each ) {

			var node = pub.first
			while( node ) {
				do_on_each( node )
				node = node.next
			}

		}

		return pub

	}

	return pub

}()

<|endoftext|>