<commit_before>/*
 * Copyright 2017 Scott Bender <scott@scottbender.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

const debug = require('debug')('signalk:interfaces:appstore')
const _ = require('lodash')
const fs = require('fs')
const compareVersions = require('compare-versions')
const path = require('path')
const installModule = require('../modules').installModule
const findModulesWithKeyword = require('../modules').findModulesWithKeyword
const page = require('../page')

module.exports = function (app) {
  var moduleInstalling = undefined
  var modulesInstalledSinceStartup = {}
  var moduleInstallQueue = []

  return {
    start: function () {
      app.get('/appstore/output/:id/:version', (req, res, next) => {
        let { result, footer } = page(__dirname + '/appstore.html')

        result += '
Errors installing ' + req.params.id + '
'
        result += '
'
        result += modulesInstalledSinceStartup[req.params.id].output
        result += '
'
        result +=
          '<button type="button" class="btn">Retry</button> '
        result += footer
        res.send(result)
      })

      app.get(
        [
          '/appstore/install/:name/:version',
          '/appstore/install/:org/:name/:version'
        ],
        (req, res, next) => {
          var name = req.params.name
          var version = req.params.version

          if (req.params.org) {
            name = req.params.org + '/' + name
          }

          findPluginsAndWebapps()
            .then(([plugins, webapps]) => {
              if (
                !plugins.find(packageNameIs(name)) &&
                !webapps.find(packageNameIs(name))
              ) {
                res.send('No such webapp or plugin available:' + name)
              } else {
                if (moduleInstalling) {
                  moduleInstallQueue.push({ name: name, version: version })
                } else {
                  installSKModule(name, version)
                }
                res.redirect('/appstore')
              }
            })
            .catch(error => {
              console.error(error.message)
              console.error(error.stack)
              res.status(500)
              res.send('
' + error.message + '
')
            })
        }
      )

      app.get('/appstore/available/', (req, res, next) => {
        findPluginsAndWebapps()
          .then(([plugins, webapps]) => {
            var available = []

            getModulesInfo(plugins, getPlugin, available)
            getModulesInfo(webapps, getWebApp, available)

            res.send(JSON.stringify(available.sort(moduleSorter)))
          })
          .catch(error => {
            console.error(error.message)
            console.error(error.stack)
            res.status(500)
            res.send(error.message)
          })
      })

      app.get('/appstore/', (req, res, next) => {
        let { result, footer } = page(__dirname + '/appstore.html')

        findPluginsAndWebapps()
          .then(([plugins, webapps]) => {
            if (Object.keys(modulesInstalledSinceStartup).length) {
              result += '
Server '
              if (
                moduleInstallQueue.length > 0 ||
                moduleInstalling ||
                !app.securityStrategy
              ) {
                result += 'restart'
              } else {
                result += 'restart'
              }
              result +=
                ' is required to finish install or update of plugins and web apps.
\n'
            }

            result += makeSection(
              'Plugins',
              plugins,
              getPlugin,
              '/plugins/configure/#'
            )
            result += makeSection('Web Apps', webapps, getWebApp, '')

            if (moduleInstalling) {
              result +=
                ''
            }

            result += footer
            res.send(result)
          })
          .catch(error => {
            console.error(error.message)
            console.error(error.stack)
            res.status(500)
            res.send('
' + error.message + '
')
          })
      })
    },
    stop: function () {}
  }

  function findPluginsAndWebapps () {
    return Promise.all([
      findModulesWithKeyword('signalk-node-server-plugin'),
      findModulesWithKeyword('signalk-webapp')
    ])
  }

  function getPlugin (id) {
    return app.plugins.find(plugin => plugin.packageName === id)
  }

  function getWebApp (id) {
    return app.webapps.find(webapp => webapp.name === id)
  }

  function moduleSorter (left, right) {
    if (left.name < right.name) {
      return -1
    } else if (left.name > right.name) {
      return 1
    } else {
      return 0
    }
  }

  function getModulesInfo (modules, existing, result) {
    modules.reduce((result, plugin) => {
      var name = plugin.package.name
      var version = plugin.package.version

      console.log(JSON.stringify(plugin))

      var pluginInfo = {
        name: name,
        version: version,
        description: plugin.package.description,
        author: getAuthor(plugin),
        npmUrl: getNpmUrl(plugin)
      }

      var installedModule = existing(name)
      if (installedModule) {
        pluginInfo.installedVersion = installedModule.version
        pluginInfo.hasUpdate =
          compareVersions(version, installedModule.version) > 0
      }

      if (modulesInstalledSinceStartup[name]) {
        if (moduleInstalling && moduleInstalling.name == name) {
          pluginInfo.isInstalling = true
        } else if (modulesInstalledSinceStartup[name].code != 0) {
          pluginInfo.installFauled = true
        }
        pluginInfo.installedSinceStartup = true
      }

      result.push(pluginInfo)

      return result
    }, result)
  }

  function makeSection (title, modules, existing, pathPrefix) {
    modules = modules.sort((left, right) => {
      if (pathPrefix + left.package.name < pathPrefix + right.package.name) {
        return -1
      } else if (
        pathPrefix + left.package.name >
        pathPrefix + right.package.name
      ) {
        return 1
      } else {
        return 0
      }
    })
    return `

${title}

        Install
        Update
        Name
        Description
        Authors
        Link

      ${makeRows(modules, existing, pathPrefix)}

    `
  }

  function makeRows (modules, existing, pathPrefix) {
    return modules.reduce(function (result, moduleInfo) {
      var name = moduleInfo.package.name
      var version = moduleInfo.package.version

      var installedModule = existing(name)
      var isLink = false
      if (installedModule) {
        var stat = fs.lstatSync(
          path.join(__dirname, '../../node_modules/' + name)
        )
        var isLink = stat.isSymbolicLink()
      }

      result += `

          ${getInstallColumn(name, version, installedModule, isLink)}
          ${getUpdateColumn(name, version, installedModule, isLink)}
          ${getNameColumn(name, installedModule, pathPrefix)}
          ${moduleInfo.package.description}
          ${getAuthorColumn(moduleInfo)}
          ${getNpmColumn(moduleInfo)}

      `
      return result
    }, '')
  }

  function getNameColumn (name, installedModule, pathPrefix) {
    return installedModule
      ? `<a href="${pathPrefix}${name}">${name}</a>`
      : `${name}`
  }

  function getAuthorColumn (moduleInfo) {
    debug(moduleInfo.package.name + ' author: ' + moduleInfo.package.author)
    return (
      (moduleInfo.package.author &&
        (moduleInfo.package.author.name || moduleInfo.package.author.email)) +
      '' +
      (moduleInfo.package.contributors || [])
        .map(contributor => contributor.name || contributor.email)
        .join(',') +
      '' +
      (moduleInfo.package.name.startsWith('@signalk/')
        ? ' (Signal K team)'
        : '')
    )
  }

  function getAuthor (moduleInfo) {
    debug(moduleInfo.package.name + ' author: ' + moduleInfo.package.author)
    return (
      (moduleInfo.package.author &&
        (moduleInfo.package.author.name || moduleInfo.package.author.email)) +
      '' +
      (moduleInfo.package.contributors || [])
        .map(contributor => contributor.name || contributor.email)
        .join(',') +
      '' +
      (moduleInfo.package.name.startsWith('@signalk/')
        ? ' (Signal K team)'
        : '')
    )
  }

  function getNpmColumn (moduleInfo) {
    const npm = _.get(moduleInfo.package, 'links.npm')
    return npm ? 'npm' : ''
  }

  function getNpmUrl (moduleInfo) {
    const npm = _.get(moduleInfo.package, 'links.npm')
    return npm || null
  }

  function getInstallColumn (name, version, installedModule, isLink) {
    let result = ''
    if (modulesInstalledSinceStartup[name]) {
      if (moduleInstalling && moduleInstalling.name == name) {
        result += `<p class="text-primary">Installing ${moduleInstalling.version}...</p>`
      } else if (modulesInstalledSinceStartup[name].code == 0) {
        result += `
 Installed ${modulesInstalledSinceStartup[
          name
        ].version}
`
      } else {
        result += `

          <button type="button" class="btn-danger">Error</button>
          `
      }
    } else if (moduleInstallQueue.find(p => p.name == name)) {
      result += '
Waiting...
'
    } else if (!installedModule) {
      result += `<a href="/appstore/install/${name}/${version}"><button type="button" class="btn">Install ${version}</button></a>`
    } else {
      result += `${installedModule.version} Installed`
      if (isLink) {
        result += '
(Linked)' + '
'
      }
    }
    return result
  }

  function getUpdateColumn (name, version, installedModule, isLink) {
    let result = ''
    if (!modulesInstalledSinceStartup[name]) {
      if (installedModule) {
        var compared = compareVersions(version, installedModule.version)
        if (compared > 0) {
          if (!isLink) {
            result += `

            <button type="button" class="btn">Update to ${version}</button>
            `
          } else {
            result += version
          }
        } else if (compared < 0) {
          result += 'Newer Installed'
        } else {
          result += 'Latest Installed'
        }
      }
    }
    return result
  }

  function installSKModule (module, version) {
    moduleInstalling = {
      name: module,
      output: [],
      version: version
    }
    modulesInstalledSinceStartup[module] = moduleInstalling

    installModule(
      module,
      version,
      output => {
        modulesInstalledSinceStartup[module].output.push(output)
        console.log(`stdout: ${output}`)
      },
      output => {
        modulesInstalledSinceStartup[module].output.push(output)
        console.error(`stderr: ${output}`)
      },
      code => {
        debug('close: ' + module)
        modulesInstalledSinceStartup[module]['code'] = code
        moduleInstalling = undefined
        console.log(`child process exited with code ${code}`)

        if (moduleInstallQueue.length) {
          var next = moduleInstallQueue.splice(0, 1)[0]
          installSKModule(next.name, next.version)
        }
      }
    )
  }
}

function packageNameIs (name) {
  return x => x.package.name === name
}
<commit_msg>remove: sorting of apps in the appstore api<commit_after>/*
 * Copyright 2017 Scott Bender <scott@scottbender.net>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0

 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
*/

const debug = require('debug')('signalk:interfaces:appstore')
const _ = require('lodash')
const fs = require('fs')
const compareVersions = require('compare-versions')
const path = require('path')
const installModule = require('../modules').installModule
const findModulesWithKeyword = require('../modules').findModulesWithKeyword
const page = require('../page')

module.exports = function (app) {
  var moduleInstalling = undefined
  var modulesInstalledSinceStartup = {}
  var moduleInstallQueue = []

  return {
    start: function () {
      app.get('/appstore/output/:id/:version', (req, res, next) => {
        let { result, footer } = page(__dirname + '/appstore.html')

        result += '
Errors installing ' + req.params.id + '
'
        result += '
'
        result += modulesInstalledSinceStartup[req.params.id].output
        result += '
'
        result +=
          '<button type="button" class="btn">Retry</button> '
        result += footer
        res.send(result)
      })

      app.get(
        [
          '/appstore/install/:name/:version',
          '/appstore/install/:org/:name/:version'
        ],
        (req, res, next) => {
          var name = req.params.name
          var version = req.params.version

          if (req.params.org) {
            name = req.params.org + '/' + name
          }

          findPluginsAndWebapps()
            .then(([plugins, webapps]) => {
              if (
                !plugins.find(packageNameIs(name)) &&
                !webapps.find(packageNameIs(name))
              ) {
                res.send('No such webapp or plugin available:' + name)
              } else {
                if (moduleInstalling) {
                  moduleInstallQueue.push({ name: name, version: version })
                } else {
                  installSKModule(name, version)
                }
                res.redirect('/appstore')
              }
            })
            .catch(error => {
              console.error(error.message)
              console.error(error.stack)
              res.status(500)
              res.send('
' + error.message + '
')
            })
        }
      )

      app.get('/appstore/available/', (req, res, next) => {
        findPluginsAndWebapps()
          .then(([plugins, webapps]) => {
            var available = []

            getModulesInfo(plugins, getPlugin, available)
            getModulesInfo(webapps, getWebApp, available)

            res.send(JSON.stringify(available))
          })
          .catch(error => {
            console.error(error.message)
            console.error(error.stack)
            res.status(500)
            res.send(error.message)
          })
      })

      app.get('/appstore/', (req, res, next) => {
        let { result, footer } = page(__dirname + '/appstore.html')

        findPluginsAndWebapps()
          .then(([plugins, webapps]) => {
            if (Object.keys(modulesInstalledSinceStartup).length) {
              result += '
Server '
              if (
                moduleInstallQueue.length > 0 ||
                moduleInstalling ||
                !app.securityStrategy
              ) {
                result += 'restart'
              } else {
                result += 'restart'
              }
              result +=
                ' is required to finish install or update of plugins and web apps.
\n'
            }

            result += makeSection(
              'Plugins',
              plugins,
              getPlugin,
              '/plugins/configure/#'
            )
            result += makeSection('Web Apps', webapps, getWebApp, '')

            if (moduleInstalling) {
              result +=
                ''
            }

            result += footer
            res.send(result)
          })
          .catch(error => {
            console.error(error.message)
            console.error(error.stack)
            res.status(500)
            res.send('
' + error.message + '
')
          })
      })
    },
    stop: function () {}
  }

  function findPluginsAndWebapps () {
    return Promise.all([
      findModulesWithKeyword('signalk-node-server-plugin'),
      findModulesWithKeyword('signalk-webapp')
    ])
  }

  function getPlugin (id) {
    return app.plugins.find(plugin => plugin.packageName === id)
  }

  function getWebApp (id) {
    return app.webapps.find(webapp => webapp.name === id)
  }

  function getModulesInfo (modules, existing, result) {
    modules.reduce((result, plugin) => {
      var name = plugin.package.name
      var version = plugin.package.version

      var pluginInfo = {
        name: name,
        version: version,
        description: plugin.package.description,
        author: getAuthor(plugin),
        npmUrl: getNpmUrl(plugin)
      }

      var installedModule = existing(name)
      if (installedModule) {
        pluginInfo.installedVersion = installedModule.version
        pluginInfo.hasUpdate =
          compareVersions(version, installedModule.version) > 0
      }

      if (modulesInstalledSinceStartup[name]) {
        if (moduleInstalling && moduleInstalling.name == name) {
          pluginInfo.isInstalling = true
        } else if (modulesInstalledSinceStartup[name].code != 0) {
          pluginInfo.installFailed = true
        }
        pluginInfo.installedSinceStartup = true
      }

      result.push(pluginInfo)

      return result
    }, result)
  }

  function makeSection (title, modules, existing, pathPrefix) {
    modules = modules.sort((left, right) => {
      if (pathPrefix + left.package.name < pathPrefix + right.package.name) {
        return -1
      } else if (
        pathPrefix + left.package.name >
        pathPrefix + right.package.name
      ) {
        return 1
      } else {
        return 0
      }
    })
    return `

${title}

        Install
        Update
        Name
        Description
        Authors
        Link

      ${makeRows(modules, existing, pathPrefix)}

    `
  }

  function makeRows (modules, existing, pathPrefix) {
    return modules.reduce(function (result, moduleInfo) {
      var name = moduleInfo.package.name
      var version = moduleInfo.package.version

      var installedModule = existing(name)
      var isLink = false
      if (installedModule) {
        var stat = fs.lstatSync(
          path.join(__dirname, '../../node_modules/' + name)
        )
        var isLink = stat.isSymbolicLink()
      }

      result += `

          ${getInstallColumn(name, version, installedModule, isLink)}
          ${getUpdateColumn(name, version, installedModule, isLink)}
          ${getNameColumn(name, installedModule, pathPrefix)}
          ${moduleInfo.package.description}
          ${getAuthorColumn(moduleInfo)}
          ${getNpmColumn(moduleInfo)}

      `
      return result
    }, '')
  }

  function getNameColumn (name, installedModule, pathPrefix) {
    return installedModule
      ? `<a href="${pathPrefix}${name}">${name}</a>`
      : `${name}`
  }

  function getAuthorColumn (moduleInfo) {
    debug(moduleInfo.package.name + ' author: ' + moduleInfo.package.author)
    return (
      (moduleInfo.package.author &&
        (moduleInfo.package.author.name || moduleInfo.package.author.email)) +
      '' +
      (moduleInfo.package.contributors || [])
        .map(contributor => contributor.name || contributor.email)
        .join(',') +
      '' +
      (moduleInfo.package.name.startsWith('@signalk/')
        ? ' (Signal K team)'
        : '')
    )
  }

  function getAuthor (moduleInfo) {
    debug(moduleInfo.package.name + ' author: ' + moduleInfo.package.author)
    return (
      (moduleInfo.package.author &&
        (moduleInfo.package.author.name || moduleInfo.package.author.email)) +
      '' +
      (moduleInfo.package.contributors || [])
        .map(contributor => contributor.name || contributor.email)
        .join(',') +
      '' +
      (moduleInfo.package.name.startsWith('@signalk/')
        ? ' (Signal K team)'
        : '')
    )
  }

  function getNpmColumn (moduleInfo) {
    const npm = _.get(moduleInfo.package, 'links.npm')
    return npm ? 'npm' : ''
  }

  function getNpmUrl (moduleInfo) {
    const npm = _.get(moduleInfo.package, 'links.npm')
    return npm || null
  }

  function getInstallColumn (name, version, installedModule, isLink) {
    let result = ''
    if (modulesInstalledSinceStartup[name]) {
      if (moduleInstalling && moduleInstalling.name == name) {
        result += `<p class="text-primary">Installing ${moduleInstalling.version}...</p>`
      } else if (modulesInstalledSinceStartup[name].code == 0) {
        result += `
 Installed ${modulesInstalledSinceStartup[
          name
        ].version}
`
      } else {
        result += `

          <button type="button" class="btn-danger">Error</button>
          `
      }
    } else if (moduleInstallQueue.find(p => p.name == name)) {
      result += '
Waiting...
'
    } else if (!installedModule) {
      result += `<a href="/appstore/install/${name}/${version}"><button type="button" class="btn">Install ${version}</button></a>`
    } else {
      result += `${installedModule.version} Installed`
      if (isLink) {
        result += '
(Linked)' + '
'
      }
    }
    return result
  }

  function getUpdateColumn (name, version, installedModule, isLink) {
    let result = ''
    if (!modulesInstalledSinceStartup[name]) {
      if (installedModule) {
        var compared = compareVersions(version, installedModule.version)
        if (compared > 0) {
          if (!isLink) {
            result += `

            <button type="button" class="btn">Update to ${version}</button>
            `
          } else {
            result += version
          }
        } else if (compared < 0) {
          result += 'Newer Installed'
        } else {
          result += 'Latest Installed'
        }
      }
    }
    return result
  }

  function installSKModule (module, version) {
    moduleInstalling = {
      name: module,
      output: [],
      version: version
    }
    modulesInstalledSinceStartup[module] = moduleInstalling

    installModule(
      module,
      version,
      output => {
        modulesInstalledSinceStartup[module].output.push(output)
        console.log(`stdout: ${output}`)
      },
      output => {
        modulesInstalledSinceStartup[module].output.push(output)
        console.error(`stderr: ${output}`)
      },
      code => {
        debug('close: ' + module)
        modulesInstalledSinceStartup[module]['code'] = code
        moduleInstalling = undefined
        console.log(`child process exited with code ${code}`)

        if (moduleInstallQueue.length) {
          var next = moduleInstallQueue.splice(0, 1)[0]
          installSKModule(next.name, next.version)
        }
      }
    )
  }
}

function packageNameIs (name) {
  return x => x.package.name === name
}
<|endoftext|>


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

"use strict";

define(function(require, exports, module) {

// Dependencies
const React = require("react");
const { Reps } = require("reps/reps");
const { ObjectBox } = require("reps/object-box");
const { Caption } = require("reps/caption");

// Shortcuts
const { SPAN, A } = Reps.DOM;

/**
 * @rep
 */
var ItemRep = React.createFactory(React.createClass(
/** @lends ItemRep */
{
  displayName: "ItemRep",
  render: function(){
    var object = this.props.object;
    var delim = this.props.delim;
    var REP = Reps.getRep(object);
    return (
      SPAN({},
        REP({object: object}),
        delim
      )
    )
  }
}));

/**
 * @rep
 */
var ArrayRep = React.createClass(
/** @lends ArrayRep */
{
  displayName: "ArrayRep",
  render: function() {
    var mode = this.props.mode || "short";
    var object = this.props.object;
    var hasTwisty = this.hasSpecialProperties(object);

    var items;

    if (mode == "tiny") {
      items = object.length;
    } else {
      // xxxHonza: prefs["ObjectShortIteratorMax"]
      var max = (mode == "short") ? 3 : 300;
      items = this.arrayIterator(object, max);
    }

    return (
      ObjectBox({className: "array", onClick: this.onToggleProperties},
        A({className: "objectLink", onclick: this.onClickBracket},
          SPAN({className: "arrayLeftBracket", role: "presentation"}, "[")
        ),
        items,
        A({className: "objectLink", onclick: this.onClickBracket},
          SPAN({className: "arrayRightBracket", role: "presentation"}, "]")
        ),
        SPAN({className: "arrayProperties", role: "group"})
      )
    )
  },

  getTitle: function(object, context) {
    return "[" + object.length + "]";
  },

  arrayIterator: function(array, max) {
    var items = [];

    for (var i=0; i<array.length && i<=max; i++) {
      try {
        var delim = (i == array.length-1 ? "" : ", ");
        var value = array[i];

        // Cycle detected
        //if (value === array) {
        //  value = new Reps.ReferenceObj(value);
        //}

        items.push(ItemRep({
          key: i,
          object: value,
          delim: delim
        }));
      }
      catch (exc) {
        items.push(ItemRep({object: exc, delim: delim, key: i}));
      }
    }

    if (array.length > max + 1) {
      items.pop();
      items.push(Caption({
        key: "more",
        object: Locale.$STR("reps.more"),
      }));
    }

    return items;
  },

  /**
   * Returns true if the passed object is an array with additional (custom)
   * properties, otherwise returns false. Custom properties should be
   * displayed in extra expandable section.
   *
   * Example array with a custom property.
   * let arr = [0, 1];
   * arr.myProp = "Hello";
   *
   * @param {Array} array The array object.
   */
  hasSpecialProperties: function(array) {
    function isInteger(x) {
      var y = parseInt(x, 10);
      if (isNaN(y)) {
        return false;
      }
      return x === y.toString();
    }

    var n = 0;
    var props = Object.getOwnPropertyNames(array);
    for (var i=0; i<props.length; i++) {
      var p = props[i];

      // Valid indexes are skipped
      if (isInteger(p)) {
        continue;
      }

      // Ignore standard 'length' property, anything else is custom.
      if (p != "length") {
        return true;
      }
    }

    return false;
  },

  // Event Handlers

  onToggleProperties: function(event) {
    // xxxHonza: TODO
  },

  onClickBracket: function(event) {
  }
});

// Registration

function supportsObject(object, type) {
  return Array.isArray(object) ||
    Object.prototype.toString.call(object) === "[object Arguments]";
}

Reps.registerRep({
  rep: React.createFactory(ArrayRep),
  supportsObject: supportsObject
});

exports.ArrayRep = React.createFactory(ArrayRep);
});
<commit_msg>Make Array rep an extensible base class<commit_after>/* See license.txt for terms of usage */

"use strict";

define(function(require, exports, module) {

// Dependencies
const React = require("react");
const { Reps } = require("reps/reps");
const { ObjectBox } = require("reps/object-box");
const { Caption } = require("reps/caption");

// Shortcuts
const { SPAN, A } = Reps.DOM;

/**
 * @rep
 */
var ArrayRep =
/** @lends ArrayRep */
{
  displayName: "ArrayRep",

  render: function() {
    var mode = this.props.mode || "short";
    var object = this.props.object;
    var hasTwisty = this.hasSpecialProperties(object);

    var items;

    if (mode == "tiny") {
      items = this.getLength(object);
    } else {
      // xxxHonza: prefs["ObjectShortIteratorMax"]
      var max = (mode == "short") ? 3 : 300;
      items = this.getItems(object, max);
    }

    return (
      ObjectBox({className: "array", onClick: this.onToggleProperties},
        A({className: "objectLink", onclick: this.onClickBracket},
          SPAN({className: "arrayLeftBracket", role: "presentation"}, "[")
        ),
        items,
        A({className: "objectLink", onclick: this.onClickBracket},
          SPAN({className: "arrayRightBracket", role: "presentation"}, "]")
        ),
        SPAN({className: "arrayProperties", role: "group"})
      )
    )
  },

  getLength: function(object) {
    return object.length;
  },

  getTitle: function(object) {
    return "[" + object.length + "]";
  },

  getItems: function(array, max) {
    var items = this.arrayIterator(array, max);

    items = items.map(item => ItemRep(item));

    if (array.length > max + 1) {
      items.pop();
      items.push(Caption({
        key: "more",
        object: Locale.$STR("reps.more"),
      }));
    }

    return items;
  },

  arrayIterator: function(array, max) {
    var items = [];

    for (var i=0; i<array.length && i<=max; i++) {
      try {
        var delim = (i == array.length-1 ? "" : ", ");
        var value = array[i];

        // Cycle detected
        //if (value === array) {
        //  value = new Reps.ReferenceObj(value);
        //}

        items.push({
          key: i,
          object: value,
          delim: delim
        });
      }
      catch (exc) {
        items.push({object: exc, delim: delim, key: i});
      }
    }

    return items;
  },

  /**
   * Returns true if the passed object is an array with additional (custom)
   * properties, otherwise returns false. Custom properties should be
   * displayed in extra expandable section.
   *
   * Example array with a custom property.
   * let arr = [0, 1];
   * arr.myProp = "Hello";
   *
   * @param {Array} array The array object.
   */
  hasSpecialProperties: function(array) {
    function isInteger(x) {
      var y = parseInt(x, 10);
      if (isNaN(y)) {
        return false;
      }
      return x === y.toString();
    }

    var n = 0;
    var props = Object.getOwnPropertyNames(array);
    for (var i=0; i<props.length; i++) {
      var p = props[i];

      // Valid indexes are skipped
      if (isInteger(p)) {
        continue;
      }

      // Ignore standard 'length' property, anything else is custom.
      if (p != "length") {
        return true;
      }
    }

    return false;
  },

  // Event Handlers

  onToggleProperties: function(event) {
    // xxxHonza: TODO
  },

  onClickBracket: function(event) {
  }
};

/**
 * @rep
 */
var ItemRep = React.createFactory(React.createClass(
/** @lends ItemRep */
{
  displayName: "ItemRep",

  render: function(){
    var object = this.props.object;
    var delim = this.props.delim;
    var TAG = Reps.getRep(object);
    return (
      SPAN({},
        TAG({object: object}),
        delim
      )
    )
  }
}));

// Registration

var ArrayClass = React.createClass(ArrayRep);

function supportsObject(object, type) {
  return Array.isArray(object) ||
    Object.prototype.toString.call(object) === "[object Arguments]";
}

Reps.registerRep({
  rep: React.createFactory(ArrayClass),
  supportsObject: supportsObject
});

exports.ArrayRep = React.createFactory(ArrayClass);
exports.ArrayComponent = ArrayRep;
});
<|endoftext|>


<commit_before>'use strict';

import style from '../element/style';
import css from '../module/css';

export default {

  /**
   * Instanciate the given object comp
   * @param  {Object} comp list component
   * @return {component}
   */
  _initComponent(options) {
    //console.log('_initComponent', options.name, options);
    options = options || {};

    // shortcuts
    // options.flex = options.flex || comp.flex;
    // options.hide = options.hide || comp.hide;
    // options.theme = options.theme || comp.theme;

    var name = options.name || 'main';

    //options.container = comp.container;
    var component = this.component[name] = new options.component(options);

    this.components.push(component);

    // register component
    this._componentRegister(name, component);

    //settings
    //this._initComponentSettings(component);

    // style, size and event
    this._setComponentStyles(component);
    this._setComponentDisplay(component);

    return component;
  },

  /**
   * [_componentRegister description]
   * @param  {string} name      [description]
   * @param  {component} component [description]
   */
  _componentRegister(name, component) {
    //console.log('_componentRegister', name, component.class);
    this.components = this.components || [];
    this.components.push(component);
    var className = component.class;

    this.controls = this.controls || [];

    var controls = this.options.controls;

    if (controls && controls.indexOf(className) >= 0) {
      this.controls.push(component);
    }
  },

  /**
   * [_initComponentSettings description]
   * @param  {component} component [description]
   */
  // _initComponentSettings(component) {
  //
  //  var name = component.getName();
  //  var element = component.wrapper;
  // },

  /**
   * [_initComponentSettings description]
   * @param  {component} component [description]
   */
  _setComponentStyles(component) {

    if (component.options.flex) {
      css.add(component.wrapper, 'flex-' + component.options.flex);
    } else {

      //console.log('not flex', component.options.name, component.options);

      if (component.options.size && component.options.width) {
        var size = component.options.size;
        if (this.settings &&
          this.settings.layout &&
          this.settings.layout.section &&
          this.settings.layout.section[component.name] &&
          this.settings.layout.section[component.name].width) {

          size = this.settings.layout.section[component.name].width;

          style.set(component.wrapper, {
            'width': size + 'px'
          });
        }
      } else {
        var wrapper = component.wrapper || component.wrapper || null;
        style.set(wrapper, {
          height: component.options.size + 'px'
        });
      }
    }

    if (component.options.hide) {
      style.set(component.wrapper, {
        display: 'none'
      });
    }

    if (component.options.theme) {
      css.add(component.wrapper, 'theme' + '-' + component.options.theme);
    }
  },

  /**
   * [_initSize description]
   * @param  {component} component [description]
   */
  _setComponentDisplay(component) {
    var display = 'normalized';

    // var name = component.getName();
    // if (this.settings[name] && this.settings[name].display) {
    //  display = this.settings[name].display;
    // }

    if (!component.setDisplay) return;
    component.setDisplay(display, 'width');

    if (component.options.flex) return;

    this.emit('drag');

    this._attachComponentEvents(component);
  },

  /**
   * _setComponentSettings description
   * @param {Object} component Component object
   */
  // _setComponentSettings(component) {
  //  var display = 'normalized';

  //  var name = component.getName();
  //  var element = component.wrapper;

  //  if (component.options.flex) {

  //    if (this.settings[name] && this.settings[name].width) {
  //      //style('flex', 'none');
  //      element.addClass('flex-none');
  //      if (display === 'minimized') {

  //        style('width', 0);
  //      } else {

  //        if (this.settings[name].width < 32)
  //          this.settings[name].width = 32;

  //        element.style('width', this.settings[name].width || 160);
  //      }

  //      component.width = this.settings[name].width || 200;
  //      component._modifier = 'width';
  //    } else if (this.settings[name] && this.settings[name].height) {
  //      element.style('flex', 'none');
  //      element.style('height', this.settings[name].height);
  //      component.height = this.settings[name].height || 160;
  //      component._modifier = 'height';
  //    }
  //  }
  // },

  /**
   * [_attachComponentEvents description]
   * @param  {component} component [description]
   */
  _attachComponentEvents(component) {
    var name = component.name || component.options.name;

    if (!component.on) {
      console.log('missing on', component.class, component.name);
      return;
    }

    if (!this.on) {
      console.log('this missong on', component.class, component.name);
      return;
    }
  }
};<commit_msg>remove the shortcuts<commit_after>'use strict';

import style from '../element/style';
import css from '../module/css';

export default {

  /**
   * Instanciate the given object comp
   * @param  {Object} comp list component
   * @return {component}
   */
  _initComponent(options) {
    //console.log('_initComponent', options.name, options);
    options = options || {};

    var name = options.name || 'main';

    //options.container = comp.container;
    var component = this.component[name] = new options.component(options);

    this.components.push(component);

    // register component
    this._componentRegister(name, component);

    //settings
    //this._initComponentSettings(component);

    // style, size and event
    this._setComponentStyles(component);
    this._setComponentDisplay(component);

    return component;
  },

  /**
   * [_componentRegister description]
   * @param  {string} name      [description]
   * @param  {component} component [description]
   */
  _componentRegister(name, component) {
    //console.log('_componentRegister', name, component.class);
    this.components = this.components || [];
    this.components.push(component);
    var className = component.class;

    this.controls = this.controls || [];

    var controls = this.options.controls;

    if (controls && controls.indexOf(className) >= 0) {
      this.controls.push(component);
    }
  },

  /**
   * [_initComponentSettings description]
   * @param  {component} component [description]
   */
  // _initComponentSettings(component) {
  //
  //  var name = component.getName();
  //  var element = component.wrapper;
  // },

  /**
   * [_initComponentSettings description]
   * @param  {component} component [description]
   */
  _setComponentStyles(component) {

    if (component.options.flex) {
      css.add(component.wrapper, 'flex-' + component.options.flex);
    } else {
      var size = component.options.size;
      if (component.options.size && component.options.width) {
        style.set(component.wrapper, {
          width: size + 'px'
        });
      } else {
        style.set(component.wrapper, {
          height: size + 'px'
        });
      }
    }

    if (component.options.hide) {
      style.set(component.wrapper, {
        display: 'none'
      });
    }

    if (component.options.theme) {
      css.add(component.wrapper, 'theme' + '-' + component.options.theme);
    }
  },

  /**
   * [_initSize description]
   * @param  {component} component [description]
   */
  _setComponentDisplay(component) {
    var display = 'normalized';

    // var name = component.getName();
    // if (this.settings[name] && this.settings[name].display) {
    //  display = this.settings[name].display;
    // }

    if (!component.setDisplay) return;
    component.setDisplay(display, 'width');

    if (component.options.flex) return;

    this.emit('drag');

    this._attachComponentEvents(component);
  },

  /**
   * _setComponentSettings description
   * @param {Object} component Component object
   */
  // _setComponentSettings(component) {
  //  var display = 'normalized';

  //  var name = component.getName();
  //  var element = component.wrapper;

  //  if (component.options.flex) {

  //    if (this.settings[name] && this.settings[name].width) {
  //      //style('flex', 'none');
  //      element.addClass('flex-none');
  //      if (display === 'minimized') {

  //        style('width', 0);
  //      } else {

  //        if (this.settings[name].width < 32)
  //          this.settings[name].width = 32;

  //        element.style('width', this.settings[name].width || 160);
  //      }

  //      component.width = this.settings[name].width || 200;
  //      component._modifier = 'width';
  //    } else if (this.settings[name] && this.settings[name].height) {
  //      element.style('flex', 'none');
  //      element.style('height', this.settings[name].height);
  //      component.height = this.settings[name].height || 160;
  //      component._modifier = 'height';
  //    }
  //  }
  // },

};<|endoftext|>


<commit_before>/**
 * Simple interface for request modification in Firefox. Use with care, as it
 * can slow down requests drastically, since the handler is ran sync and blocks
 * the request from getting sent/received. And you can in theory look at all the
 * user's traffic.
 *
 * It's generally advised to try an alternative method from
 * {@link https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Intercepting_Page_Loads|MDN: Intercept Page Loads}
 * instead. This implementation covers the "HTTP Observers" part.
 *
 * @author Martin Giger
 * @license MPL-2.0
 * @module requestmod
 * @borrows module:lib/const.INCOMING as INCOMING
 * @borrows module:lib/const.OUTGOING as OUTGOING
 */

"use strict";

const { Class } = require("sdk/core/heritage");
const { Disposable } = require("sdk/core/disposable");
const events = require("sdk/system/events");
const { Ci } = require("chrome");
const { OngoingRequest } = require("./ongoingrequest");
const { Rules } = require("sdk/util/rules");
const { contract } = require("sdk/util/contract");
const { isRegExp } = require("sdk/lang/type");
const { INCOMING, OUTGOING } = require("./const");

const INCOMING_OBSERVER = "http-on-examine-response";
const OUTGOING_OBSERVER = "http-on-modify-request";

const models = new WeakMap();

const modelFor = (rm) => models.get(rm);

// Modified contract from pagemod.
const isRegExpOrString = (v) => isRegExp(v) || typeof v === 'string';
const isDirection = (v) => v === INCOMING || v === OUTGOING;

const modContract = contract({
    url: {
        is: ['string', 'array', 'regexp'],
        ok: (rule) => {
            if (isRegExpOrString(rule))
                return true;
            if (Array.isArray(rule) && rule.length > 0)
                return rule.every(isRegExpOrString);
            return false;
        },
        msg: 'The `url` option must always contain atleast one rule as a string, regular expression, or an array of strings and regular expressions.'
    },
    direction: {
        is: ['array'],
        ok: (direction) => Array.isArray(direction) && direction.length > 0 && direction.every(isDirection),
        msg: 'The `direction` option must always be an array with at least one item and each item must have the value of a direction constant.'
    },
    requestHandler: {
        is: ['function'],
        msg: 'The `requestHandler` option must alwys be a function.'
    }
});

let RequestMod = Class(
/** @lends module:requestmod.RequestMod.prototype */
{
    implements: [
        Disposable,
        modContract.properties(modelFor)
    ],
    /**
     * Must execute actions on the {@link module:lib/ongoingrequest.OngoingRequest|OngoingRequest} object synchronously.
     * @callback requestCallback
     * @argument {module:lib/ongoingrequest.OngoingRequest} request
     */
    /**
     * @typedef {Object} RequestModOptions
     * @property {Array.<(module:requestmod.INCOMING|module:requestmod.OUTGOING)>} direction - The request
     * directions that should be listened for
     * @property {(Array.<(string|RegExp)>|RegExp|string)} url - An url pattern
     * string with '*' wildcards
     * (see {@link https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/util_match-pattern|MDN: SDK match-pattern module}
     * for detailed documentation on the syntax) or a regular expression or an array of such
     * elements.
     * @property {module:requestmod~requestCallback} requestHandler
     */
    /**
     * @constructs
     * @extends external:sdk/core/disposable.Dispose
     * @argument {module:requestmod~RequestModOptions} options
     * @alias module:requestmod.RequestMod
     */
    setup: function(options) {
        let model = modContract(options);
        models.set(this, model);

        model.url = Rules();
        model.url.add(options.url);

        this.observe = this.observe.bind(this);
        if(model.direction.indexOf(INCOMING) != -1) {
            events.on(INCOMING_OBSERVER, this.observe);
        }
        if(model.direction.indexOf(OUTGOING) != -1) {
            events.on(OUTGOING_OBSERVER, this.observe);
        }
    },
    observe: function({type, subject, data}) {
        const direction = type === INCOMING_OBSERVER ? INCOMING : OUTGOING;
        let model = modelFor(this);

        // Make sure we've got an HttpChannel
        subject.QueryInterface(Ci.nsIHttpChannel);
        let uri = subject.URI.spec;
        // Check if the request passes the url mask
        if(model.url.matchesAny(uri)) {
            // create ongoing request
            let oreq = OngoingRequest({
                direction: direction,
                channel: subject
            });
            // send ongoing request to listener and execute it
            model.requestHandler(oreq);
            // delete ongoing request (the beauty of synchronous execution)
            oreq.destroy();
        }
    },

    dispose: function() {
        let model = modelFor(this);
        if(model.direction.indexOf(INCOMING) != -1) {
            events.off(INCOMING_OBSERVER, this.observe);
        }
        if(model.direction.indexOf(OUTGOING) != -1) {
            events.off(OUTGOING_OBSERVER, this.observe);
        }

        for(let i in model.url) {
            model.url.remove(model.url[i]);
        }

        models.delete(this);
    },
    set url(val) {
        let model = modelFor(this);
        for(let i in model.url) {
            model.url.remove(model.url[i]);
        }
        model.url.add(val);
    }
});

RequestMod.INCOMING = INCOMING;
RequestMod.OUTGOING = OUTGOING;

exports.RequestMod = RequestMod;
<commit_msg>Fix requestmod extends<commit_after>/**
 * Simple interface for request modification in Firefox. Use with care, as it
 * can slow down requests drastically, since the handler is ran sync and blocks
 * the request from getting sent/received. And you can in theory look at all the
 * user's traffic.
 *
 * It's generally advised to try an alternative method from
 * {@link https://developer.mozilla.org/en-US/Add-ons/Overlay_Extensions/XUL_School/Intercepting_Page_Loads|MDN: Intercept Page Loads}
 * instead. This implementation covers the "HTTP Observers" part.
 *
 * @author Martin Giger
 * @license MPL-2.0
 * @module requestmod
 * @borrows module:lib/const.INCOMING as INCOMING
 * @borrows module:lib/const.OUTGOING as OUTGOING
 */

"use strict";

const { Class } = require("sdk/core/heritage");
const { Disposable } = require("sdk/core/disposable");
const events = require("sdk/system/events");
const { Ci } = require("chrome");
const { OngoingRequest } = require("./ongoingrequest");
const { Rules } = require("sdk/util/rules");
const { contract } = require("sdk/util/contract");
const { isRegExp } = require("sdk/lang/type");
const { INCOMING, OUTGOING } = require("./const");

const INCOMING_OBSERVER = "http-on-examine-response";
const OUTGOING_OBSERVER = "http-on-modify-request";

const models = new WeakMap();

const modelFor = (rm) => models.get(rm);

// Modified contract from pagemod.
const isRegExpOrString = (v) => isRegExp(v) || typeof v === 'string';
const isDirection = (v) => v === INCOMING || v === OUTGOING;

const modContract = contract({
    url: {
        is: ['string', 'array', 'regexp'],
        ok: (rule) => {
            if (isRegExpOrString(rule))
                return true;
            if (Array.isArray(rule) && rule.length > 0)
                return rule.every(isRegExpOrString);
            return false;
        },
        msg: 'The `url` option must always contain atleast one rule as a string, regular expression, or an array of strings and regular expressions.'
    },
    direction: {
        is: ['array'],
        ok: (direction) => Array.isArray(direction) && direction.length > 0 && direction.every(isDirection),
        msg: 'The `direction` option must always be an array with at least one item and each item must have the value of a direction constant.'
    },
    requestHandler: {
        is: ['function'],
        msg: 'The `requestHandler` option must alwys be a function.'
    }
});

let RequestMod = Class(
/** @lends module:requestmod.RequestMod.prototype */
{
    implements: [
        Disposable,
        modContract.properties(modelFor)
    ],
    /**
     * Must execute actions on the {@link module:lib/ongoingrequest.OngoingRequest|OngoingRequest} object synchronously.
     * @callback requestCallback
     * @argument {module:lib/ongoingrequest.OngoingRequest} request
     */
    /**
     * @typedef {Object} RequestModOptions
     * @property {Array.<(module:requestmod.INCOMING|module:requestmod.OUTGOING)>} direction - The request
     * directions that should be listened for
     * @property {(Array.<(string|RegExp)>|RegExp|string)} url - An url pattern
     * string with '*' wildcards
     * (see {@link https://developer.mozilla.org/en-US/Add-ons/SDK/Low-Level_APIs/util_match-pattern|MDN: SDK match-pattern module}
     * for detailed documentation on the syntax) or a regular expression or an array of such
     * elements.
     * @property {module:requestmod~requestCallback} requestHandler
     */
    /**
     * @constructs
     * @extends external:sdk/core/disposable.Disposable
     * @argument {module:requestmod~RequestModOptions} options
     * @alias module:requestmod.RequestMod
     */
    setup: function(options) {
        let model = modContract(options);
        models.set(this, model);

        model.url = Rules();
        model.url.add(options.url);

        this.observe = this.observe.bind(this);
        if(model.direction.indexOf(INCOMING) != -1) {
            events.on(INCOMING_OBSERVER, this.observe);
        }
        if(model.direction.indexOf(OUTGOING) != -1) {
            events.on(OUTGOING_OBSERVER, this.observe);
        }
    },
    observe: function({type, subject, data}) {
        const direction = type === INCOMING_OBSERVER ? INCOMING : OUTGOING;
        let model = modelFor(this);

        // Make sure we've got an HttpChannel
        subject.QueryInterface(Ci.nsIHttpChannel);
        let uri = subject.URI.spec;
        // Check if the request passes the url mask
        if(model.url.matchesAny(uri)) {
            // create ongoing request
            let oreq = OngoingRequest({
                direction: direction,
                channel: subject
            });
            // send ongoing request to listener and execute it
            model.requestHandler(oreq);
            // delete ongoing request (the beauty of synchronous execution)
            oreq.destroy();
        }
    },

    dispose: function() {
        let model = modelFor(this);
        if(model.direction.indexOf(INCOMING) != -1) {
            events.off(INCOMING_OBSERVER, this.observe);
        }
        if(model.direction.indexOf(OUTGOING) != -1) {
            events.off(OUTGOING_OBSERVER, this.observe);
        }

        for(let i in model.url) {
            model.url.remove(model.url[i]);
        }

        models.delete(this);
    },
    set url(val) {
        let model = modelFor(this);
        for(let i in model.url) {
            model.url.remove(model.url[i]);
        }
        model.url.add(val);
    }
});

RequestMod.INCOMING = INCOMING;
RequestMod.OUTGOING = OUTGOING;

exports.RequestMod = RequestMod;
<|endoftext|>


<commit_before>L.UGeoJSONLayer = L.GeoJSON.extend({
    options: {
      debug: false,
      light: true,
      usebbox: false,
      endpoint: "-1",
      parameters: {},
      headers: {},
      maxRequests: 5,
      pollTime:0,
      once: false,
      enctype: "form-data", //urlencoded || form-data || json
      afterFetch: function() {},
      after: function(data){}
    },

    callback: function(data) {
      if(this.options.light)
      {
        this.clearLayers();//if needed, we clean the layers
      }

      //Then we add the new data
      this.addData(data);
      this.options.after(data);
    },

  initialize: function (uOptions, options) {
    L.GeoJSON.prototype.initialize.call(this, undefined, options);
    L.Util.setOptions(this, uOptions);

    this._layersOld = [];
    this._requests = [];
  },

  onMoveEnd: function () {
    if (this.options.debug) {
      console.debug("load Data");
    }

    while(this._requests.length > this.options.maxRequests) //This allows to stop the oldest requests
    {
      this._requests.shift().abort();
    }

    var postData = {};
    if (typeof this.options.parameters === 'function') {
      postData = this.options.parameters();
    } else {
      for(var k in this.options.parameters)
      {
        if(this.options.parameters[k].scope != undefined)
        {
	  postData[k]=this.options.parameters[k].scope[k];
        }
        else
        {
	  postData[k]=this.options.parameters[k];
        }
      }
    }

    var bounds = this._map.getBounds();

    if ( this.options.usebbox ) {
      postData.bbox = bounds.toBBoxString();
    } else {
      postData.south = bounds.getSouth();
      postData.north = bounds.getNorth();
      postData.east = bounds.getEast();
      postData.west = bounds.getWest();
    }
    postData.zoom = this._map.getZoom();

    var self = this;
    var request = new XMLHttpRequest();
    request.open("POST", this.options.endpoint, true);
    for(var k in this.options.headers)
    {
      if(this.options.headers[k].scope != undefined)
      {
        request.setRequestHeader(k,this.options.headers[k].scope[k]);
      }
      else
      {
        request.setRequestHeader(k,this.options.headers[k]);
      }
    }

    request.onload = function() {
      for(var i in self._requests)
      {
        if(self._requests[i] === request)
        {
          self._requests.splice(i,1); //We remove the request from the list of currently running requests.
          break;
        }
      }

      if (this.status >= 200 && this.status < 400) {
        self.options.afterFetch();
        self.callback(JSON.parse(this.responseText));
      }
    };

    this._requests.push(request);

  if(this.options.enctype=="urlencoded" || this.options.enctype=="json"){
    if(this.options.enctype=="urlencoded") {
      // urlencoded request
      var urlencoded="";
      for(var p in postData){
        if(urlencoded.length>0) urlencoded+="&";
        urlencoded+=encodeURIComponent(p)+"="+encodeURIComponent(postData[p]);
      }
      request.send(urlencoded);
    } else{
      // json request
      request.send(JSON.stringify(postData));
    }

  } else {
    var postFormData = new FormData();
    for (var p in postData){
      postFormData.append(p, postData[p]);
    }
    request.send(postFormData);
  }

  },

  onAdd: function (map) {
    this._map = map;

    if (this.options.endpoint != undefined && this.options.endpoint != "-1") {
		  this.onMoveEnd();

      if(!this.options.once) {
        map.on('dragend', this.onMoveEnd, this);
        map.on('zoomend', this.onMoveEnd, this);
        map.on("refresh", this.onMoveEnd, this);

        if (this.options.pollTime > 0) {
          this.intervalID = window.setInterval(this.onMoveEnd.bind(this), this.options.pollTime);
        }
      }
    }

    if (this.options.debug) {
      console.debug("add layer");
    }
  },

  onRemove: function (map) {
    if (this.options.debug) {
      console.debug("remove layer");
    }
    L.LayerGroup.prototype.onRemove.call(this, map);

    if (!this.options.once && this.options.pollTime > 0) {
      window.clearInterval(this.intervalID);
    }

    while(this._requests.length > 0)
    {
      this._requests.shift().abort();
    }

    if(!this.options.once) {
      map.off({
        'dragend': this.onMoveEnd
      }, this);
      map.off({
        'zoomend': this.onMoveEnd
      }, this);
        map.off({
        'refresh': this.onMoveEnd
      }, this);
    }

    this._map = null;
  }

});

L.uGeoJSONLayer = function (uOptions, options) {
  return new L.UGeoJSONLayer(uOptions, options);
};
<commit_msg>Add transformData feature<commit_after>L.UGeoJSONLayer = L.GeoJSON.extend({
    options: {
      debug: false,
      light: true,
      usebbox: false,
      endpoint: "-1",
      parameters: {},
      headers: {},
      maxRequests: 5,
      pollTime:0,
      once: false,
      enctype: "form-data", //urlencoded || form-data || json
      transformData: function(data) {},
      afterFetch: function() {},
      after: function(data){}
    },

    callback: function(data) {
      if(this.options.light)
      {
        this.clearLayers();//if needed, we clean the layers
      }

      //Then we add the new data
      this.addData(data);
      this.options.after(data);
    },

  initialize: function (uOptions, options) {
    L.GeoJSON.prototype.initialize.call(this, undefined, options);
    L.Util.setOptions(this, uOptions);

    this._layersOld = [];
    this._requests = [];
  },

  onMoveEnd: function () {
    if (this.options.debug) {
      console.debug("load Data");
    }

    while(this._requests.length > this.options.maxRequests) //This allows to stop the oldest requests
    {
      this._requests.shift().abort();
    }

    var postData = {};
    if (typeof this.options.parameters === 'function') {
      postData = this.options.parameters();
    } else {
      for(var k in this.options.parameters)
      {
        if(this.options.parameters[k].scope != undefined)
        {
	  postData[k]=this.options.parameters[k].scope[k];
        }
        else
        {
	  postData[k]=this.options.parameters[k];
        }
      }
    }

    var bounds = this._map.getBounds();

    if ( this.options.usebbox ) {
      postData.bbox = bounds.toBBoxString();
    } else {
      postData.south = bounds.getSouth();
      postData.north = bounds.getNorth();
      postData.east = bounds.getEast();
      postData.west = bounds.getWest();
    }
    postData.zoom = this._map.getZoom();

    var self = this;
    var request = new XMLHttpRequest();
    request.open("POST", this.options.endpoint, true);
    for(var k in this.options.headers)
    {
      if(this.options.headers[k].scope != undefined)
      {
        request.setRequestHeader(k,this.options.headers[k].scope[k]);
      }
      else
      {
        request.setRequestHeader(k,this.options.headers[k]);
      }
    }

    request.onload = function() {
      for(var i in self._requests)
      {
        if(self._requests[i] === request)
        {
          self._requests.splice(i,1); //We remove the request from the list of currently running requests.
          break;
        }
      }

      if (this.status >= 200 && this.status < 400) {
        var data = JSON.parse(this.responseText);

        if (self.options.transformData) {
          data = self.options.transformData(data);
        }

        self.options.afterFetch();
        self.callback(data);
      }
    };

    this._requests.push(request);

  if(this.options.enctype=="urlencoded" || this.options.enctype=="json"){
    if(this.options.enctype=="urlencoded") {
      // urlencoded request
      var urlencoded="";
      for(var p in postData){
        if(urlencoded.length>0) urlencoded+="&";
        urlencoded+=encodeURIComponent(p)+"="+encodeURIComponent(postData[p]);
      }
      request.send(urlencoded);
    } else{
      // json request
      request.send(JSON.stringify(postData));
    }

  } else {
    var postFormData = new FormData();
    for (var p in postData){
      postFormData.append(p, postData[p]);
    }
    request.send(postFormData);
  }

  },

  onAdd: function (map) {
    this._map = map;

    if (this.options.endpoint != undefined && this.options.endpoint != "-1") {
		  this.onMoveEnd();

      if(!this.options.once) {
        map.on('dragend', this.onMoveEnd, this);
        map.on('zoomend', this.onMoveEnd, this);
        map.on("refresh", this.onMoveEnd, this);

        if (this.options.pollTime > 0) {
          this.intervalID = window.setInterval(this.onMoveEnd.bind(this), this.options.pollTime);
        }
      }
    }

    if (this.options.debug) {
      console.debug("add layer");
    }
  },

  onRemove: function (map) {
    if (this.options.debug) {
      console.debug("remove layer");
    }
    L.LayerGroup.prototype.onRemove.call(this, map);

    if (!this.options.once && this.options.pollTime > 0) {
      window.clearInterval(this.intervalID);
    }

    while(this._requests.length > 0)
    {
      this._requests.shift().abort();
    }

    if(!this.options.once) {
      map.off({
        'dragend': this.onMoveEnd
      }, this);
      map.off({
        'zoomend': this.onMoveEnd
      }, this);
        map.off({
        'refresh': this.onMoveEnd
      }, this);
    }

    this._map = null;
  }

});

L.uGeoJSONLayer = function (uOptions, options) {
  return new L.UGeoJSONLayer(uOptions, options);
};
<|endoftext|>


<commit_before>'use strict';

// ---------------------------------------------------------------------------

const foxbit = require ('./foxbit.js');

// ---------------------------------------------------------------------------

module.exports = class chilebit extends foxbit {
    describe () {
        return this.deepExtend (super.describe (), {
            'id': 'chilebit',
            'name': 'ChileBit',
            'countries': [ 'CL' ],
            'has': {
                'CORS': false,
            },
            'urls': {
                'logo': 'https://user-images.githubusercontent.com/1294454/27991414-1298f0d8-647f-11e7-9c40-d56409266336.jpg',
                'api': {
                    'public': 'https://api.blinktrade.com/api',
                    'private': 'https://api.blinktrade.com/tapi',
                },
                'www': 'https://chilebit.net',
                'doc': 'https://blinktrade.com/docs',
            },
            'options': {
                'brokerId': '9', // https://blinktrade.com/docs/#brokers
            },
        });
    }
};
<commit_msg>delist chilebit<commit_after><|endoftext|>


<commit_before>/**
 * This module defines a custom jsDoc tag.
 * It allows you to document route parameters of a route.
 * @module lib/routeparam
 */

'use strict'

const tableBuilder = require('./parameterTableBuilder')

exports.name = 'params'
exports.options = {
  mustHaveValue: true,
  mustNotHaveDescription: false,
  canHaveType: true,
  canHaveName: true,
  onTagged: function (doclet, tag) {
    if (!doclet.params) {
      doclet.params = []
    }

    doclet.params.push({
      'name': tag.value.name,
      'type': tag.value.type ? (tag.value.type.names.length === 1 ? tag.value.type.names[0] : tag.value.type.names) : '',
      'description': tag.value.description || ''
    })
  }
}
exports.newDocletHandler = function (e) {
  if (e.doclet.kind !== "member")
    return;

  const parameters = e.doclet.params
  if (parameters) {
    const table = tableBuilder.build('Route Parameters', parameters)

    e.doclet.description = `${e.doclet.description || ''}
                            ${table}`
  }
}
<commit_msg>this is a better fix, instead of precedent commit<commit_after>/**
 * This module defines a custom jsDoc tag.
 * It allows you to document route parameters of a route.
 * @module lib/routeparam
 */

'use strict'

const tableBuilder = require('./parameterTableBuilder')

exports.name = 'params'
exports.options = {
  mustHaveValue: true,
  mustNotHaveDescription: false,
  canHaveType: true,
  canHaveName: true,
  onTagged: function (doclet, tag) {
    if (!doclet.params) {
      doclet.params = []
    }

    doclet.params.push({
      'name': tag.value.name,
      'type': tag.value.type ? (tag.value.type.names.length === 1 ? tag.value.type.names[0] : tag.value.type.names) : '',
      'description': tag.value.description || ''
    })
  }
}
exports.newDocletHandler = function (e) {
  if (e.doclet.route === undefined)
    return;

  const parameters = e.doclet.params
  if (parameters) {
    const table = tableBuilder.build('Route Parameters', parameters)

    e.doclet.description = `${e.doclet.description || ''}
                            ${table}`
  }
}
<|endoftext|>


<commit_before>'use strict'
module.exports = ficToEpub
const Streampub = require('streampub')
const chapterFilename = require('./chapter-filename.js')
const sanitizeHtml = require('sanitize-html')
const ms = require('mississippi')
const url = require('url')
const fs = require('fs')
const commaNumber = require('comma-number')
const html = require('html-template-tag')

function ficToEpub (meta) {
  const epub = new Streampub({
    id: meta.id,
    title: meta.title,
    author: meta.author,
    authorUrl: meta.authorUrl,
    description: meta.description,
    source: meta.link,
    subject: meta.tags && meta.tags.length && meta.tags.join(','),
    publisher: meta.publisher,
    published: meta.started || meta.created,
    modified: meta.modified,
    includeTOC: meta.includeTOC,
    numberTOC: meta.numberTOC
  })

  if (meta.cover && !/:/.test(meta.cover)) {
    epub.write(Streampub.newCoverImage(fs.createReadStream(meta.cover)))
  } else {
    let titleContent = ''
    titleContent += html`

<title>${meta.title}</title>
`
    titleContent += html`<section epub:type="title"><h1>${meta.title}</h1></section>`
    if (meta.author) {
      const author = meta.authorUrl ? html`<a href="${meta.authorUrl}">${meta.author}</a>` : meta.author
      titleContent += `<h3>by <span epub:type="credits">${author}</span></h3>`
    }
    titleContent += html`<table>`
    if (meta.link) {
      const wrappableLink = meta.link.replace(/(.....)/g, '$1<wbr>')
      titleContent += `<tr><th>Source</th><td><a href="${meta.link}">${wrappableLink}</a></td></tr>`
    }
    if (meta.created) titleContent += html`<tr><th>Published</th><td>${meta.created}</td></tr>`
    if (meta.modified) titleContent += html`<tr><th>Updated</th><td>${meta.modified}</td></tr>`
    if (meta.tags && meta.tags.length) {
      titleContent += html`<tr><th>Tags</th><td><section epub:type="keywords"><em>${meta.tags.join(', ')}</em></section></td></tr>`
    }
    if (meta.words) titleContent += html`<tr><th>Words</th><td>${commaNumber(meta.words)}</td></tr>`
    titleContent += `</table>`
    if (meta.description) titleContent += `<section epub:type="abstract"><p>${meta.description}</p></section>`
    titleContent += `</body>`
    const titlePage = `${titleContent}`
    epub.write(Streampub.newChapter('Title Page', titlePage, 0, 'top.xhtml'))
  }
  return ms.pipeline.obj(ms.through.obj(transformChapter(meta)), epub)
}

function transformChapter (meta) {
  return function (chapter, _, done) {
    if (chapter.image) {
      this.push(Streampub.newFile(chapter.filename, chapter.content))
      return done()
    }
    const index = chapter.order != null && (1 + chapter.order)
    const name = chapter.name
    const filename = chapterFilename(chapter)
    const toSanitize = '' +
      (name ? html`<title>${name}</title></head>` : '') +
      '
' + chapter.content + '
' +
      ''
    const content = sanitizeHtml(toSanitize, meta.site.sanitizeHtmlConfig())
    this.push(Streampub.newChapter(name, content, index, filename))
    done()
  }
}
<commit_msg>fic-to-epub: Generate our own TOC pages instead of relying on streampub<commit_after>'use strict'
module.exports = ficToEpub
const Streampub = require('streampub')
const chapterFilename = require('./chapter-filename.js')
const sanitizeHtml = require('sanitize-html')
const ms = require('mississippi')
const url = require('url')
const fs = require('fs')
const commaNumber = require('comma-number')
const html = require('html-template-tag')

function ficToEpub (meta) {
  const epub = new Streampub({
    id: meta.id,
    title: meta.title,
    author: meta.author,
    authorUrl: meta.authorUrl,
    description: meta.description,
    source: meta.link,
    subject: meta.tags && meta.tags.length && meta.tags.join(','),
    publisher: meta.publisher,
    published: meta.started || meta.created,
    modified: meta.modified,
    numberTOC: meta.numberTOC
  })

  if (meta.cover && !/:/.test(meta.cover)) {
    epub.write(Streampub.newCoverImage(fs.createReadStream(meta.cover)))
  } else {
    let titleContent = ''
    titleContent += html`

<title>${meta.title}</title>
`
    titleContent += html`<section epub:type="title"><h1>${meta.title}</h1></section>`
    if (meta.author) {
      const author = meta.authorUrl ? html`<a href="${meta.authorUrl}">${meta.author}</a>` : meta.author
      titleContent += `<h3>by <span epub:type="credits">${author}</span></h3>`
    }
    titleContent += html`<table>`
    if (meta.link) {
      const wrappableLink = meta.link.replace(/(.....)/g, '$1<wbr>')
      titleContent += `<tr><th>Source</th><td><a href="${meta.link}">${wrappableLink}</a></td></tr>`
    }
    if (meta.created) titleContent += html`<tr><th>Published</th><td>${meta.created}</td></tr>`
    if (meta.modified) titleContent += html`<tr><th>Updated</th><td>${meta.modified}</td></tr>`
    if (meta.tags && meta.tags.length) {
      titleContent += html`<tr><th>Tags</th><td><section epub:type="keywords"><em>${meta.tags.join(', ')}</em></section></td></tr>`
    }
    if (meta.words) titleContent += html`<tr><th>Words</th><td>${commaNumber(meta.words)}</td></tr>`
    titleContent += `</table>`
    if (meta.description) titleContent += `<section epub:type="abstract"><p>${meta.description}</p></section>`
    titleContent += `</body>`
    const titlePage = `${titleContent}`
    epub.write(Streampub.newChapter('Title Page', titlePage, 0, 'top.xhtml'))
  }
  if (meta.includeTOC) {
    const style = `
  h1, h3 { text-align: center; }
  ol { margin-left: 3em; }`
    const header = html`<title>${meta.title}</title><style>${style}</style>`
    const title = html`<h1>${meta.title}</h1>`
    let author = ''
    if (meta.author) {
      author = meta.authorUrl
        ? html`<h3>by <a href="${meta.authorUrl}">${meta.author}</a></h3>`
        : html`<h3>by ${meta.author}</h3>`
    }
    const tocitems = meta.chapters.map((chapter) => html`<li><a href="${chapterFilename(chapter)}">${chapter.name}</li>`).join('\n')
    const toc = `<ol>${tocitems}</ol>`
    const body = `${title}${author}${toc}`
    const tocPage = `<html><head>${header}</head><body>${body}</body></html>`
    epub.write(Streampub.newChapter('Table of Contents', tocPage, 1, 'toc.xhtml'))
  }
  return ms.pipeline.obj(ms.through.obj(transformChapter(meta)), epub)
}

function transformChapter (meta) {
  return function (chapter, _, done) {
    if (chapter.image) {
      this.push(Streampub.newFile(chapter.filename, chapter.content))
      return done()
    }
    const index = chapter.order != null && (1 + chapter.order)
    const name = chapter.name
    const filename = chapterFilename(chapter)
    const toSanitize = '' +
      (name ? html`<title>${name}</title></head>` : '') +
      '
' + chapter.content + '
' +
      ''
    const content = sanitizeHtml(toSanitize, meta.site.sanitizeHtmlConfig())
    this.push(Streampub.newChapter(name, content, index, filename))
    done()
  }
}
<|endoftext|>


<commit_before>/* DOM Level2 Events implemented as described here:
 *
 * http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html
 *
 */
var core = require("./core").dom.level2.core,
    sys = require("sys");

var events = {};

events.EventException = function() {
    if (arguments.length > 0) {
        this._code = arguments[0];
    } else {
        this._code = 0;
    }
    if (arguments.length > 1) {
        this._message = arguments[1];
    } else {
        this._message = "Unspecified event type";
    }
    Error.call(this, this._message);
    if (Error.captureStackTrace) {
        Error.captureStackTrace(this, events.EventException);
    }
};
events.EventException.prototype = {
  UNSPECIFIED_EVENT_TYPE_ERR : 0,
  get code() { return this._code;}
};
events.EventException.prototype.__proto__ = Error.prototype;

events.Event = function(eventType) {
    this._eventType = eventType;
    this._type = null;
    this._bubbles = null;
    this._cancelable = null;
    this._target = null;
    this._currentTarget = null;
    this._eventPhase = null;
    this._timeStamp = null;
    this._preventDefault = false;
    this._stopPropagation = false;
};
events.Event.prototype = {
    initEvent: function(type, bubbles, cancelable) {
        this._type = type;
        this._bubbles = bubbles;
        this._cancelable = cancelable;
    },
    preventDefault: function() {
        if (this._cancelable) {
            this._preventDefault = true;
        }
    },
    stopPropagation: function() {
        this._stopPropagation = true;
    },
    CAPTURING_PHASE : 1,
    AT_TARGET       : 2,
    BUBBLING_PHASE  : 3,
    get eventType() { return this._eventType; },
    get type() { return this._type; },
    get bubbles() { return this._bubbles; },
    get cancelable() { return this._cancelable; },
    get target() { return this._target; },
    get currentTarget() { return this._currentTarget; },
    get eventPhase() { return this._eventPhase; },
    get timeStamp() { return this._timeStamp; }
};

events.HTMLEvent = function(eventType) {
    events.Event.call(this, eventType);
};
events.HTMLEvent.prototype.__proto__ = events.Event.prototype;

events.UIEvent = function(eventType) {
    events.Event.call(this, eventType);
    this.view = null;
    this.detail = null;
};
events.UIEvent.prototype = {
    initUIEvent: function(type, bubbles, cancelable, view, detail) {
        this.initEvent(type, bubbles, cancelable);
        this.view = view;
        this.detail = detail;
    },
};
events.UIEvent.prototype.__proto__ = events.Event.prototype;

events.MouseEvent = function(eventType) {
    events.UIEvent.call(this, eventType);
    this.screenX = null;
    this.screenY = null;
    this.clientX = null;
    this.clientY = null;
    this.ctrlKey = null;
    this.shiftKey = null;
    this.altKey = null;
    this.metaKey = null;
    this.button = null;
    this.relatedTarget = null;
};
events.MouseEvent.prototype = {
    initMouseEvent:   function(type,
                               bubbles,
                               cancelable,
                               view,
                               detail,
                               screenX,
                               screenY,
                               clientX,
                               clientY,
                               ctrlKey,
                               altKey,
                               shiftKey,
                               metaKey,
                               button,
                               relatedTarget) {
        this.initUIEvent(type, bubbles, cancelable, view, detail);
        this.screenX  = screenX
        this.screenY  = screenY
        this.clientX  = clientX
        this.clientY  = clientY
        this.ctrlKey  = ctrlKey
        this.shiftKey  = shiftKey
        this.altKey  = altKey
        this.metaKey  = metaKey
        this.button  = button
        this.relatedTarget  = relatedTarget
    }
};
events.MouseEvent.prototype.__proto__ = events.UIEvent.prototype;

events.MutationEvent = function(eventType) {
    events.Event.call(this, eventType);
    this.relatedNode = null;
    this.prevValue = null;
    this.newValue = null;
    this.attrName = null;
    this.attrChange = null;
};
events.MutationEvent.prototype = {
    initMutationEvent:   function(type,
                                  bubbles,
                                  cancelable,
                                  relatedNode,
                                  prevValue,
                                  newValue,
                                  attrName,
                                  attrChange) {
        this.initEvent(type, bubbles, cancelable);
        this.relatedNode = relatedNode;
        this.prevValue = prevValue;
        this.newValue = newValue;
        this.attrName = attrName;
        this.attrChange = attrChange;
    },
    MODIFICATION : 1,
    ADDITION     : 2,
    REMOVAL      : 3
};
events.MutationEvent.prototype.__proto__ = events.Event.prototype;

events.EventTarget = function() {};

events.EventTarget.getListeners = function getListeners(target, type, capturing) {
    var listeners = target._listeners
            && target._listeners[type]
            && target._listeners[type][capturing];
    if (listeners && listeners.length) {
        return listeners;
    }
    return [];
};

events.EventTarget.dispatch = function dispatch(event, iterator, capturing) {
    var listeners,
        target = iterator();

    while (target && !event._stopPropagation) {
        listeners = events.EventTarget.getListeners(target, event._type, capturing);
        for (var y = 0; y < listeners.length; y++) {
            event._currentTarget = target;
            try {
              listeners[y].call(target, event);
            } catch (e) {
              target.trigger(
                'error', "Dispatching event '" + event._type + "' failed",
                {error: e, event: event}
              );
            }
        }
        target = iterator();
    }
    return !event._stopPropagation;
};

events.EventTarget.forwardIterator = function forwardIterator(list) {
  var i = 0, len = list.length;
  return function iterator() { return i < len ? list[i++] : null };
};

events.EventTarget.backwardIterator = function backwardIterator(list) {
  var i = list.length;
  return function iterator() { return i >=0 ? list[--i] : null };
};

events.EventTarget.singleIterator = function singleIterator(obj) {
  var i = 1;
  return function iterator() { return i-- ? obj : null };
};

events.EventTarget.prototype = {
    addEventListener: function(type, listener, capturing) {
        this._listeners = this._listeners || {};
        var listeners = this._listeners[type] || {};
        capturing = (capturing === true);
        var capturingListeners = listeners[capturing] || [];
        for (var i=0; i < capturingListeners.length; i++) {
            if (capturingListeners[i] === listener) {
                return;
            }
        }
        capturingListeners.push(listener);
        listeners[capturing] = capturingListeners;
        this._listeners[type] = listeners;
    },

    removeEventListener: function(type, listener, capturing) {
        var listeners  = this._listeners && this._listeners[type];
        if (!listeners) return;
        var capturingListeners = listeners[(capturing === true)];
        if (!capturingListeners) return;
        for (var i=0; i < capturingListeners.length; i++) {
            if (capturingListeners[i] === listener) {
                capturingListeners.splice(i, 1);
                return;
            }
        }
    },

    dispatchEvent: function(event) {
        if (event == null) {
            throw new events.EventException(0, "Null event");
        }
        if (event._type == null || event._type == "") {
            throw new events.EventException(0, "Uninitialized event");
        }

        var nextTarget = null;
        var targetList = [];

        event._target = this;

        //per the spec we gather the list of targets first to ensure
        //against dom modifications during actual event dispatch
        nextTarget = this._parentNode;
        while (nextTarget) {
            targetList.push(nextTarget);
            nextTarget = nextTarget._parentNode;
        }

        var iterator = events.EventTarget.backwardIterator(targetList);

        event._eventPhase = event.CAPTURING_PHASE;
        if (!events.EventTarget.dispatch(event, iterator, true)) return event._preventDefault;

        iterator = events.EventTarget.singleIterator(event._target);
        event._eventPhase = event.AT_TARGET;
        if (!events.EventTarget.dispatch(event, iterator, false)) return event._preventDefault;

        var traditionalHandler = this["on" + event._type];
        if (traditionalHandler) {
          try {
            if (traditionalHandler(event) === false) {
              return true;
            }
          }
          catch (e) {
            event._target.trigger(
              'error', "Dispatching event '" + event._type + "' failed.",
              {error: e, event: event}
            );
          }
        }

        if (event._bubbles && !event._stopPropagation) {
            i = 0;
            iterator = events.EventTarget.forwardIterator(targetList);
            event._eventPhase = event.BUBBLING_PHASE;
            events.EventTarget.dispatch(event, iterator, false);
        }

        return event._preventDefault;
    }

};

core.Node.prototype.__proto__ = events.EventTarget.prototype;

function getDocument(el) {
  return el.nodeType == 9 ? el : el._ownerDocument;
}

function mutationEventsEnabled(el) {
  return (el.nodeType == 1 || el.nodeType == 4 || el.nodeType == 9) &&
      getDocument(el).implementation.hasFeature('MutationEvents');
}

function advise(clazz, method, advice) {
    var proto = clazz.prototype,
        impl = proto[method];

  proto[method] = function() {
    var args = Array.prototype.slice.call(arguments);
    var ret = impl.apply(this, arguments);
    args.unshift(ret);
    return advice.apply(this, args) || ret;
  };
}

function adviseBefore(clazz, method, advice) {
  var proto = clazz.prototype,
      impl = proto[method];

  proto[method] = function() {
    advice.apply(this, arguments);
    return impl.apply(this, arguments);
  };
}

function dispatchInsertionEvent(append) {
  return function(ret, newChild, refChild) {
    if ((append || refChild != null) && mutationEventsEnabled(this)) {
      var doc = getDocument(this),
          ev = doc.createEvent("MutationEvents");

      ev.initMutationEvent("DOMNodeInserted", true, false, this, null, null, null, null);
      newChild.dispatchEvent(ev);
      if (this.nodeType == 9 || this._attachedToDocument) {
        ev = doc.createEvent("MutationEvents");
        ev.initMutationEvent("DOMNodeInsertedIntoDocument", false, false, null, null, null, null, null);
        core.visitTree(newChild, function(el) {
          if (el.nodeType == 1) {
            el.dispatchEvent(ev);
            el._attachedToDocument = true;
          }
        });
      }
    }
  };
}

function dispatchRemovalEvent(oldChild) {
  if (mutationEventsEnabled(this)) {
    var doc = getDocument(this),
        ev = doc.createEvent("MutationEvents");

    ev.initMutationEvent("DOMNodeRemoved", true, false, this, null, null, null, null);
    oldChild.dispatchEvent(ev);

    ev = doc.createEvent("MutationEvents");
    ev.initMutationEvent("DOMNodeRemovedFromDocument", false, false, null, null, null, null, null);
    core.visitTree(oldChild, function(el) {
      if (el.nodeType == 1) {
        el.dispatchEvent(ev);
        el._attachedToDocument = false;
      }
    });
  }
}

function dispatchAttrEvent(change, arg) {
  return function(ret) {
    var target = this._parentNode,
        node = arguments[arg];

    if (mutationEventsEnabled(target)) {
      var doc = target._ownerDocument,
          attrChange = events.MutationEvent.prototype[change],
          prevVal = arg == 0 ? node.value : null,
          newVal = arg == 1 ? node.value : null,
          ev = doc.createEvent("MutationEvents");

      ev.initMutationEvent("DOMAttrModified", true, false, target, prevVal, newVal, node.name, attrChange);
      target.dispatchEvent(ev);
    }
  }
}

advise(core.Node, 'insertBefore', dispatchInsertionEvent());
advise(core.Node, 'appendChild', dispatchInsertionEvent(true));
adviseBefore(core.Node, 'removeChild', dispatchRemovalEvent);

advise(core.AttrNodeMap, 'removeNamedItem', dispatchAttrEvent('REMOVAL', 0));
advise(core.AttrNodeMap, 'setNamedItem', dispatchAttrEvent('ADDITION', 1));

core.CharacterData.prototype.__defineSetter__("_nodeValue", function(value) {
    var oldValue = this._nodeValue;
    this._text = value;
    if (this._ownerDocument && this._parentNode && mutationEventsEnabled(this)) {
      var ev = this._ownerDocument.createEvent("MutationEvents")
      ev.initMutationEvent("DOMCharacterDataModified", true, false, this, oldValue, value, null, null);
      this.dispatchEvent(ev);
    }
});

core.Document.prototype.createEvent = function(eventType) {
    switch (eventType) {
        case "MutationEvents": return new events.MutationEvent(eventType);
        case "UIEvents": return new events.UIEvent(eventType);
        case "MouseEvents": return new events.MouseEvent(eventType);
        case "HTMLEvents": return new events.HTMLEvent(eventType);
    }
    return new events.Event(eventType);
};

core.Node.prototype.trigger = function(type, message, data) {
  if (this.createEvent) {
    var evt = this.createEvent('Event');

    // Event does bubble and is not cancelable.
    evt.initEvent(type, true, false);

    evt.message = message;
    evt.data    = data || (new Error(message)).stack;

    this.dispatchEvent(evt);
  }
}

exports.dom =
{
  level2 : {
    core   : core,
    events : events
  }
};

<commit_msg>Fixed mutation events so that insertBefore(node, null) triggers a DOMNodeInserted event<commit_after>/* DOM Level2 Events implemented as described here:
 *
 * http://www.w3.org/TR/2000/REC-DOM-Level-2-Events-20001113/events.html
 *
 */
var core = require("./core").dom.level2.core,
    sys = require("sys");

var events = {};

events.EventException = function() {
    if (arguments.length > 0) {
        this._code = arguments[0];
    } else {
        this._code = 0;
    }
    if (arguments.length > 1) {
        this._message = arguments[1];
    } else {
        this._message = "Unspecified event type";
    }
    Error.call(this, this._message);
    if (Error.captureStackTrace) {
        Error.captureStackTrace(this, events.EventException);
    }
};
events.EventException.prototype = {
  UNSPECIFIED_EVENT_TYPE_ERR : 0,
  get code() { return this._code;}
};
events.EventException.prototype.__proto__ = Error.prototype;

events.Event = function(eventType) {
    this._eventType = eventType;
    this._type = null;
    this._bubbles = null;
    this._cancelable = null;
    this._target = null;
    this._currentTarget = null;
    this._eventPhase = null;
    this._timeStamp = null;
    this._preventDefault = false;
    this._stopPropagation = false;
};
events.Event.prototype = {
    initEvent: function(type, bubbles, cancelable) {
        this._type = type;
        this._bubbles = bubbles;
        this._cancelable = cancelable;
    },
    preventDefault: function() {
        if (this._cancelable) {
            this._preventDefault = true;
        }
    },
    stopPropagation: function() {
        this._stopPropagation = true;
    },
    CAPTURING_PHASE : 1,
    AT_TARGET       : 2,
    BUBBLING_PHASE  : 3,
    get eventType() { return this._eventType; },
    get type() { return this._type; },
    get bubbles() { return this._bubbles; },
    get cancelable() { return this._cancelable; },
    get target() { return this._target; },
    get currentTarget() { return this._currentTarget; },
    get eventPhase() { return this._eventPhase; },
    get timeStamp() { return this._timeStamp; }
};

events.HTMLEvent = function(eventType) {
    events.Event.call(this, eventType);
};
events.HTMLEvent.prototype.__proto__ = events.Event.prototype;

events.UIEvent = function(eventType) {
    events.Event.call(this, eventType);
    this.view = null;
    this.detail = null;
};
events.UIEvent.prototype = {
    initUIEvent: function(type, bubbles, cancelable, view, detail) {
        this.initEvent(type, bubbles, cancelable);
        this.view = view;
        this.detail = detail;
    },
};
events.UIEvent.prototype.__proto__ = events.Event.prototype;

events.MouseEvent = function(eventType) {
    events.UIEvent.call(this, eventType);
    this.screenX = null;
    this.screenY = null;
    this.clientX = null;
    this.clientY = null;
    this.ctrlKey = null;
    this.shiftKey = null;
    this.altKey = null;
    this.metaKey = null;
    this.button = null;
    this.relatedTarget = null;
};
events.MouseEvent.prototype = {
    initMouseEvent:   function(type,
                               bubbles,
                               cancelable,
                               view,
                               detail,
                               screenX,
                               screenY,
                               clientX,
                               clientY,
                               ctrlKey,
                               altKey,
                               shiftKey,
                               metaKey,
                               button,
                               relatedTarget) {
        this.initUIEvent(type, bubbles, cancelable, view, detail);
        this.screenX  = screenX
        this.screenY  = screenY
        this.clientX  = clientX
        this.clientY  = clientY
        this.ctrlKey  = ctrlKey
        this.shiftKey  = shiftKey
        this.altKey  = altKey
        this.metaKey  = metaKey
        this.button  = button
        this.relatedTarget  = relatedTarget
    }
};
events.MouseEvent.prototype.__proto__ = events.UIEvent.prototype;

events.MutationEvent = function(eventType) {
    events.Event.call(this, eventType);
    this.relatedNode = null;
    this.prevValue = null;
    this.newValue = null;
    this.attrName = null;
    this.attrChange = null;
};
events.MutationEvent.prototype = {
    initMutationEvent:   function(type,
                                  bubbles,
                                  cancelable,
                                  relatedNode,
                                  prevValue,
                                  newValue,
                                  attrName,
                                  attrChange) {
        this.initEvent(type, bubbles, cancelable);
        this.relatedNode = relatedNode;
        this.prevValue = prevValue;
        this.newValue = newValue;
        this.attrName = attrName;
        this.attrChange = attrChange;
    },
    MODIFICATION : 1,
    ADDITION     : 2,
    REMOVAL      : 3
};
events.MutationEvent.prototype.__proto__ = events.Event.prototype;

events.EventTarget = function() {};

events.EventTarget.getListeners = function getListeners(target, type, capturing) {
    var listeners = target._listeners
            && target._listeners[type]
            && target._listeners[type][capturing];
    if (listeners && listeners.length) {
        return listeners;
    }
    return [];
};

events.EventTarget.dispatch = function dispatch(event, iterator, capturing) {
    var listeners,
        target = iterator();

    while (target && !event._stopPropagation) {
        listeners = events.EventTarget.getListeners(target, event._type, capturing);
        for (var y = 0; y < listeners.length; y++) {
            event._currentTarget = target;
            try {
              listeners[y].call(target, event);
            } catch (e) {
              target.trigger(
                'error', "Dispatching event '" + event._type + "' failed",
                {error: e, event: event}
              );
            }
        }
        target = iterator();
    }
    return !event._stopPropagation;
};

events.EventTarget.forwardIterator = function forwardIterator(list) {
  var i = 0, len = list.length;
  return function iterator() { return i < len ? list[i++] : null };
};

events.EventTarget.backwardIterator = function backwardIterator(list) {
  var i = list.length;
  return function iterator() { return i >=0 ? list[--i] : null };
};

events.EventTarget.singleIterator = function singleIterator(obj) {
  var i = 1;
  return function iterator() { return i-- ? obj : null };
};

events.EventTarget.prototype = {
    addEventListener: function(type, listener, capturing) {
        this._listeners = this._listeners || {};
        var listeners = this._listeners[type] || {};
        capturing = (capturing === true);
        var capturingListeners = listeners[capturing] || [];
        for (var i=0; i < capturingListeners.length; i++) {
            if (capturingListeners[i] === listener) {
                return;
            }
        }
        capturingListeners.push(listener);
        listeners[capturing] = capturingListeners;
        this._listeners[type] = listeners;
    },

    removeEventListener: function(type, listener, capturing) {
        var listeners  = this._listeners && this._listeners[type];
        if (!listeners) return;
        var capturingListeners = listeners[(capturing === true)];
        if (!capturingListeners) return;
        for (var i=0; i < capturingListeners.length; i++) {
            if (capturingListeners[i] === listener) {
                capturingListeners.splice(i, 1);
                return;
            }
        }
    },

    dispatchEvent: function(event) {
        if (event == null) {
            throw new events.EventException(0, "Null event");
        }
        if (event._type == null || event._type == "") {
            throw new events.EventException(0, "Uninitialized event");
        }

        var nextTarget = null;
        var targetList = [];

        event._target = this;

        //per the spec we gather the list of targets first to ensure
        //against dom modifications during actual event dispatch
        nextTarget = this._parentNode;
        while (nextTarget) {
            targetList.push(nextTarget);
            nextTarget = nextTarget._parentNode;
        }

        var iterator = events.EventTarget.backwardIterator(targetList);

        event._eventPhase = event.CAPTURING_PHASE;
        if (!events.EventTarget.dispatch(event, iterator, true)) return event._preventDefault;

        iterator = events.EventTarget.singleIterator(event._target);
        event._eventPhase = event.AT_TARGET;
        if (!events.EventTarget.dispatch(event, iterator, false)) return event._preventDefault;

        var traditionalHandler = this["on" + event._type];
        if (traditionalHandler) {
          try {
            if (traditionalHandler(event) === false) {
              return true;
            }
          }
          catch (e) {
            event._target.trigger(
              'error', "Dispatching event '" + event._type + "' failed.",
              {error: e, event: event}
            );
          }
        }

        if (event._bubbles && !event._stopPropagation) {
            i = 0;
            iterator = events.EventTarget.forwardIterator(targetList);
            event._eventPhase = event.BUBBLING_PHASE;
            events.EventTarget.dispatch(event, iterator, false);
        }

        return event._preventDefault;
    }

};

core.Node.prototype.__proto__ = events.EventTarget.prototype;

function getDocument(el) {
  return el.nodeType == 9 ? el : el._ownerDocument;
}

function mutationEventsEnabled(el) {
  return (el.nodeType == 1 || el.nodeType == 4 || el.nodeType == 9) &&
      getDocument(el).implementation.hasFeature('MutationEvents');
}

function advise(clazz, method, advice) {
    var proto = clazz.prototype,
        impl = proto[method];

  proto[method] = function() {
    var args = Array.prototype.slice.call(arguments);
    var ret = impl.apply(this, arguments);
    args.unshift(ret);
    return advice.apply(this, args) || ret;
  };
}

function adviseBefore(clazz, method, advice) {
  var proto = clazz.prototype,
      impl = proto[method];

  proto[method] = function() {
    advice.apply(this, arguments);
    return impl.apply(this, arguments);
  };
}

function dispatchInsertionEvent(ret, newChild, refChild) {
  if (mutationEventsEnabled(this)) {
    var doc = getDocument(this),
        ev = doc.createEvent("MutationEvents");

    ev.initMutationEvent("DOMNodeInserted", true, false, this, null, null, null, null);
    newChild.dispatchEvent(ev);
    if (this.nodeType == 9 || this._attachedToDocument) {
      ev = doc.createEvent("MutationEvents");
      ev.initMutationEvent("DOMNodeInsertedIntoDocument", false, false, null, null, null, null, null);
      core.visitTree(newChild, function(el) {
        if (el.nodeType == 1) {
          el.dispatchEvent(ev);
          el._attachedToDocument = true;
        }
      });
    }
  }
}

function dispatchRemovalEvent(oldChild) {
  if (mutationEventsEnabled(this)) {
    var doc = getDocument(this),
        ev = doc.createEvent("MutationEvents");

    ev.initMutationEvent("DOMNodeRemoved", true, false, this, null, null, null, null);
    oldChild.dispatchEvent(ev);

    ev = doc.createEvent("MutationEvents");
    ev.initMutationEvent("DOMNodeRemovedFromDocument", false, false, null, null, null, null, null);
    core.visitTree(oldChild, function(el) {
      if (el.nodeType == 1) {
        el.dispatchEvent(ev);
        el._attachedToDocument = false;
      }
    });
  }
}

function dispatchAttrEvent(change, arg) {
  return function(ret) {
    var target = this._parentNode,
        node = arguments[arg];

    if (mutationEventsEnabled(target)) {
      var doc = target._ownerDocument,
          attrChange = events.MutationEvent.prototype[change],
          prevVal = arg == 0 ? node.value : null,
          newVal = arg == 1 ? node.value : null,
          ev = doc.createEvent("MutationEvents");

      ev.initMutationEvent("DOMAttrModified", true, false, target, prevVal, newVal, node.name, attrChange);
      target.dispatchEvent(ev);
    }
  }
}

advise(core.Node, 'insertBefore', dispatchInsertionEvent);
adviseBefore(core.Node, 'removeChild', dispatchRemovalEvent);

advise(core.AttrNodeMap, 'removeNamedItem', dispatchAttrEvent('REMOVAL', 0));
advise(core.AttrNodeMap, 'setNamedItem', dispatchAttrEvent('ADDITION', 1));

core.CharacterData.prototype.__defineSetter__("_nodeValue", function(value) {
    var oldValue = this._nodeValue;
    this._text = value;
    if (this._ownerDocument && this._parentNode && mutationEventsEnabled(this)) {
      var ev = this._ownerDocument.createEvent("MutationEvents")
      ev.initMutationEvent("DOMCharacterDataModified", true, false, this, oldValue, value, null, null);
      this.dispatchEvent(ev);
    }
});

core.Document.prototype.createEvent = function(eventType) {
    switch (eventType) {
        case "MutationEvents": return new events.MutationEvent(eventType);
        case "UIEvents": return new events.UIEvent(eventType);
        case "MouseEvents": return new events.MouseEvent(eventType);
        case "HTMLEvents": return new events.HTMLEvent(eventType);
    }
    return new events.Event(eventType);
};

core.Node.prototype.trigger = function(type, message, data) {
  if (this.createEvent) {
    var evt = this.createEvent('Event');

    // Event does bubble and is not cancelable.
    evt.initEvent(type, true, false);

    evt.message = message;
    evt.data    = data || (new Error(message)).stack;

    this.dispatchEvent(evt);
  }
}

exports.dom =
{
  level2 : {
    core   : core,
    events : events
  }
};

<|endoftext|>