<commit_before>/*global Uint8Array*/
var exifParser = require('exif-parser'),
    fs = require('fs');

module.exports = {
    name: 'unexpected-exif',
    version: require('../package.json').version,
    installInto: function (expect) {
        expect.installPlugin(require('magicpen-media'));

        expect.addAssertion(['string', 'Buffer'], 'to have (exif|EXIF) data satisfying', function (expect, subject, value) {
            var title,
                subjectUrl;
            if (typeof subject === 'string') {
                var matchDataUrl = subject.match(/^data:[^;]*;base64,(.*)$/);
                if (matchDataUrl) {
                    subject = new Buffer(matchDataUrl[1], 'base64');
                } else {
                    title = subject;
                    subjectUrl = subject;
                    subject = fs.readFileSync(subject);
                }
            } else if (subject instanceof Uint8Array) {
                subject = new Buffer(subject);
            }

            this.subjectOutput = function () {
                this.image(subjectUrl || subject, { width: 10, height: 5, link: true, title: title });
            };

            var exifData = exifParser.create(subject).parse();
            if (exifData && exifData.startMarker) {
                delete exifData.startMarker;
            }
            return expect(exifData, 'to satisfy', value);
        });
    }
};
<commit_msg>Update to unexpected v10's addAssertion syntax [ci skip].<commit_after>/*global Uint8Array*/
var exifParser = require('exif-parser'),
    fs = require('fs');

module.exports = {
    name: 'unexpected-exif',
    version: require('../package.json').version,
    installInto: function (expect) {
        expect.installPlugin(require('magicpen-media'));

        expect.addAssertion('<string|Buffer> to have (exif|EXIF) data satisfying <any>', function (expect, subject, value) {
            var title,
                subjectUrl;
            if (typeof subject === 'string') {
                var matchDataUrl = subject.match(/^data:[^;]*;base64,(.*)$/);
                if (matchDataUrl) {
                    subject = new Buffer(matchDataUrl[1], 'base64');
                } else {
                    title = subject;
                    subjectUrl = subject;
                    subject = fs.readFileSync(subject);
                }
            } else if (subject instanceof Uint8Array) {
                subject = new Buffer(subject);
            }

            this.subjectOutput = function () {
                this.image(subjectUrl || subject, { width: 10, height: 5, link: true, title: title });
            };

            var exifData = exifParser.create(subject).parse();
            if (exifData && exifData.startMarker) {
                delete exifData.startMarker;
            }
            return expect(exifData, 'to satisfy', value);
        });
    }
};
<|endoftext|>


<commit_before>// manages behavior of results view list vs maps setting
define(['util/web-storage-proxy','map-view-manager'],function(webStorageProxy,mapViewManager) {
  'use strict';

		// PRIVATE PROPERTIES
		var listViewButton;
		var mapViewButton;
		var listView;
		var mapView;
		var selected;

		var storageName = "resultviewpref";

		// PUBLIC METHODS
		function init()
		{
			listView = document.getElementById("list-view");
			mapView = document.getElementById("map-view");

			// check that required views are present on the page
			if (listView && mapView)
			{
				listViewButton = document.getElementById("list-view-btn");
				mapViewButton = document.getElementById("map-view-btn");

				listViewButton.addEventListener( "mousedown" , _listClickHandler , false);
				mapViewButton.addEventListener( "mousedown" , _mapClickHandler , false);

				_updateButtonStates();
			}
		}

		function _updateButtonStates()
		{
			if (webStorageProxy.getItem(storageName) == "map"){
				selected = mapViewButton;
				mapViewManager.init();
				listViewButton.disabled = "";
			}else{
				selected = listViewButton;
				mapViewButton.disabled = "";
			}

			selected.disabled = "disabled";
			if (selected == listViewButton)
			{
				mapView.classList.add("hide");
				listView.classList.remove("hide");
			}
			else if (selected == mapViewButton)
			{
				listView.classList.add("hide");
				mapView.classList.remove("hide");
			}
		}

		// PRIVATE METHODS
		function _listClickHandler(evt)
		{
			webStorageProxy.setItem(storageName , "list");
			_updateButtonStates();
		}

		function _mapClickHandler(evt)
		{
			webStorageProxy.setItem(storageName , "map");
			_updateButtonStates();
		}

	return {
		init:init
	};
});<commit_msg>Fixes initialization issue with mapbox<commit_after>// manages behavior of results view list vs maps setting
define(['util/web-storage-proxy','map-view-manager'],function(webStorageProxy,mapViewManager) {
  'use strict';

		// PRIVATE PROPERTIES
		var listViewButton;
		var mapViewButton;
		var listView;
		var mapView;
		var selected;

		var storageName = "resultviewpref";

		// PUBLIC METHODS
		function init()
		{
			listView = document.getElementById("list-view");
			mapView = document.getElementById("map-view");

			// check that required views are present on the page
			if (listView && mapView)
			{
				listViewButton = document.getElementById("list-view-btn");
				mapViewButton = document.getElementById("map-view-btn");

				listViewButton.addEventListener( "mousedown" , _listClickHandler , false);
				mapViewButton.addEventListener( "mousedown" , _mapClickHandler , false);

				_updateButtonStates();
			}
		}

		function _updateButtonStates()
		{
			if (webStorageProxy.getItem(storageName) == "map"){
				selected = mapViewButton;
				listViewButton.disabled = "";
			}else{
				selected = listViewButton;
				mapViewButton.disabled = "";
			}

			selected.disabled = "disabled";
			if (selected == listViewButton)
			{
				mapView.classList.add("hide");
				listView.classList.remove("hide");
			}
			else if (selected == mapViewButton)
			{
				listView.classList.add("hide");
				mapView.classList.remove("hide");
				mapViewManager.init();
			}
		}

		// PRIVATE METHODS
		function _listClickHandler(evt)
		{
			webStorageProxy.setItem(storageName , "list");
			_updateButtonStates();
		}

		function _mapClickHandler(evt)
		{
			webStorageProxy.setItem(storageName , "map");
			_updateButtonStates();
		}

	return {
		init:init
	};
});<|endoftext|>


<commit_before>/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for NodeJS is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */

'use strict'
var flatten = require('flat')
var unflatten = require('flat').unflatten
var util = require('util')
var RC = require('rc-yaml-2')
var fs = require('fs')

// load SPM receivers from file containing
// env vars e.g. SPM_RECEIVER_URL, EVENTS_RECEIVER_URL, LOGSENE_RECEIVER_URL
// the file overwrites the actual environment
// and is used by Sematext Enterprise or multi-region setups to
// setup receiver URLs
function loadEnvFromFile (fileName) {
  try {
    var receivers = fs.readFileSync(fileName).toString()
    if (receivers) {
      var lines = receivers.split('\n')
    }
    // console.log(new Date(), 'loading Sematext receiver URLs from ' + fileName)
    lines.forEach(function (line) {
      var kv = line.split('=')
      if (kv.length === 2 && kv[1].length > 0) {
        process.env[kv[0].trim()] = kv[1].trim()
      // console.log(kv[0].trim() + ' = ' + kv[1].trim())
      }
    })
  } catch (error) {
    // ignore missing file or wrong format
    // console.error(error.message)
  }
}
var envFileName = '/etc/sematext/receivers.config'
/**
  if (/win/.test(os.platform()) {
    envFileName = process.env.ProgramData + '\\Sematext\\receivers.config'
  }
**/
loadEnvFromFile(envFileName)

var spmDefaultConfig = {
  tokens: {
    spm: process.env.SPM_TOKEN
  },
  maxDbSize: Number(process.env.SPM_MAX_DB_SIZE) || 1024 * 1024 * 24,
  agentsToLoad: [],
  maxDataPoints: Number(process.env.SPM_MAX_DATAPOINTS) || 90,
  recoverInterval: Number(process.env.SPM_RECOVER_INTERVAL_IN_MS) || 10000,
  collectionInterval: Number(process.env.SPM_COLLECTION_INTERVAL_IN_MS) || 10000,
  transmitInterval: Number(process.env.SPM_TRANSMIT_INTERVAL_IN_MS) || 15000,
  maxRetransmitBatchSize: Number(process.env.SPM_MAX_RETRANSMIT_BATCH_SIZE) || 100,
  spmSenderBulkInsertUrl: process.env.SPM_RECEIVER_URL || 'https://spm-receiver.sematext.com:443/receiver/v1/_bulk',
  eventsReceiverUrl: process.env.EVENTS_RECEIVER_URL || 'https://event-receiver.sematext.com',
  dbDir: process.env.SPM_DB_DIR || './spmdb',
  logger: {
    dir: process.env.SPM_LOG_DIRECTORY || './spmlogs',
    level: process.env.SPM_LOG_LEVEL || 'error',
    console: process.env.SPM_LOG_TO_CONSOLE || false,
    maxfiles: Number(process.env.SPM_LOG_MAX_FILES) || '2',
    maxsize: Number(process.env.SPM_LOG_MAX_FILE_SIZE) || '524288',
    filename: process.env.SPM_LOG_FILE_PREFIX || 'spm',
    useLogstashFormat: process.env.SPM_LOG_LOGSTASH_FORMAT || false,
    silent: process.env.SPM_LOG_SILENT || false
  }
}
var SpmConfig = function (appType) {
  var rc = new RC(appType, spmDefaultConfig)
  util._extend(this, rc)
  this.rcFlat = flatten(this)
  return this
}

SpmConfig.prototype.get = function (flatKey) {
  return this.rcFlat[flatKey]
}

SpmConfig.prototype.set = function (flatKey, value) {
  var kv = {}
  kv[flatKey] = value
  kv.object = true
  var result = unflatten(kv)
  delete result.object
  delete this.rcFlat
  util._extend(this, result)
  this.rcFlat = flatten(this)
  return this
}

module.exports = new SpmConfig(process.env.SPM_AGENT_APP_TYPE || 'spmagent')
<commit_msg>increase max DB size for buffered metrics to 100 MB<commit_after>/*
 * @copyright Copyright (c) Sematext Group, Inc. - All Rights Reserved
 *
 * @licence SPM for NodeJS is free-to-use, proprietary software.
 * THIS IS PROPRIETARY SOURCE CODE OF Sematext Group, Inc. (Sematext)
 * This source code may not be copied, reverse engineered, or altered for any purpose.
 * This source code is to be used exclusively by users and customers of Sematext.
 * Please see the full license (found in LICENSE in this distribution) for details on its license and the licenses of its dependencies.
 */

'use strict'
var flatten = require('flat')
var unflatten = require('flat').unflatten
var util = require('util')
var RC = require('rc-yaml-2')
var fs = require('fs')

// load SPM receivers from file containing
// env vars e.g. SPM_RECEIVER_URL, EVENTS_RECEIVER_URL, LOGSENE_RECEIVER_URL
// the file overwrites the actual environment
// and is used by Sematext Enterprise or multi-region setups to
// setup receiver URLs
function loadEnvFromFile (fileName) {
  try {
    var receivers = fs.readFileSync(fileName).toString()
    if (receivers) {
      var lines = receivers.split('\n')
    }
    // console.log(new Date(), 'loading Sematext receiver URLs from ' + fileName)
    lines.forEach(function (line) {
      var kv = line.split('=')
      if (kv.length === 2 && kv[1].length > 0) {
        process.env[kv[0].trim()] = kv[1].trim()
      // console.log(kv[0].trim() + ' = ' + kv[1].trim())
      }
    })
  } catch (error) {
    // ignore missing file or wrong format
    // console.error(error.message)
  }
}
var envFileName = '/etc/sematext/receivers.config'
/**
  if (/win/.test(os.platform()) {
    envFileName = process.env.ProgramData + '\\Sematext\\receivers.config'
  }
**/
loadEnvFromFile(envFileName)

var spmDefaultConfig = {
  tokens: {
    spm: process.env.SPM_TOKEN
  },
  maxDbSize: Number(process.env.SPM_MAX_DB_SIZE) || 1024 * 1024 * 100,
  agentsToLoad: [],
  maxDataPoints: Number(process.env.SPM_MAX_DATAPOINTS) || 90,
  recoverInterval: Number(process.env.SPM_RECOVER_INTERVAL_IN_MS) || 10000,
  collectionInterval: Number(process.env.SPM_COLLECTION_INTERVAL_IN_MS) || 10000,
  transmitInterval: Number(process.env.SPM_TRANSMIT_INTERVAL_IN_MS) || 15000,
  maxRetransmitBatchSize: Number(process.env.SPM_MAX_RETRANSMIT_BATCH_SIZE) || 100,
  spmSenderBulkInsertUrl: process.env.SPM_RECEIVER_URL || 'https://spm-receiver.sematext.com:443/receiver/v1/_bulk',
  eventsReceiverUrl: process.env.EVENTS_RECEIVER_URL || 'https://event-receiver.sematext.com',
  dbDir: process.env.SPM_DB_DIR || './spmdb',
  logger: {
    dir: process.env.SPM_LOG_DIRECTORY || './spmlogs',
    level: process.env.SPM_LOG_LEVEL || 'error',
    console: process.env.SPM_LOG_TO_CONSOLE || false,
    maxfiles: Number(process.env.SPM_LOG_MAX_FILES) || '2',
    maxsize: Number(process.env.SPM_LOG_MAX_FILE_SIZE) || '524288',
    filename: process.env.SPM_LOG_FILE_PREFIX || 'spm',
    useLogstashFormat: process.env.SPM_LOG_LOGSTASH_FORMAT || false,
    silent: process.env.SPM_LOG_SILENT || false
  }
}
var SpmConfig = function (appType) {
  var rc = new RC(appType, spmDefaultConfig)
  util._extend(this, rc)
  this.rcFlat = flatten(this)
  return this
}

SpmConfig.prototype.get = function (flatKey) {
  return this.rcFlat[flatKey]
}

SpmConfig.prototype.set = function (flatKey, value) {
  var kv = {}
  kv[flatKey] = value
  kv.object = true
  var result = unflatten(kv)
  delete result.object
  delete this.rcFlat
  util._extend(this, result)
  this.rcFlat = flatten(this)
  return this
}

module.exports = new SpmConfig(process.env.SPM_AGENT_APP_TYPE || 'spmagent')
<|endoftext|>


<commit_before>(function(){
  Ciclavia.Modules.RouteSubmitGuide = Stapes.subclass({
    STEPS: ["instructions", "clickPoints", "enterInfo"],
    TEMPLATES: {
      instructions: "route-submits/instructions"
    },

    CSS: {
      INSTRUCTIONS: {
        container: ".infoconfirm",
        okayButton: ".infoconfirm .okay"
      },

      BUTTONS: {
        submitModeButton: "#submit-mode-button",
        submitModeCancelButton: "#submit-mode-cancel-button",
        submitModeDoneButton: "#submit-mode-done-button"
      }
    },

    constructor: function(map){
      this.map = map;
      this.routeCreator = new Ciclavia.Modules.RouteCreator();
      this._setListeners();
    },

    advanceToNextStep: function(){
      this.set("step", this.get("step") + 1);
    },

    resetAll: function(){
      this.set("step", 0, true);
      this.map.mapnav.show();
      this.map.removeElement(this.routeCreator.currentLineElementForMap());
      this._showButtonsFor(["submit mode"]);
      this.routeCreator.reset();
    },

    render: function(){
      var currentStepName = this.currentStepName();
      if(currentStepName === "instructions"){

        // Step 0
        Ciclavia.Modules.Blackout.on();
        var renderedTemplate = HandlebarsTemplates[this.TEMPLATES.instructions]();
        $("body").append(renderedTemplate);
        this._showButtonsFor([]);

      } else if(currentStepName === "clickPoints"){

        // Step 1
        $(this.CSS.INSTRUCTIONS.container).remove();
        Ciclavia.Modules.Blackout.off();
        this.map.mapnav.hide();
        this._showButtonsFor(["cancel submit", "done submitting"]);

      } else if (currentStepName === "enterInfo"){

        // Step 2

      }
    },

    currentStepName: function(){
      return this.STEPS[this.get("step")];
    },

    _setListeners: function(){
      $(document).on("click", this.CSS.INSTRUCTIONS.okayButton, this.advanceToNextStep.bind(this));

      this._bindtoSubmitModeButton();
      this._bindtoCancelSubmitModeButton();

      this.on("change:step", this.render.bind(this));
      this.map.on("change:mode", this._modeChanged.bind(this));
      this.map.on("mapClick", this._mapClicked.bind(this));
    },

    _mapClicked: function(clickEvent){
      if(this.currentStepName() === "clickPoints"){
        var latlng = clickEvent.latlng;
        this.routeCreator.addPoint([latlng.lat, latlng.lng]);
        this.map
          .removeElement(this.routeCreator.lastLineElementForMap())
          .addElement(this.routeCreator.currentLineElementForMap());
      }
    },

    _modeChanged: function(mode){
      if(mode === "submit"){
        this.set("step", 0);
      } else if(mode === "view") {
        this.resetAll();
      } else {
        throw "Map changed to unknown mode";
      }
    },

    _bindtoSubmitModeButton: function(){
      var $button = $(this.CSS.BUTTONS.submitModeButton);
      $button.click(function(){
        this.emit("submitModeButtonClicked");
      }.bind(this));
    },

    _bindtoCancelSubmitModeButton: function(){
      $(this.CSS.BUTTONS.submitModeCancelButton).click(function(){
        this.emit("submitModeCancelButtonClicked");
      }.bind(this));
    },

    _showButtonsFor: function(arrayOfButtonNames){
      var mapping = {
        "submit mode": $(this.CSS.BUTTONS.submitModeButton),
        "cancel submit": $(this.CSS.BUTTONS.submitModeCancelButton),
        "done submitting": $(this.CSS.BUTTONS.submitModeDoneButton)
      };

      _.each(mapping, function($button, key){
        if(_.contains(arrayOfButtonNames, key)){
          $button.removeClass("hidden");
        } else {
          $button.addClass("hidden");
        }
      });
    }
  });

})();<commit_msg>Don't reset. Bad fix<commit_after>(function(){
  Ciclavia.Modules.RouteSubmitGuide = Stapes.subclass({
    STEPS: ["instructions", "clickPoints", "enterInfo"],
    TEMPLATES: {
      instructions: "route-submits/instructions"
    },

    CSS: {
      INSTRUCTIONS: {
        container: ".infoconfirm",
        okayButton: ".infoconfirm .okay"
      },

      BUTTONS: {
        submitModeButton: "#submit-mode-button",
        submitModeCancelButton: "#submit-mode-cancel-button",
        submitModeDoneButton: "#submit-mode-done-button"
      }
    },

    constructor: function(map){
      this.map = map;
      this.routeCreator = new Ciclavia.Modules.RouteCreator();
      this._setListeners();
    },

    advanceToNextStep: function(){
      this.set("step", this.get("step") + 1);
    },

    resetAll: function(){
      this.map.mapnav.show();
      this.map.removeElement(this.routeCreator.currentLineElementForMap());
      this._showButtonsFor(["submit mode"]);
      this.routeCreator.reset();
    },

    render: function(){
      var currentStepName = this.currentStepName();
      if(currentStepName === "instructions"){

        // Step 0
        Ciclavia.Modules.Blackout.on();
        var renderedTemplate = HandlebarsTemplates[this.TEMPLATES.instructions]();
        $("body").append(renderedTemplate);
        this._showButtonsFor([]);

      } else if(currentStepName === "clickPoints"){

        // Step 1
        $(this.CSS.INSTRUCTIONS.container).remove();
        Ciclavia.Modules.Blackout.off();
        this.map.mapnav.hide();
        this._showButtonsFor(["cancel submit", "done submitting"]);

      } else if (currentStepName === "enterInfo"){

        // Step 2

      }
    },

    currentStepName: function(){
      return this.STEPS[this.get("step")];
    },

    _setListeners: function(){
      $(document).on("click", this.CSS.INSTRUCTIONS.okayButton, this.advanceToNextStep.bind(this));

      this._bindtoSubmitModeButton();
      this._bindtoCancelSubmitModeButton();

      this.on("change:step", this.render.bind(this));
      this.map.on("change:mode", this._modeChanged.bind(this));
      this.map.on("mapClick", this._mapClicked.bind(this));
    },

    _mapClicked: function(clickEvent){
      if(this.map.get("mode") == "submit" && this.currentStepName() === "clickPoints"){
        var latlng = clickEvent.latlng;
        this.routeCreator.addPoint([latlng.lat, latlng.lng]);
        this.map
          .removeElement(this.routeCreator.lastLineElementForMap())
          .addElement(this.routeCreator.currentLineElementForMap());
      }
    },

    _modeChanged: function(mode){
      if(mode === "submit"){
        this.set("step", 0);
      } else if(mode === "view") {
        this.resetAll();
      } else {
        throw "Map changed to unknown mode";
      }
    },

    _bindtoSubmitModeButton: function(){
      var $button = $(this.CSS.BUTTONS.submitModeButton);
      $button.click(function(){
        this.emit("submitModeButtonClicked");
      }.bind(this));
    },

    _bindtoCancelSubmitModeButton: function(){
      $(this.CSS.BUTTONS.submitModeCancelButton).click(function(){
        this.emit("submitModeCancelButtonClicked");
      }.bind(this));
    },

    _showButtonsFor: function(arrayOfButtonNames){
      var mapping = {
        "submit mode": $(this.CSS.BUTTONS.submitModeButton),
        "cancel submit": $(this.CSS.BUTTONS.submitModeCancelButton),
        "done submitting": $(this.CSS.BUTTONS.submitModeDoneButton)
      };

      _.each(mapping, function($button, key){
        if(_.contains(arrayOfButtonNames, key)){
          $button.removeClass("hidden");
        } else {
          $button.addClass("hidden");
        }
      });
    }
  });

})();<|endoftext|>


<commit_before>import React, {PropTypes} from 'react'
import ReactDOM from 'react-dom'
import FormBuilderPropTypes from '../FormBuilderPropTypes'

import {ProseMirror} from 'prosemirror'

import 'prosemirror/dist/menu/menubar'
import 'prosemirror/dist/inputrules/autoinput'
import {parseFrom, serializeTo} from 'prosemirror/dist/format'
import {defaultSchema, Node} from 'prosemirror/dist/model'

const EMPTY_VALUE = defaultSchema.node('doc', null, defaultSchema.node('paragraph'))

// Just a rudimentary value container for prosemirror-produced html. Not meant for production.
class ProseMirrorValueContainer {
  static deserialize(htmlValue, context) {
    const doc = htmlValue ? parseFrom(defaultSchema, htmlValue, 'html') : EMPTY_VALUE
    return new ProseMirrorValueContainer(doc, context)
  }

  constructor(doc, context) {
    this.doc = doc
    this.context = context
  }

  validate() {
    const {field} = this.context
    // todo: figure out a more robust way of checking if document is empty
    if (field.required && this.doc === EMPTY_VALUE) {
      return [{id: 'required'}]
    }
  }

  patch(patch) {
    // console.log('received patch for document: ', patch)
    /* this.doc.transform( ... ) */
    if (!patch.$setDoc || !(patch.$setDoc instanceof Node)) {
      throw new Error('The only allowed patch operation are $setDoc and its value must be a new ProseMirror document')
    }

    return new ProseMirrorValueContainer(patch.$setDoc, this.context)
  }

  serialize() {
    return serializeTo(this.doc, 'html')
  }
}

export default class RichTextProsemirror extends React.Component {
  constructor(props, context) {
    super(props, context)
    this.handleProseMirrorTransform = this.handleProseMirrorTransform.bind(this)
  }

  static valueContainer = ProseMirrorValueContainer;

  static propTypes = {
    field: FormBuilderPropTypes.field.isRequired,
    defaultValue: PropTypes.string,
    value: PropTypes.instanceOf(ProseMirrorValueContainer),
    onChange: PropTypes.func
  };

  static defaultProps = {
    onChange() {}
  };

  componentWillMount() {
    this._prosemirror = new ProseMirror({
      menuBar: true
    })
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this).appendChild(this._prosemirror.wrapper)
    if (this.props.value) {
      this.setContent(this.props.value.doc)
    }

    this._prosemirror.on('transform', this.handleProseMirrorTransform)
  }

  componentDidUpdate({options: previous}) {
  }

  componentWillUnmount() {
    this._prosemirror.off('change', this.handleProseMirrorTransform)
  }

  setContent(doc) {
    this._prosemirror.setContent(doc)
  }

  handleProseMirrorTransform(transform) {
    this.props.onChange({patch: {$setDoc: this._prosemirror.doc}})
    // todo: figure out how this patch should be
    // const steps = []
    // const maps = []
    // for (let i = 0; i < transform.steps.length; i++) {
    //   steps.push(transform.steps[i])
    //   maps.push(transform.maps[i])
    // }
    //
    // this.props.onChange({
    //   patch: {
    //     $maps: maps,
    //     $steps: steps
    //   }
    // })
  }

  render() {
    return

  }
}
<commit_msg>Support resetting/clearing prosemirror document<commit_after>import React, {PropTypes} from 'react'
import ReactDOM from 'react-dom'
import FormBuilderPropTypes from '../FormBuilderPropTypes'

import {ProseMirror} from 'prosemirror'

import 'prosemirror/dist/menu/menubar'
import 'prosemirror/dist/inputrules/autoinput'
import {parseFrom, serializeTo} from 'prosemirror/dist/format'
import {defaultSchema, Node} from 'prosemirror/dist/model'

const EMPTY_VALUE = defaultSchema.node('doc', null, defaultSchema.node('paragraph'))

// Just a rudimentary value container for prosemirror-produced html. Not meant for production.
class ProseMirrorValueContainer {
  static deserialize(htmlValue, context) {
    const doc = htmlValue ? parseFrom(defaultSchema, htmlValue, 'html') : EMPTY_VALUE
    return new ProseMirrorValueContainer(doc, context)
  }

  constructor(doc, context) {
    this.doc = doc
    this.context = context
  }

  validate() {
    const {field} = this.context
    // todo: figure out a more robust way of checking if document is empty
    if (field.required && this.doc === EMPTY_VALUE) {
      return [{id: 'required'}]
    }
  }

  patch(patch) {
    // console.log('received patch for document: ', patch)
    /* this.doc.transform( ... ) */
    if (!patch.$setDoc || !(patch.$setDoc instanceof Node)) {
      throw new Error('The only allowed patch operation are $setDoc and its value must be a new ProseMirror document')
    }

    return new ProseMirrorValueContainer(patch.$setDoc, this.context)
  }

  serialize() {
    return serializeTo(this.doc, 'html')
  }
}

export default class RichTextProsemirror extends React.Component {
  constructor(props, context) {
    super(props, context)
    this.handleProseMirrorTransform = this.handleProseMirrorTransform.bind(this)
  }

  static valueContainer = ProseMirrorValueContainer;

  static propTypes = {
    field: FormBuilderPropTypes.field.isRequired,
    defaultValue: PropTypes.string,
    value: PropTypes.instanceOf(ProseMirrorValueContainer),
    onChange: PropTypes.func
  };

  static defaultProps = {
    onChange() {}
  };

  componentWillMount() {
    this._prosemirror = new ProseMirror({
      menuBar: true
    })
  }

  componentDidMount() {
    ReactDOM.findDOMNode(this).appendChild(this._prosemirror.wrapper)
    if (this.props.value) {
      this.setContent(this.props.value.doc)
    }

    this._prosemirror.on('transform', this.handleProseMirrorTransform)
  }

  componentDidUpdate(prevProps) {
    if (this.props.value.doc !== this._prosemirror.doc) {
      this._prosemirror.setDoc(this.props.value.doc)
    }
  }
  componentWillUnmount() {
    this._prosemirror.off('change', this.handleProseMirrorTransform)
  }

  setContent(doc) {
    this._prosemirror.setContent(doc)
  }

  handleProseMirrorTransform(transform) {
    this.props.onChange({patch: {$setDoc: this._prosemirror.doc}})
    // todo: figure out how this patch should be
    // const steps = []
    // const maps = []
    // for (let i = 0; i < transform.steps.length; i++) {
    //   steps.push(transform.steps[i])
    //   maps.push(transform.maps[i])
    // }
    //
    // this.props.onChange({
    //   patch: {
    //     $maps: maps,
    //     $steps: steps
    //   }
    // })
  }

  render() {
    return

  }
}
<|endoftext|>


<commit_before>
// utilities for working with the js-registry site.

exports.publish = publish
exports.tag = tag
exports.adduser = adduser
exports.get = get

var npm = require("../../npm")
  , http = require("http")
  , url = require("url")
  , log = require("./log")
  , uuid = require("./uuid")
  , sha = require("./sha")
  , sys = require("sys")
  , ini = require("./ini")
  , Buffer = require("buffer").Buffer
  , fs = require("fs")
  , path = require("path")

function get (project, version, cb) {
  if (typeof version === "function") {
    cb = version
    version = null
  }
  GET(project+"/"+(version || ""), cb)
}

function tag (project, version, tag, cb) { PUT(project+"/"+tag, version, cb) }

function publish (data, cb) {
  // add the dist-url to the data, pointing at the tarball.
  // if the {name} isn't there, then create it.
  // if the {version} is already there, then fail.
  // then:
  // PUT the data to {config.registry}/{data.name}/{data.version}
  try { reg() }
  catch (ex) { return cb(ex) }

  var fullData =
    { _id : data.name
    , name : data.name
    , description : data.description
    , "dist-tags" : {}
    , versions : {}
    }
  fullData.versions[ data.version ] = data
  data._id = data.name+"-"+data.version
  var attURI = encodeURIComponent(data.name)
             + "/-/"
             + encodeURIComponent(data.name)
             + "-"
             + encodeURIComponent(data.version)
             + ".tgz"
  data.dist = { "tarball" : url.resolve(npm.config.get("registry"), attURI) }

  // first try to just PUT the whole fullData, and this will fail if it's
  // already there, because it'll be lacking a _rev, so couch'll bounce it.
  PUT(encodeURIComponent(data.name), fullData, function (er, data, json, response) {
    // get the rev and then upload the attachment
    // a 409 is expected here, if this is a new version of an existing package.
    if (er && !(response && response.statusCode !== 409)) {
      return log.er(cb, "Failed PUT response")(er)
    }
    var sendVersionAgain = !!er
    GET(encodeURIComponent(data.name), function (er, d) {
      if (er) return cb(er)
      var rev = d && d._rev
        , tarball = path.join(npm.cache, data.name, data.version, "package.tgz")
        , dataURI = encodeURIComponent(data.name)+"/"+encodeURIComponent(data.version)
      attURI += "/" + rev
      upload(attURI, tarball, function (er) {
        if (!sendVersionAgain) return log.er(cb, "Couldn't send tarball")(er)
        PUT(dataURI, data, log.er(cb, "Error sending version data"))
      })
    })
  })
}
function request (method, where, what, cb) {
  if (typeof what === "function" && !cb) {
    cb = what
    what = null
  }
  try { reg() }
  catch (ex) { return cb(ex) }

  var authRequired = what && !where.match(/^\/?adduser\/org\.couchdb\.user:/)
  where = url.resolve(npm.config.get("registry"), where)
  var u = url.parse(where)
    , https = u.protocol === "https:"
    , auth = authRequired && npm.config.get("auth")

  if (authRequired && !auth) {
    return cb(new Error(
      "Cannot insert data into the registry without authorization and https\n"
      + "See: npm-adduser(1)"))
  }
  if (auth && !https) {
    log("Sending authorization over insecure channel.", "WARNING")
  }
  var headers = { "host" : u.host
                , "accept" : "application/json"
                }
  if (auth) headers.authorization = "Basic " + auth
  if (what) {
    if (what instanceof File) {
      what = what.data
      headers["content-type"] = "application/octet-stream"
    } else {
      what = JSON.stringify(what)
      headers["content-type"] = "application/json"
    }
    headers["content-length"] = what.length
  }

  var client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request(method, u.pathname, headers)
  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      var parsed
      try {
        parsed = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, null, data, response)
      }
      if (parsed && parsed.error) return cb(new Error(
        parsed.error + (" "+parsed.reason || "")))
      cb(null, parsed, data, response)
    })
  })
  if (what) request.write(what, "ascii")
  request.end()
}

function GET (where, cb) { request("GET", where, cb) }
function PUT (where, what, cb) { request("PUT", where, what, cb) }

function upload (where, filename, cb) {
  new File(filename, function (er, f) {
    if (er) log.er(cb, "Couldn't open "+filename)(er)
    PUT(where, f, cb)
  })
}
function File (name, cb) {
  var f = this
  f.name = name
  if (f.loaded) return cb(null, f)
  fs.stat(f.name, function (er, stat) {
    if (er) return log.er(cb, "doesn't exist "+f.name)(er)
    fs.readFile(f.name, function (er, data) {
      if (er) return log.er(cb, "problem reading "+f.name)(er)
      f.data = data
      cb(null, f)
    })
  })
}

function reg () {
  var r = npm.config.get("registry")
  if (!r) throw new Error(
    "Must define registry URL before accessing registry.")
  if (r.substr(-1) !== "/") {
    r += "/"
  }
  npm.config.set("registry", r)
  return r
}

function adduser (username, password, email, callback) {
  var salt = uuid.generate()
    , userobj =
      { _id : 'org.couchdb.user:'+username
      , name : username
      , type : "user"
      , roles : []
      , salt : salt
      , password_sha : sha.hex_sha1(password + salt)
      , email : email
      }
  PUT
    ( '/adduser/org.couchdb.user:'+encodeURIComponent(username)
    , userobj
    , function (error, data, json, response) {
        // if the error is a 409, then update the rev.
        if (error || response && response.statusCode !== 201) {
          log(response && response.statusCode, "response")
          log(error, "error")
          return callback(new Error( (response && response.statusCode) + " "+
            "Could not create user "+error+'\n'+JSON.stringify(data)))
        }
        callback()
      }
    )
}
<commit_msg>Fixes for the change to the publish logic.<commit_after>
// utilities for working with the js-registry site.

exports.publish = publish
exports.tag = tag
exports.adduser = adduser
exports.get = get

var npm = require("../../npm")
  , http = require("http")
  , url = require("url")
  , log = require("./log")
  , uuid = require("./uuid")
  , sha = require("./sha")
  , sys = require("sys")
  , ini = require("./ini")
  , Buffer = require("buffer").Buffer
  , fs = require("fs")
  , path = require("path")

function get (project, version, cb) {
  if (typeof version === "function") {
    cb = version
    version = null
  }
  GET(project+"/"+(version || ""), cb)
}

function tag (project, version, tag, cb) { PUT(project+"/"+tag, version, cb) }

function publish (data, cb) {
  // add the dist-url to the data, pointing at the tarball.
  // if the {name} isn't there, then create it.
  // if the {version} is already there, then fail.
  // then:
  // PUT the data to {config.registry}/{data.name}/{data.version}
  try { reg() }
  catch (ex) { return cb(ex) }

  var fullData =
    { _id : data.name
    , name : data.name
    , description : data.description
    , "dist-tags" : {}
    , versions : {}
    }
  fullData.versions[ data.version ] = data
  data._id = data.name+"-"+data.version
  var attURI = encodeURIComponent(data.name)
             + "/-/"
             + encodeURIComponent(data.name)
             + "-"
             + encodeURIComponent(data.version)
             + ".tgz"
  data.dist = { "tarball" : url.resolve(npm.config.get("registry"), attURI) }

  // first try to just PUT the whole fullData, and this will fail if it's
  // already there, because it'll be lacking a _rev, so couch'll bounce it.
  PUT(encodeURIComponent(data.name), fullData, function (er, regData, json, response) {
    // get the rev and then upload the attachment
    // a 409 is expected here, if this is a new version of an existing package.
    if (er && !(response && response.statusCode === 409)) {
      return log.er(cb, "Failed PUT response")(er)
    }
    var sendVersionAgain = !!er
    GET(encodeURIComponent(data.name), function (er, d) {
      if (er) return cb(er)
      log(data, "tarball data")

      var rev = d && d._rev
        , tarball = path.join(npm.cache, data.name, data.version, "package.tgz")
        , dataURI = encodeURIComponent(data.name)+"/"+encodeURIComponent(data.version)
      log(tarball, "tarball")
      attURI += "/" + rev
      upload(attURI, tarball, function (er) {
        if (!sendVersionAgain) return log.er(cb, "Couldn't send tarball")(er)
        PUT(dataURI, data, log.er(cb, "Error sending version data"))
      })
    })
  })
}
function request (method, where, what, cb) {
  if (typeof what === "function" && !cb) {
    cb = what
    what = null
  }
  try { reg() }
  catch (ex) { return cb(ex) }

  var authRequired = what && !where.match(/^\/?adduser\/org\.couchdb\.user:/)
  where = url.resolve(npm.config.get("registry"), where)
  var u = url.parse(where)
    , https = u.protocol === "https:"
    , auth = authRequired && npm.config.get("auth")

  if (authRequired && !auth) {
    return cb(new Error(
      "Cannot insert data into the registry without authorization and https\n"
      + "See: npm-adduser(1)"))
  }
  if (auth && !https) {
    log("Sending authorization over insecure channel.", "WARNING")
  }
  var headers = { "host" : u.host
                , "accept" : "application/json"
                }
  if (auth) headers.authorization = "Basic " + auth
  if (what) {
    if (what instanceof File) {
      what = what.data
      headers["content-type"] = "application/octet-stream"
    } else {
      what = JSON.stringify(what)
      headers["content-type"] = "application/json"
    }
    headers["content-length"] = what.length
  }

  var client = http.createClient(u.port || (https ? 443 : 80), u.hostname, https)
    , request = client.request(method, u.pathname, headers)
  request.addListener("response", function (response) {
    // if (response.statusCode !== 200) return cb(new Error(
    //   "Status code " + response.statusCode + " from PUT "+where))
    var data = ""
    response.setBodyEncoding("utf8")
    response.addListener("data", function (chunk) { data += chunk })
    response.addListener("end", function () {
      var parsed
      try {
        parsed = JSON.parse(data)
      } catch (ex) {
        ex.message += "\n" + data
        return cb(ex, null, data, response)
      }
      if (parsed && parsed.error) return cb(new Error(
        parsed.error + (" "+parsed.reason || "")))
      cb(null, parsed, data, response)
    })
  })
  if (what) request.write(what, "ascii")
  request.end()
}

function GET (where, cb) { request("GET", where, cb) }
function PUT (where, what, cb) { request("PUT", where, what, cb) }

function upload (where, filename, cb) {
  new File(filename, function (er, f) {
    if (er) log.er(cb, "Couldn't open "+filename)(er)
    PUT(where, f, cb)
  })
}
function File (name, cb) {
  var f = this
  f.name = name
  if (f.loaded) return cb(null, f)
  fs.stat(f.name, function (er, stat) {
    if (er) return log.er(cb, "doesn't exist "+f.name)(er)
    fs.readFile(f.name, function (er, data) {
      if (er) return log.er(cb, "problem reading "+f.name)(er)
      f.data = data
      cb(null, f)
    })
  })
}

function reg () {
  var r = npm.config.get("registry")
  if (!r) throw new Error(
    "Must define registry URL before accessing registry.")
  if (r.substr(-1) !== "/") {
    r += "/"
  }
  npm.config.set("registry", r)
  return r
}

function adduser (username, password, email, callback) {
  var salt = uuid.generate()
    , userobj =
      { _id : 'org.couchdb.user:'+username
      , name : username
      , type : "user"
      , roles : []
      , salt : salt
      , password_sha : sha.hex_sha1(password + salt)
      , email : email
      }
  PUT
    ( '/adduser/org.couchdb.user:'+encodeURIComponent(username)
    , userobj
    , function (error, data, json, response) {
        // if the error is a 409, then update the rev.
        if (error || response && response.statusCode !== 201) {
          log(response && response.statusCode, "response")
          log(error, "error")
          return callback(new Error( (response && response.statusCode) + " "+
            "Could not create user "+error+'\n'+JSON.stringify(data)))
        }
        callback()
      }
    )
}
<|endoftext|>


<commit_before>/**
 * Video.js Resolution Selector
 *
 * This plugin for Video.js adds a resolution selector option
 * to the toolbar. Usage:
 *
 * <video>
 * 	<source data-res="480" src="..." />
 * 	<source data-res="240" src="..." />
 * </video>
 */

(function (_V_) {

    /***********************************************************************************
     * Define some helper functions
     ***********************************************************************************/
    var methods = {

        /**
         * In a future version, this can be made more intelligent,
         * but for now, we'll just add a "p" at the end if we are passed
         * numbers.
         *
         * @param	(string)	res	The resolution to make a label for
         *
         * @returns	(string)	The label text string
         */
        res_label: function (res) {

            return (/^\d+$/.test(res)) ? res + 'p' : res;
        }
    };

    /***********************************************************************************
     * Setup our resolution menu items
     ***********************************************************************************/
    _V_.ResolutionMenuItem = _V_.MenuItem.extend({

        // Call variable to prevent the resolution change from being called twice
        call_count: 0,

        /** @constructor */
        init: function (player, options) {

            var touchstart = false;

            // Modify options for parent MenuItem class's init.
            options.label = methods.res_label(options.res);
            options.selected = (options.res.toString() === player.getCurrentRes().toString());

            // Call the parent constructor
            _V_.MenuItem.call(this, player, options);

            // Store the resolution as a property
            this.resolution = options.res;

            // Register our click and tap handlers
            this.on(['click', 'tap'], this.onClick);

            // Toggle the selected class whenever the resolution changes
            player.on('changeRes', _V_.bind(this, function () {

                if (this.resolution == player.getCurrentRes()) {

                    this.selected(true);

                } else {

                    this.selected(false);
                }

                // Reset the call count
                this.call_count = 0;
            }));
        }
    });

    // Handle clicks on the menu items
    _V_.ResolutionMenuItem.prototype.onClick = function () {

        // Check if this has already been called
        if (this.call_count > 0) {
            return;
        }

        // Call the player.changeRes method
        this.player().changeRes(this.resolution);

        // Increment the call counter
        this.call_count++;
    };

    /***********************************************************************************
     * Setup our resolution menu title item
     ***********************************************************************************/
    _V_.ResolutionTitleMenuItem = _V_.MenuItem.extend({

        init: function (player, options) {

            // Call the parent constructor
            _V_.MenuItem.call(this, player, options);

            // No click handler for the menu title
            this.off('click');
        }
    });

    /***********************************************************************************
     * Define our resolution selector button
     ***********************************************************************************/
    _V_.ResolutionSelector = _V_.MenuButton.extend({

        /** @constructor */
        init: function (player, options) {

            // Add our list of available resolutions to the player object
            player.availableRes = options.available_res;

            // Call the parent constructor
            _V_.MenuButton.call(this, player, options);

            // Set the button text based on the option provided
            this.el().firstChild.firstChild.innerHTML = options.buttonText;
        }
    });

    // Set class for resolution selector button
    _V_.ResolutionSelector.prototype.className = 'vjs-res-button';

    // Create a menu item for each available resolution
    _V_.ResolutionSelector.prototype.createItems = function () {

        var player = this.player(),
            items = [],
            current_res;

        // Add the menu title item
        items.push(new _V_.ResolutionTitleMenuItem(player, {

            el: _V_.Component.prototype.createEl('li', {

                className: 'vjs-menu-title vjs-res-menu-title',
                innerHTML: player.localize('Quality')
            })
        }));

        // Add an item for each available resolution
        for (current_res in player.availableRes) {

            // Don't add an item for the length attribute
            if ('length' == current_res) {
                continue;
            }

            items.push(new _V_.ResolutionMenuItem(player, {
                res: current_res
            }));
        }

        // Sort the available resolutions in descending order
        items.sort(function (a, b) {

            if (typeof a.resolution == 'undefined') {

                return -1;

            } else {

                return parseInt(b.resolution) - parseInt(a.resolution);
            }
        });

        return items;
    };

    /***********************************************************************************
     * Register the plugin with videojs, main plugin function
     ***********************************************************************************/
    _V_.plugin('resolutionSelector', function (options) {

        // Only enable the plugin on HTML5 videos
        if (!this.el().firstChild.canPlayType) {
            return;
        }

        /*******************************************************************
         * Setup variables, parse settings
         *******************************************************************/
        var player = this,
            sources = player.options().sources,
            i = sources.length,
            j,
            found_type,

            // Override default options with those provided
            settings = _V_.util.mergeOptions({

                default_res: '', // (string)	The resolution that should be selected by default ( '480' or  '480,1080,240' )
                force_types: false // (array)	List of media types. If passed, we need to have source for each type in each resolution or that resolution will not be an option

            }, options || {}),

            available_res = {
                length: 0
            },
            current_res,
            resolutionSelector,

            // Split default resolutions if set and valid, otherwise default to an empty array
            default_resolutions = (settings.default_res && typeof settings.default_res == 'string') ? settings.default_res.split(',') : [];

        // Get all of the available resoloutions
        while (i > 0) {

            i--;

            // Skip sources that don't have data-res attributes
            if (!sources[i]['data-res']) {
                continue;
            }

            current_res = sources[i]['data-res'];

            if (typeof available_res[current_res] !== 'object') {

                available_res[current_res] = [];
                available_res.length++;
            }

            available_res[current_res].push(sources[i]);
        }

        // Check for forced types
        if (settings.force_types) {

            // Loop through all available resoultions
            for (current_res in available_res) {

                // Don't count the length property as a resolution
                if ('length' == current_res) {
                    continue;
                }

                i = settings.force_types.length;
                found_types = 0;

                // Loop through all required types
                while (i > 0) {

                    i--;

                    j = available_res[current_res].length;

                    // Loop through all available sources in current resolution
                    while (j > 0) {

                        j--;

                        // Check if the current source matches the current type we're checking
                        if (settings.force_types[i] === available_res[current_res][j].type) {

                            found_types++;
                            break;
                        }
                    }
                }

                // If we didn't find sources for all of the required types in the current res, remove it
                if (found_types < settings.force_types.length) {

                    delete available_res[current_res];
                    available_res.length--;
                }
            }
        }

        // Make sure we have at least 2 available resolutions before we add the button
        if (available_res.length < 2) {
            return;
        }

        // Loop through the choosen default resolutions if there were any
        for (i = 0; i < default_resolutions.length; i++) {

            // Set the video to start out with the first available default res
            if (available_res[default_resolutions[i]]) {

                player.src(available_res[default_resolutions[i]]);
                player.currentRes = default_resolutions[i];
                break;
            }
        }

        /*******************************************************************
         * Add methods to player object
         *******************************************************************/

        // Make sure we have player.localize() if it's not defined by Video.js
        if (typeof player.localize !== 'function') {

            player.localize = function (string) {

                return string;
            };
        }

        // Helper function to get the current resolution
        player.getCurrentRes = function () {

            if (typeof player.currentRes !== 'undefined') {

                return player.currentRes;

            } else {

                try {

                    return res = player.options().sources[0]['data-res'];

                } catch (e) {

                    return '';
                }
            }
        };

        // Define the change res method
        player.changeRes = function (target_resolution) {

            var video_el = player.el().firstChild,
                is_paused = player.paused(),
                current_time = player.currentTime(),
                button_nodes,
                button_node_count;

            // Do nothing if we aren't changing resolutions or if the resolution isn't defined
            if (player.getCurrentRes() == target_resolution || !player.availableRes || !player.availableRes[target_resolution]) {
                return;
            }

            // Make sure the loadedmetadata event will fire
            if ('none' == video_el.preload) {
                video_el.preload = 'metadata';
            }

            // Change the source and make sure we don't start the video over
            player.src(player.availableRes[target_resolution]).one('loadedmetadata', function () {

                player.currentTime(current_time);

                // If the video was paused, don't show the poster image again
                player.addClass('vjs-has-started');

                if (!is_paused) {
                    player.play();
                }
            });

            // Save the newly selected resolution in our player options property
            player.currentRes = target_resolution;

            // Make sure the button has been added to the control bar
            if (player.controlBar.resolutionSelector) {

                button_nodes = player.controlBar.resolutionSelector.el().firstChild.children;
                button_node_count = button_nodes.length;

                // Update the button text
                while (button_node_count > 0) {

                    button_node_count--;

                    if ('vjs-control-text' == button_nodes[button_node_count].className) {

                        button_nodes[button_node_count].innerHTML = methods.res_label(target_resolution);
                        break;
                    }
                }
            }

            // Update the classes to reflect the currently selected resolution
            player.trigger('changeRes');
        };

        /*******************************************************************
         * Add the resolution selector button
         *******************************************************************/

        // Get the starting resolution
        current_res = player.getCurrentRes();

        if (current_res) {
            current_res = methods.res_label(current_res);
        }

        // Add the resolution selector button
        resolutionSelector = new _V_.ResolutionSelector(player, {
            buttonText: player.localize(current_res || 'Quality'),
            available_res: available_res
        });

        // Add the button to the control bar object and the DOM
        player.controlBar.resolutionSelector = player.controlBar.addChild(resolutionSelector);
    });

})(videojs);<commit_msg>More code cleanup<commit_after>/**
 * Video.js Resolution Selector
 *
 * This plugin for Video.js adds a resolution selector option
 * to the toolbar. Usage:
 *
 * <video>
 * 	<source data-res="480" src="..." />
 * 	<source data-res="240" src="..." />
 * </video>
 */

(function( _V_ ) {

	/***********************************************************************************
	 * Define some helper functions
	 ***********************************************************************************/
	var methods = {

		/**
		 * In a future version, this can be made more intelligent,
		 * but for now, we'll just add a "p" at the end if we are passed
		 * numbers.
		 *
		 * @param	(string)	res	The resolution to make a label for
		 *
		 * @returns	(string)	The label text string
		 */
		res_label : function( res ) {

			return ( /^\d+$/.test( res ) ) ? res + 'p' : res;
		}
	};

	/***********************************************************************************
	 * Setup our resolution menu items
	 ***********************************************************************************/
	_V_.ResolutionMenuItem = _V_.MenuItem.extend({

		// Call variable to prevent the resolution change from being called twice
		call_count : 0,

		/** @constructor */
		init : function( player, options ){

			var touchstart = false;

			// Modify options for parent MenuItem class's init.
			options.label = methods.res_label( options.res );
			options.selected = ( options.res.toString() === player.getCurrentRes().toString() );

			// Call the parent constructor
			_V_.MenuItem.call( this, player, options );

			// Store the resolution as a property
			this.resolution = options.res;

			// Register our click and tap handlers
			this.on( ['click', 'tap'], this.onClick );

			// Toggle the selected class whenever the resolution changes
			player.on( 'changeRes', _V_.bind( this, function() {

				if ( this.resolution == player.getCurrentRes() ) {

					this.selected( true );

				} else {

					this.selected( false );
				}

				// Reset the call count
				this.call_count = 0;
			}));
		}
	});

	// Handle clicks on the menu items
	_V_.ResolutionMenuItem.prototype.onClick = function() {

		// Check if this has already been called
		if ( this.call_count > 0 ) { return; }

		// Call the player.changeRes method
		this.player().changeRes( this.resolution );

		// Increment the call counter
		this.call_count++;
	};

	/***********************************************************************************
	 * Setup our resolution menu title item
	 ***********************************************************************************/
	_V_.ResolutionTitleMenuItem = _V_.MenuItem.extend({

		init : function( player, options ) {

			// Call the parent constructor
			_V_.MenuItem.call( this, player, options );

			// No click handler for the menu title
			this.off( 'click' );
		}
	});

	/***********************************************************************************
	 * Define our resolution selector button
	 ***********************************************************************************/
	_V_.ResolutionSelector = _V_.MenuButton.extend({

		/** @constructor */
		init : function( player, options ) {

			// Add our list of available resolutions to the player object
			player.availableRes = options.available_res;

			// Call the parent constructor
			_V_.MenuButton.call( this, player, options );

			// Set the button text based on the option provided
			this.el().firstChild.firstChild.innerHTML = options.buttonText;
		}
	});

	// Set class for resolution selector button
	_V_.ResolutionSelector.prototype.className = 'vjs-res-button';

	// Create a menu item for each available resolution
	_V_.ResolutionSelector.prototype.createItems = function() {

		var player = this.player(),
			items = [],
			current_res;

		// Add the menu title item
		items.push( new _V_.ResolutionTitleMenuItem( player, {

			el : _V_.Component.prototype.createEl( 'li', {

				className	: 'vjs-menu-title vjs-res-menu-title',
				innerHTML	: player.localize( 'Quality' )
			})
		}));

		// Add an item for each available resolution
		for ( current_res in player.availableRes ) {

			// Don't add an item for the length attribute
			if ( 'length' == current_res ) { continue; }

			items.push( new _V_.ResolutionMenuItem( player, {
				res : current_res
			}));
		}

		// Sort the available resolutions in descending order
		items.sort(function( a, b ) {

			if ( typeof a.resolution == 'undefined' ) {

				return -1;

			} else {

				return parseInt( b.resolution ) - parseInt( a.resolution );
			}
		});

		return items;
	};

	/***********************************************************************************
	 * Register the plugin with videojs, main plugin function
	 ***********************************************************************************/
	_V_.plugin( 'resolutionSelector', function( options ) {

		// Only enable the plugin on HTML5 videos
		if ( ! this.el().firstChild.canPlayType  ) { return; }

		/*******************************************************************
		 * Setup variables, parse settings
		 *******************************************************************/
		var player = this,
			sources	= player.options().sources,
			i = sources.length,
			j,
			found_type,

			// Override default options with those provided
			settings = _V_.util.mergeOptions({

				default_res	: '',		// (string)	The resolution that should be selected by default ( '480' or  '480,1080,240' )
				force_types	: false		// (array)	List of media types. If passed, we need to have source for each type in each resolution or that resolution will not be an option

			}, options || {} ),

			available_res = { length : 0 },
			current_res,
			resolutionSelector,

			// Split default resolutions if set and valid, otherwise default to an empty array
			default_resolutions = ( settings.default_res && typeof settings.default_res == 'string' ) ? settings.default_res.split( ',' ) : [];

		// Get all of the available resoloutions
		while ( i > 0 ) {

			i--;

			// Skip sources that don't have data-res attributes
			if ( ! sources[i]['data-res'] ) { continue; }

			current_res = sources[i]['data-res'];

			if ( typeof available_res[current_res] !== 'object' ) {

				available_res[current_res] = [];
				available_res.length++;
			}

			available_res[current_res].push( sources[i] );
		}

		// Check for forced types
		if ( settings.force_types ) {

			// Loop through all available resoultions
			for ( current_res in available_res ) {

				// Don't count the length property as a resolution
				if ( 'length' == current_res ) { continue; }

				i = settings.force_types.length;
				found_types = 0;

				// Loop through all required types
				while ( i > 0 ) {

					i--;

					j = available_res[current_res].length;

					// Loop through all available sources in current resolution
					while ( j > 0 ) {

						j--;

						// Check if the current source matches the current type we're checking
						if ( settings.force_types[i] === available_res[current_res][j].type ) {

							found_types++;
							break;
						}
					}
				}

				// If we didn't find sources for all of the required types in the current res, remove it
				if ( found_types < settings.force_types.length ) {

					delete available_res[current_res];
					available_res.length--;
				}
			}
		}

		// Make sure we have at least 2 available resolutions before we add the button
		if ( available_res.length < 2 ) { return; }

		// Loop through the choosen default resolutions if there were any
		for ( i = 0; i < default_resolutions.length; i++ ) {

			// Set the video to start out with the first available default res
			if ( available_res[default_resolutions[i]] ) {

				player.src( available_res[default_resolutions[i]] );
				player.currentRes = default_resolutions[i];
				break;
			}
		}

		/*******************************************************************
		 * Add methods to player object
		 *******************************************************************/

		// Make sure we have player.localize() if it's not defined by Video.js
		if ( typeof player.localize !== 'function' ) {

			player.localize = function( string ) {

				return string;
			};
		}

		// Helper function to get the current resolution
		player.getCurrentRes = function() {

			if ( typeof player.currentRes !== 'undefined' ) {

				return player.currentRes;

			} else {

				try {

					return res = player.options().sources[0]['data-res'];

				} catch(e) {

					return '';
				}
			}
		};

		// Define the change res method
		player.changeRes = function( target_resolution ) {

			var video_el = player.el().firstChild,
				is_paused = player.paused(),
				current_time = player.currentTime(),
				button_nodes,
				button_node_count;

			// Do nothing if we aren't changing resolutions or if the resolution isn't defined
			if ( player.getCurrentRes() == target_resolution
				|| ! player.availableRes
				|| ! player.availableRes[target_resolution] ) { return; }

			// Make sure the loadedmetadata event will fire
			if ( 'none' == video_el.preload ) { video_el.preload = 'metadata'; }

			// Change the source and make sure we don't start the video over
			player.src( player.availableRes[target_resolution] ).one( 'loadedmetadata', function() {

				player.currentTime( current_time );

				// If the video was paused, don't show the poster image again
				player.addClass( 'vjs-has-started' );

				if ( ! is_paused ) { player.play(); }
			});

			// Save the newly selected resolution in our player options property
			player.currentRes = target_resolution;

			// Make sure the button has been added to the control bar
			if ( player.controlBar.resolutionSelector ) {

				button_nodes = player.controlBar.resolutionSelector.el().firstChild.children;
				button_node_count = button_nodes.length;

				// Update the button text
				while ( button_node_count > 0 ) {

					button_node_count--;

					if ( 'vjs-control-text' == button_nodes[button_node_count].className ) {

						button_nodes[button_node_count].innerHTML = methods.res_label( target_resolution );
						break;
					}
				}
			}

			// Update the classes to reflect the currently selected resolution
			player.trigger( 'changeRes' );
		};

		/*******************************************************************
		 * Add the resolution selector button
		 *******************************************************************/

		// Get the starting resolution
		current_res = player.getCurrentRes();

		if ( current_res ) { current_res = methods.res_label( current_res ); }

		// Add the resolution selector button
		resolutionSelector = new _V_.ResolutionSelector( player, {
			buttonText		: player.localize( current_res || 'Quality' ),
			available_res	: available_res
		});

		// Add the button to the control bar object and the DOM
		player.controlBar.resolutionSelector = player.controlBar.addChild( resolutionSelector );
	});

})( videojs );<|endoftext|>


<commit_before>const zoomControl = require('map-zoom-control');

const images = require('./images');
const object = require('./object');
const updater = require('./updater');
const util = require('./util');
const makeFeatureEventHandler = require('./feature-event-handler');
const query = require('./query');

module.exports = map;

/* global mapboxgl */

function customControl(options) {
  return {
    onAdd(map) {
      const ctrl = this;
      ctrl._map = map;
      ctrl._container = document.createElement('div');
      ctrl._container.className = 'mapboxgl-ctrl';
      if (options.el) {
        ctrl._container.appendChild(options.el);
      }
      if (options.onAdd) {
        options.onAdd.call(ctrl, map);
      }
      return ctrl._container;
    },
    onRemove() {
      const ctrl = this;
      if (options.el) {
        ctrl._container.removeChild(options.el);
      }
      if (options.onRemove) {
        options.onRemove.call(ctrl);
      }
      ctrl._container.parentNode.removeChild(ctrl._container);
      delete ctrl._container;
      delete ctrl._map;
    }
  };
}

function mapTypeControl(mapTypeControlOptions, customMapTypes, fn) {
  return customControl({
    onAdd() {
      const ctrl = this;
      ctrl._events = [];
      mapTypeControlOptions.mapTypeIds.forEach(function (id) {
        const type = ctrl._container.appendChild(document.createElement('div'));
        const ev = {
          el: type,
          event: 'click',
          fn: fn.bind(undefined, id)
        };
        type.className = 'map-type';
        type.innerHTML = `<div>${customMapTypes[id].name}</div>`;
        type.addEventListener(ev.event, ev.fn);
        ctrl._events.push(ev);
      });
    },
    onRemove() {
      const ctrl = this;
      ctrl._events.forEach(ev => ev.type.removeEventListener(ev.event, ev.fn));
      delete ctrl._events;
    }
  });
}

function getAttribution(style) {
  if (!style) {
    return [];
  }
  let sourceCaches = style.sourceCaches;
  let attributions = Object.values(sourceCaches).reduce(function (attributions, sourceCache) {
    const source = sourceCache.getSource();
    if (source.attribution && attributions.indexOf(source.attribution) < 0) {
      attributions.push(source.attribution);
    }
    return attributions;
  }, []);

  // remove any entries that are substrings of another entry.
  // first sort by length so that substrings come first
  attributions.sort((a, b) => a.length - b.length);
  attributions = attributions.filter(function (attrib, i) {
    for (let j = i + 1; j < attributions.length; j += 1) {
      if (attributions[j].indexOf(attrib) >= 0) {
        return false;
      }
    }
    return true;
  });
  return attributions.join(' ');
}

function transition(prop) {
  const _m = this;
  _m[prop] = Object.assign(function (options) {
    if (options.zoom) {
      options.zoom = Math.floor(options.zoom);
    }
    _m[prop].superior.apply(this, arguments);
  }, {
    superior: _m[prop]
  });
}

function mapUnits(units) {
  return units === 'km' ? 'metric' : 'imperial';
}

function map(node, options) {
  const controlPosition = {
    BL: 'bottom-left',
    LB: 'bottom-left',
    BR: 'bottom-right',
    RB: 'bottom-right',
    TL: 'top-left',
    LT: 'top-left',
    TR: 'top-right',
    RT: 'top-right'
  };

  let self;
  let mapTypeId;
  let styles;

  function element() {
    return node;
  }

  function center(c) {
    if (!c) {
      return util.mll2ll(self._m.getCenter());
    }
    self._m.setCenter(c);
  }

  function zoom(z) {
    if (z === undefined) {
      return Math.round(self._m.getZoom() + 1);
    }
    self._m[self._m.isStyleLoaded() ? 'zoomTo' : 'setZoom'](z - 1);
  }

  function bounds(b) {
    if (b === undefined) {
      return util.mbounds2bounds(self._m.getBounds());
    }
    let opt = {
      padding: 100
    };
    if (!self._m.isStyleLoaded()) {
      opt.animate = false;
    }
    self._m.fitBounds(b, opt);
  }

  function panToBounds(bounds) {
    // display north-west corner
    self._m.panTo([bounds[1][0], bounds[0][1]]);
    return self;
  }

  function panBy(x, y) {
    self._m.panBy([x, y]);
    return self;
  }

  function mapType() {
    return mapTypeId;
  }

  function refresh(source) {
    if (!source) {
      return self._m.resize();
    }
    var layers = [];
    layers.source = source;
    layers._layers = self._m.style._layers;
    layers = self._m.style._order.reduce(function (result, key, i, layers) {
      var layer = result._layers[key];
      if (layer.source === result.source) {
        result.unshift({
          layer: layer.serialize(),
          before: layers[i + 1]
        });
      }
      return result;
    }, layers);
    layers.forEach(function ({ layer }) {
      self._m.removeLayer(layer.id);
    });
    var sourceDef = self._m.getSource(source).serialize();
    self._m.removeSource(source);
    self._m.addSource(source, sourceDef);
    layers.forEach(function ({ layer, before }) {
      self._m.addLayer(layer, before);
    });
  }

  function addStyle(style) {
    if (!self._m.getLayer(style.id)) {
      self._m.addLayer(style, style.metadata && style.metadata.replace);
    }
  }

  function removeStyle(style) {
    if (self._m.getLayer(style.id)) {
      self._m.removeLayer(style.id);
    }
  }

  function applyUnits(units) {
    styles[units].forEach(addStyle);
    styles[units === 'metric' ? 'imperial' : 'metric'].forEach(removeStyle);
  }

  function setVisibility(style) {
    var visibility = this;
    if (self._m.getLayer(style.layer.id)) {
      self._m.setLayoutProperty(style.layer.id, 'visibility',
          style.visibility(visibility) ? 'visible' : 'none');
    }
  }

  function applyVisibility(visibility) {
    styles.visibility.forEach(setVisibility, visibility);
  }

  function checkSingleProperty(property, object) {
    return object[property];
  }

  function checkProperty(property) {
    var object = this;
    return checkSingleProperty(property, object);
  }

  function checkAnyProperty(properties, object) {
    return properties.some(checkProperty, object);
  }

  function checkAllProperties(properties, object) {
    return properties.every(checkProperty, object);
  }

  function initStyles() {
    if (!styles) {
      let style = self._m.getStyle();
      if (style.layers) {
        styles = style.layers.reduce((result, layer) => {
          if (layer.metadata) {
            if (layer.metadata.units === 'metric') {
              result.metric.push(layer);
            }
            else if (layer.metadata.units === 'imperial') {
              result.imperial.push(layer);
            }
            if (layer.metadata.visibility) {
              var visibility;
              if (Array.isArray(layer.metadata.visibility)) {
                if (layer.metadata.visibility[0] === 'all') {
                  visibility = checkAllProperties.bind(undefined, layer.metadata.visibility.slice(1));
                }
                else {
                  visibility = checkAnyProperty.bind(undefined, layer.metadata.visibility.slice(1));
                }
              }
              else {
                visibility = checkSingleProperty.bind(undefined, layer.metadata.visibility);
              }
              result.visibility.push({
                layer,
                visibility
              });
            }
            if (layer.metadata.zindex) {
              let zi = layer.metadata.zindex;
              self._layers[zi] = self._layers[zi] || [];
              self._layers[zi].unshift(layer);
            }
          }
          if (layer['source-layer'] === 'poi') {
            result.poi.push(layer.id);
          }
          return result;
        }, {
          metric: [],
          imperial: [],
          poi: [],
          visibility: []
        });
        if (options.units) {
          applyUnits(mapUnits(options.units));
        }
        applyVisibility(options.visibility);
      }
    }
  }

  function callback(e) {
    if (e.dataType === 'style') {
      initStyles();
      if (options.onReady) {
        options.onReady(self);
      }
    }
  }

  function addControl(el, position) {
    self._m.addControl(customControl({
      el
    }), controlPosition[position]);
    return self;
  }

  function ll(e) {
    if (e && e.lngLat) {
      e.ll = util.mll2ll(e.lngLat);
    }
  }

  function queryRenderedFeatures(point, options = {}) {
    if (options.layers === undefined && styles) {
      options.layers = styles.poi;
    }
    return query(self._m, point, 3, options).map(({ properties }) => properties);
  }

  function units(u) {
    if (u === undefined) {
      return options.units;
    }
    options.units = u;
    let units = mapUnits(options.units);
    applyUnits(units);
  }

  function visibility(key, value) {
    if (key === undefined) {
      return options.visibility;
    }
    if (typeof key === 'object') {
      options.visibility = key;
    }
    else {
      options.visibility[key] = value;
    }
    applyVisibility(options.visibility);
  }

  function destroy() {
    if (self._updater) {
      self._updater.destroy();
      delete self._updater;
    }
    if (self._m) {
      self.off();
      self._m.remove();
      self._images.destroy();
      delete self._m;
      delete self._images;
      delete self._layers;
    }
    styles = undefined;
  }

  options = Object.assign({
    mapboxgl,
    container: node,
    mapTypeControl: false,
    style: {
      version: 8,
      sources: {},
      layers: []
    },
    visibility: {}
  }, options);

  self = object({
    addControl,
    bounds,
    center,
    destroy,
    element,
    fitBounds: bounds, // obsolete; use bounds(b)
    ll,
    mapType,
    panBy,
    panToBounds,
    queryRenderedFeatures,
    refresh,
    units,
    visibility,
    zoom
  });

  if (options.zoom) {
    options.zoom -= 1;
  }
  if (options.minZoom) {
    options.minZoom -= 1;
  }
  if (options.maxZoom) {
    options.maxZoom -= 1;
  }

  [
    'mapTypeControlOptions',
    'zoomControlOptions',
    'fullscreenControlOptions'
  ].forEach(function(ctrlOptions) {
    ctrlOptions = options[ctrlOptions];
    if (ctrlOptions && ctrlOptions.position) {
      ctrlOptions.position = controlPosition[ctrlOptions.position] || ctrlOptions.position;
    }
  });

  self._m = new options.mapboxgl.Map(options);
  self._m.touchZoomRotate.disableRotation();
  self._featureEventHandler = makeFeatureEventHandler(self._m);
  self._images = images();
  self._layers = {};
  self._updater = updater();

  // ensure integral zoom
  ['flyTo', 'easeTo'].forEach(transition, self._m);

  self._m.once('styledata', callback);

  if (options.mapTypeControl) {
    self._m.addControl(mapTypeControl(options.mapTypeControlOptions, options.customMapTypes, function(id) {
      mapTypeId = id;
      self._m.fire('maptypeid_changed');
    }), (options.mapTypeControlOptions && options.mapTypeControlOptions.position) || 'bottom-left');
  }
  if (options.zoomControl) {
    self._m.addControl(zoomControl(),
        (options.zoomControlOptions && options.zoomControlOptions.position) || 'bottom-right');
  }
  if (options.attribution) {
    self._m.on('data', function (event) {
      if (event.dataType !== 'source') {
        return;
      }
      const attribution = getAttribution(event.style);
      if (typeof options.attribution === 'function') {
        return options.attribution((attribution.match(/href="[^"]+/g) || []).map(function (attr) {
          attr = attr.slice(6);
          attr = attr.match(/(?:http:|https:)?\/\/([^\/?]+)/);
          if (attr) {
            attr = attr[1].split('.');
            if (attr.length > 1) {
              attr = attr[attr.length - 2];
            }
          }
          return attr;
        }));
      }
      options.attribution.innerHTML = attribution;
    });
  }
  return self;
}
<commit_msg>remove `units` as unnecessary<commit_after>const zoomControl = require('map-zoom-control');

const images = require('./images');
const object = require('./object');
const updater = require('./updater');
const util = require('./util');
const makeFeatureEventHandler = require('./feature-event-handler');
const query = require('./query');

module.exports = map;

/* global mapboxgl */

function customControl(options) {
  return {
    onAdd(map) {
      const ctrl = this;
      ctrl._map = map;
      ctrl._container = document.createElement('div');
      ctrl._container.className = 'mapboxgl-ctrl';
      if (options.el) {
        ctrl._container.appendChild(options.el);
      }
      if (options.onAdd) {
        options.onAdd.call(ctrl, map);
      }
      return ctrl._container;
    },
    onRemove() {
      const ctrl = this;
      if (options.el) {
        ctrl._container.removeChild(options.el);
      }
      if (options.onRemove) {
        options.onRemove.call(ctrl);
      }
      ctrl._container.parentNode.removeChild(ctrl._container);
      delete ctrl._container;
      delete ctrl._map;
    }
  };
}

function mapTypeControl(mapTypeControlOptions, customMapTypes, fn) {
  return customControl({
    onAdd() {
      const ctrl = this;
      ctrl._events = [];
      mapTypeControlOptions.mapTypeIds.forEach(function (id) {
        const type = ctrl._container.appendChild(document.createElement('div'));
        const ev = {
          el: type,
          event: 'click',
          fn: fn.bind(undefined, id)
        };
        type.className = 'map-type';
        type.innerHTML = `<div>${customMapTypes[id].name}</div>`;
        type.addEventListener(ev.event, ev.fn);
        ctrl._events.push(ev);
      });
    },
    onRemove() {
      const ctrl = this;
      ctrl._events.forEach(ev => ev.type.removeEventListener(ev.event, ev.fn));
      delete ctrl._events;
    }
  });
}

function getAttribution(style) {
  if (!style) {
    return [];
  }
  let sourceCaches = style.sourceCaches;
  let attributions = Object.values(sourceCaches).reduce(function (attributions, sourceCache) {
    const source = sourceCache.getSource();
    if (source.attribution && attributions.indexOf(source.attribution) < 0) {
      attributions.push(source.attribution);
    }
    return attributions;
  }, []);

  // remove any entries that are substrings of another entry.
  // first sort by length so that substrings come first
  attributions.sort((a, b) => a.length - b.length);
  attributions = attributions.filter(function (attrib, i) {
    for (let j = i + 1; j < attributions.length; j += 1) {
      if (attributions[j].indexOf(attrib) >= 0) {
        return false;
      }
    }
    return true;
  });
  return attributions.join(' ');
}

function transition(prop) {
  const _m = this;
  _m[prop] = Object.assign(function (options) {
    if (options.zoom) {
      options.zoom = Math.floor(options.zoom);
    }
    _m[prop].superior.apply(this, arguments);
  }, {
    superior: _m[prop]
  });
}

function map(node, options) {
  const controlPosition = {
    BL: 'bottom-left',
    LB: 'bottom-left',
    BR: 'bottom-right',
    RB: 'bottom-right',
    TL: 'top-left',
    LT: 'top-left',
    TR: 'top-right',
    RT: 'top-right'
  };

  let self;
  let mapTypeId;
  let styles;

  function element() {
    return node;
  }

  function center(c) {
    if (!c) {
      return util.mll2ll(self._m.getCenter());
    }
    self._m.setCenter(c);
  }

  function zoom(z) {
    if (z === undefined) {
      return Math.round(self._m.getZoom() + 1);
    }
    self._m[self._m.isStyleLoaded() ? 'zoomTo' : 'setZoom'](z - 1);
  }

  function bounds(b) {
    if (b === undefined) {
      return util.mbounds2bounds(self._m.getBounds());
    }
    let opt = {
      padding: 100
    };
    if (!self._m.isStyleLoaded()) {
      opt.animate = false;
    }
    self._m.fitBounds(b, opt);
  }

  function panToBounds(bounds) {
    // display north-west corner
    self._m.panTo([bounds[1][0], bounds[0][1]]);
    return self;
  }

  function panBy(x, y) {
    self._m.panBy([x, y]);
    return self;
  }

  function mapType() {
    return mapTypeId;
  }

  function refresh(source) {
    if (!source) {
      return self._m.resize();
    }
    var layers = [];
    layers.source = source;
    layers._layers = self._m.style._layers;
    layers = self._m.style._order.reduce(function (result, key, i, layers) {
      var layer = result._layers[key];
      if (layer.source === result.source) {
        result.unshift({
          layer: layer.serialize(),
          before: layers[i + 1]
        });
      }
      return result;
    }, layers);
    layers.forEach(function ({ layer }) {
      self._m.removeLayer(layer.id);
    });
    var sourceDef = self._m.getSource(source).serialize();
    self._m.removeSource(source);
    self._m.addSource(source, sourceDef);
    layers.forEach(function ({ layer, before }) {
      self._m.addLayer(layer, before);
    });
  }

  function setVisibility(style) {
    var visibility = this;
    if (self._m.getLayer(style.layer.id)) {
      self._m.setLayoutProperty(style.layer.id, 'visibility',
          style.visibility(visibility) ? 'visible' : 'none');
    }
  }

  function applyVisibility(visibility) {
    styles.visibility.forEach(setVisibility, visibility);
  }

  function checkSingleProperty(property, object) {
    return object[property];
  }

  function checkProperty(property) {
    var object = this;
    return checkSingleProperty(property, object);
  }

  function checkAnyProperty(properties, object) {
    return properties.some(checkProperty, object);
  }

  function checkAllProperties(properties, object) {
    return properties.every(checkProperty, object);
  }

  function initStyles() {
    if (!styles) {
      let style = self._m.getStyle();
      if (style.layers) {
        styles = style.layers.reduce((result, layer) => {
          if (layer.metadata) {
            if (layer.metadata.visibility) {
              var visibility;
              if (Array.isArray(layer.metadata.visibility)) {
                if (layer.metadata.visibility[0] === 'all') {
                  visibility = checkAllProperties.bind(undefined, layer.metadata.visibility.slice(1));
                }
                else {
                  visibility = checkAnyProperty.bind(undefined, layer.metadata.visibility.slice(1));
                }
              }
              else {
                visibility = checkSingleProperty.bind(undefined, layer.metadata.visibility);
              }
              result.visibility.push({
                layer,
                visibility
              });
            }
            if (layer.metadata.zindex) {
              let zi = layer.metadata.zindex;
              self._layers[zi] = self._layers[zi] || [];
              self._layers[zi].unshift(layer);
            }
          }
          if (layer['source-layer'] === 'poi') {
            result.poi.push(layer.id);
          }
          return result;
        }, {
          poi: [],
          visibility: []
        });
        applyVisibility(options.visibility);
      }
    }
  }

  function callback(e) {
    if (e.dataType === 'style') {
      initStyles();
      if (options.onReady) {
        options.onReady(self);
      }
    }
  }

  function addControl(el, position) {
    self._m.addControl(customControl({
      el
    }), controlPosition[position]);
    return self;
  }

  function ll(e) {
    if (e && e.lngLat) {
      e.ll = util.mll2ll(e.lngLat);
    }
  }

  function queryRenderedFeatures(point, options = {}) {
    if (options.layers === undefined && styles) {
      options.layers = styles.poi;
    }
    return query(self._m, point, 3, options).map(({ properties }) => properties);
  }

  function visibility(key, value) {
    if (key === undefined) {
      return options.visibility;
    }
    if (typeof key === 'object') {
      options.visibility = key;
    }
    else {
      options.visibility[key] = value;
    }
    applyVisibility(options.visibility);
  }

  function destroy() {
    if (self._updater) {
      self._updater.destroy();
      delete self._updater;
    }
    if (self._m) {
      self.off();
      self._m.remove();
      self._images.destroy();
      delete self._m;
      delete self._images;
      delete self._layers;
    }
    styles = undefined;
  }

  options = Object.assign({
    mapboxgl,
    container: node,
    mapTypeControl: false,
    style: {
      version: 8,
      sources: {},
      layers: []
    },
    visibility: {}
  }, options);

  self = object({
    addControl,
    bounds,
    center,
    destroy,
    element,
    fitBounds: bounds, // obsolete; use bounds(b)
    ll,
    mapType,
    panBy,
    panToBounds,
    queryRenderedFeatures,
    refresh,
    visibility,
    zoom
  });

  if (options.zoom) {
    options.zoom -= 1;
  }
  if (options.minZoom) {
    options.minZoom -= 1;
  }
  if (options.maxZoom) {
    options.maxZoom -= 1;
  }

  [
    'mapTypeControlOptions',
    'zoomControlOptions',
    'fullscreenControlOptions'
  ].forEach(function(ctrlOptions) {
    ctrlOptions = options[ctrlOptions];
    if (ctrlOptions && ctrlOptions.position) {
      ctrlOptions.position = controlPosition[ctrlOptions.position] || ctrlOptions.position;
    }
  });

  self._m = new options.mapboxgl.Map(options);
  self._m.touchZoomRotate.disableRotation();
  self._featureEventHandler = makeFeatureEventHandler(self._m);
  self._images = images();
  self._layers = {};
  self._updater = updater();

  // ensure integral zoom
  ['flyTo', 'easeTo'].forEach(transition, self._m);

  self._m.once('styledata', callback);

  if (options.mapTypeControl) {
    self._m.addControl(mapTypeControl(options.mapTypeControlOptions, options.customMapTypes, function(id) {
      mapTypeId = id;
      self._m.fire('maptypeid_changed');
    }), (options.mapTypeControlOptions && options.mapTypeControlOptions.position) || 'bottom-left');
  }
  if (options.zoomControl) {
    self._m.addControl(zoomControl(),
        (options.zoomControlOptions && options.zoomControlOptions.position) || 'bottom-right');
  }
  if (options.attribution) {
    self._m.on('data', function (event) {
      if (event.dataType !== 'source') {
        return;
      }
      const attribution = getAttribution(event.style);
      if (typeof options.attribution === 'function') {
        return options.attribution((attribution.match(/href="[^"]+/g) || []).map(function (attr) {
          attr = attr.slice(6);
          attr = attr.match(/(?:http:|https:)?\/\/([^\/?]+)/);
          if (attr) {
            attr = attr[1].split('.');
            if (attr.length > 1) {
              attr = attr[attr.length - 2];
            }
          }
          return attr;
        }));
      }
      options.attribution.innerHTML = attribution;
    });
  }
  return self;
}
<|endoftext|>


<commit_before>const util = require('util');
const Event = require('../src/event').Event;

module.exports.JoinEvent = (function(superclass) {
  util.inherits(JoinEvent, superclass);
  function JoinEvent(channel, username) {
    var e = superclass.constructor.apply(this, {channel: channel, username: username});
    e.prototype.eventType = "twitch-chanel-join";
    return e;
  }
  return JoinEvent;
})(Event);

module.exports.PartEvent = (function(superclass) {
  util.inherits(PartEvent, superclass);
  function PartEvent(channel, username) {
    var e = superclass.constructor.apply(this, {channel: channel, username: username});
    e.prototype.eventType = "twitch-channel-part";
    return e;
  }
  return PartEvent;
})(Event);

module.exports.ChatEvent = (function(superclass) {
  util.inherits(ChatEvent, superclass);
  function ChatEvent(channel, username, message) {
    var e = superclass.constructor.apply(this, {channel: channel, username: username, message:message});
    e.prototype.eventType = "twitch-channel-chat";
    return e;
  }
  return ChatEvent;
})(Event);

module.exports.ActionEvent = (function(superclass) {
  util.inherits(ActionEvent, superclass);
  function ActionEvent(channel, username, message) {
    var e = superclass.constructor.apply(this, {channel: channel, username: username, message:message});
    e.prototype.eventType = "twitch-channel-action";
    return e;
  }
  return ActionEvent;
})(Event);

module.exports.HostEvent = (function(superclass) {
  util.inherits(HostEvent, superclass);
  function HostEvent(channel, username, count) {
    var e = superclass.constructor.apply(this, {channel: channel, username: username, viewers:count});
    e.prototype.eventType = "twitch-channel-host";
    return e;
  }
  return HostEvent;
})(Event);
<commit_msg>more event cleanup<commit_after>var Entity = require('../src/entity').Entity;
const util = require('util');

Event = (function(superclass) {
  util.inherits(Event, superclass);
  function Event(type, opts) {
    superclass.constructor.apply(this, uuid.v4(), opts);
  }
  Event.prototype.toObject = function() {
    return superclass.toObject();
  }
  return Event;
})(Entity);

module.exports.JoinEvent = (function(superclass) {
  util.inherits(JoinEvent, superclass);
  function JoinEvent(channel, username) {
    return superclass.constructor.apply(this, "twitch-chanel-join", {channel: channel, username: username});
  }
  return JoinEvent;
})(Event);

module.exports.PartEvent = (function(superclass) {
  util.inherits(PartEvent, superclass);
  function PartEvent(channel, username) {
    return superclass.constructor.apply(this, "twitch-chanel-part", {channel: channel, username: username});
  }
  return PartEvent;
})(Event);

module.exports.ChatEvent = (function(superclass) {
  util.inherits(ChatEvent, superclass);
  function ChatEvent(channel, username, message) {
    return superclass.constructor.apply(this, "twitch-channel-chat", {channel: channel, username: username, message:message});
  }
  return ChatEvent;
})(Event);

module.exports.ActionEvent = (function(superclass) {
  util.inherits(ActionEvent, superclass);
  function ActionEvent(channel, username, message) {
    return superclass.constructor.apply(this, "twitch-channel-action", {channel: channel, username: username, message:message});
  }
  return ActionEvent;
})(Event);

module.exports.HostEvent = (function(superclass) {
  util.inherits(HostEvent, superclass);
  function HostEvent(channel, username, count) {
    return superclass.constructor.apply(this, "twitch-channel-host", {channel: channel, username: username, viewers:count});
  }
  return HostEvent;
})(Event);
<|endoftext|>