<commit_before>(function (Handsontable) {
  var DateEditor = Handsontable.editors.TextEditor.prototype.extend();

  DateEditor.prototype.init = function () {
    if (typeof moment !== 'function') {
      throw new Error("You need to include moment.js to your project.");
    }

    if (typeof Pikaday !== 'function') {
      throw new Error("You need to include Pikaday to your project.");
    }

    Handsontable.editors.TextEditor.prototype.init.apply(this, arguments);

    this.isCellEdited = false;
    var that = this;

    this.instance.addHook('afterDestroy', function () {
      that.parentDestroyed = true;
      that.destroyElements();
    });
  };

  DateEditor.prototype.createElements = function () {
    var that = this;
    Handsontable.editors.TextEditor.prototype.createElements.apply(this, arguments);

    this.defaultDateFormat = 'DD/MM/YYYY';
    this.datePicker = document.createElement('DIV');
    this.datePickerStyle = this.datePicker.style;
    this.datePickerStyle.position = 'absolute';
    this.datePickerStyle.top = 0;
    this.datePickerStyle.left = 0;
    this.datePickerStyle.zIndex = 9999;

    Handsontable.Dom.addClass(this.datePicker, 'htDatepickerHolder');
    document.body.appendChild(this.datePicker);

    var htInput = this.instance.rootElement.querySelector('.handsontableInput');

    var defaultOptions = {
      format: that.defaultDateFormat,
      field: htInput,
      trigger: htInput,
      container: that.datePicker,
      reposition: false,
      bound: false,
      onSelect: function (dateStr) {
        if (!isNaN(dateStr.getTime())) {
          dateStr = moment(dateStr).format(that.cellProperties.dateFormat || that.defaultDateFormat);
        }
        that.setValue(dateStr);
        that.hideDatepicker();
      },
      onClose: function () {
        if(!that.parentDestroyed) {
          that.finishEditing(false);
        }
      }
    };

    this.$datePicker = new Pikaday(defaultOptions);

    var eventManager = Handsontable.eventManager(this);

    /**
     * Prevent recognizing clicking on datepicker as clicking outside of table
     */
    eventManager.addEventListener(this.datePicker, 'mousedown', function (event) {
      Handsontable.helper.stopPropagation(event);
    });

    this.hideDatepicker();
  };

  DateEditor.prototype.destroyElements = function () {
    this.$datePicker.destroy();
  };

  DateEditor.prototype.prepare = function () {
    this._opened = false;
    Handsontable.editors.TextEditor.prototype.prepare.apply(this, arguments);
  };

  DateEditor.prototype.open = function (event) {
    Handsontable.editors.TextEditor.prototype.open.call(this);
    this.showDatepicker(event);
  };

  DateEditor.prototype.close = function () {
    var that = this;
    this._opened = false;
    this.instance._registerTimeout(setTimeout(function () {
      that.instance.selection.refreshBorders();
    }, 0));

    Handsontable.editors.TextEditor.prototype.close.apply(this, arguments);
  };

  DateEditor.prototype.finishEditing = function (isCancelled, ctrlDown) {
    if (isCancelled) { // pressed ESC, restore original value
      //var value = this.instance.getDataAtCell(this.row, this.col);
      var value = this.originalValue;
      if (value !== void 0) {
        this.setValue(value);
      }
    }

    this.hideDatepicker();
    Handsontable.editors.TextEditor.prototype.finishEditing.apply(this, arguments);
  };

  DateEditor.prototype.showDatepicker = function (event) {
    var offset = this.TD.getBoundingClientRect(),
      dateFormat = this.cellProperties.dateFormat || this.defaultDateFormat,
      datePickerConfig = this.$datePicker.config(),
      dateStr,
      isMouseDown = this.instance.view.isMouseDown(),
      isMeta = event ? Handsontable.helper.isMetaKey(event.keyCode) : false;

    this.datePickerStyle.top = (window.pageYOffset + offset.top + Handsontable.Dom.outerHeight(this.TD)) + 'px';
    this.datePickerStyle.left = (window.pageXOffset + offset.left) + 'px';

    this.$datePicker._onInputFocus = function () {};
    datePickerConfig.format = dateFormat;

    if (this.originalValue) {
      dateStr = this.originalValue;

      if (moment(dateStr, dateFormat, true).isValid()) {
        this.$datePicker.setMoment(moment(dateStr, dateFormat), true);
      }

      if (!isMeta) {
        if (!isMouseDown) {
          this.setValue('');
        }
      }

    } else {
      if (this.cellProperties.defaultDate) {
        dateStr = this.cellProperties.defaultDate;

        datePickerConfig.defaultDate = dateStr;

        if (moment(dateStr, dateFormat, true).isValid()) {
          this.$datePicker.setMoment(moment(dateStr, dateFormat), true);
        }

        if (!isMeta) {
          if (!isMouseDown) {
            this.setValue('');
          }
        }
        //this.setValue(dateStr);
      }
    }

    this.datePickerStyle.display = 'block';
    this.$datePicker.show();
  };

  DateEditor.prototype.hideDatepicker = function () {
    this.datePickerStyle.display = 'none';
    this.$datePicker.hide();
  };

  Handsontable.editors.DateEditor = DateEditor;
  Handsontable.editors.registerEditor('date', DateEditor);
})(Handsontable);
<commit_msg>Fix issue with date editor making autocomplete editor unusable #2200<commit_after>(function (Handsontable) {
  var DateEditor = Handsontable.editors.TextEditor.prototype.extend();

  DateEditor.prototype.init = function () {
    if (typeof moment !== 'function') {
      throw new Error("You need to include moment.js to your project.");
    }

    if (typeof Pikaday !== 'function') {
      throw new Error("You need to include Pikaday to your project.");
    }

    Handsontable.editors.TextEditor.prototype.init.apply(this, arguments);

    this.isCellEdited = false;
    var that = this;

    this.instance.addHook('afterDestroy', function () {
      that.parentDestroyed = true;
      that.destroyElements();
    });
  };

  DateEditor.prototype.createElements = function () {
    var that = this;
    Handsontable.editors.TextEditor.prototype.createElements.apply(this, arguments);

    this.defaultDateFormat = 'DD/MM/YYYY';
    this.datePicker = document.createElement('DIV');
    this.datePickerStyle = this.datePicker.style;
    this.datePickerStyle.position = 'absolute';
    this.datePickerStyle.top = 0;
    this.datePickerStyle.left = 0;
    this.datePickerStyle.zIndex = 9999;

    Handsontable.Dom.addClass(this.datePicker, 'htDatepickerHolder');
    document.body.appendChild(this.datePicker);

    var htInput = this.TEXTAREA;

    var defaultOptions = {
      format: that.defaultDateFormat,
      field: htInput,
      trigger: htInput,
      container: that.datePicker,
      reposition: false,
      bound: false,
      onSelect: function (dateStr) {
        if (!isNaN(dateStr.getTime())) {
          dateStr = moment(dateStr).format(that.cellProperties.dateFormat || that.defaultDateFormat);
        }
        that.setValue(dateStr);
        that.hideDatepicker();
      },
      onClose: function () {
        if(!that.parentDestroyed) {
          that.finishEditing(false);
        }
      }
    };

    this.$datePicker = new Pikaday(defaultOptions);

    var eventManager = Handsontable.eventManager(this);

    /**
     * Prevent recognizing clicking on datepicker as clicking outside of table
     */
    eventManager.addEventListener(this.datePicker, 'mousedown', function (event) {
      Handsontable.helper.stopPropagation(event);
    });

    this.hideDatepicker();
  };

  DateEditor.prototype.destroyElements = function () {
    this.$datePicker.destroy();
  };

  DateEditor.prototype.prepare = function () {
    this._opened = false;
    Handsontable.editors.TextEditor.prototype.prepare.apply(this, arguments);
  };

  DateEditor.prototype.open = function (event) {
    Handsontable.editors.TextEditor.prototype.open.call(this);
    this.showDatepicker(event);
  };

  DateEditor.prototype.close = function () {
    var that = this;
    this._opened = false;
    this.instance._registerTimeout(setTimeout(function () {
      that.instance.selection.refreshBorders();
    }, 0));

    Handsontable.editors.TextEditor.prototype.close.apply(this, arguments);
  };

  DateEditor.prototype.finishEditing = function (isCancelled, ctrlDown) {
    if (isCancelled) { // pressed ESC, restore original value
      //var value = this.instance.getDataAtCell(this.row, this.col);
      var value = this.originalValue;
      if (value !== void 0) {
        this.setValue(value);
      }
    }

    this.hideDatepicker();
    Handsontable.editors.TextEditor.prototype.finishEditing.apply(this, arguments);
  };

  DateEditor.prototype.showDatepicker = function (event) {
    var offset = this.TD.getBoundingClientRect(),
      dateFormat = this.cellProperties.dateFormat || this.defaultDateFormat,
      datePickerConfig = this.$datePicker.config(),
      dateStr,
      isMouseDown = this.instance.view.isMouseDown(),
      isMeta = event ? Handsontable.helper.isMetaKey(event.keyCode) : false;

    this.datePickerStyle.top = (window.pageYOffset + offset.top + Handsontable.Dom.outerHeight(this.TD)) + 'px';
    this.datePickerStyle.left = (window.pageXOffset + offset.left) + 'px';

    this.$datePicker._onInputFocus = function () {};
    datePickerConfig.format = dateFormat;

    if (this.originalValue) {
      dateStr = this.originalValue;

      if (moment(dateStr, dateFormat, true).isValid()) {
        this.$datePicker.setMoment(moment(dateStr, dateFormat), true);
      }

      if (!isMeta) {
        if (!isMouseDown) {
          this.setValue('');
        }
      }

    } else {
      if (this.cellProperties.defaultDate) {
        dateStr = this.cellProperties.defaultDate;

        datePickerConfig.defaultDate = dateStr;

        if (moment(dateStr, dateFormat, true).isValid()) {
          this.$datePicker.setMoment(moment(dateStr, dateFormat), true);
        }

        if (!isMeta) {
          if (!isMouseDown) {
            this.setValue('');
          }
        }
        //this.setValue(dateStr);
      }
    }

    this.datePickerStyle.display = 'block';
    this.$datePicker.show();
  };

  DateEditor.prototype.hideDatepicker = function () {
    this.datePickerStyle.display = 'none';
    this.$datePicker.hide();
  };

  Handsontable.editors.DateEditor = DateEditor;
  Handsontable.editors.registerEditor('date', DateEditor);
})(Handsontable);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 Adobe Systems Incorporated. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 */

/*jslint vars: true, plusplus: true, devel: true, nomen: true, indent: 4, maxerr: 50 */
/*global define, $ */

define(function (require, exports, module) {
    "use strict";

    //constants
    var TAG_NAME = "tagName",
        ATTR_NAME = "attr.name",
        ATTR_VALUE = "attr.value";

    /**
     * @private
     * moves the current context backwards by one token
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
     * @return {boolean} whether the context changed
     */
    function _movePrevToken(ctx) {
        if (ctx.pos.ch <= 0 || ctx.token.start <= 0) {
            //move up a line
            if (ctx.pos.line <= 0) {
                return false; //at the top already
            }
            ctx.pos.line--;
            ctx.pos.ch = ctx.editor.getLine(ctx.pos.line).length;
        } else {
            ctx.pos.ch = ctx.token.start;
        }
        ctx.token = ctx.editor.getTokenAt(ctx.pos);
        return true;
    }

    /**
     * @private
     * moves the current context forward by one token
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
     * @return {boolean} whether the context changed
     */
    function _moveNextToken(ctx) {
        var eol = ctx.editor.getLine(ctx.pos.line).length;
        if (ctx.pos.ch >= eol || ctx.token.end >= eol) {
            //move down a line
            if (ctx.pos.line >= ctx.editor.lineCount() - 1) {
                return false; //at the bottom
            }
            ctx.pos.line++;
            ctx.pos.ch = 0;
        } else {
            ctx.pos.ch = ctx.token.end + 1;
        }
        ctx.token = ctx.editor.getTokenAt(ctx.pos);
        return true;
    }

   /**
     * @private
     * moves the current context in the given direction, skipping any whitespace it hits
     * @param {function} moveFxn the funciton to move the context
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} ctx
     * @return {boolean} whether the context changed
     */
    function _moveSkippingWhitespace(moveFxn, ctx) {
        if (!moveFxn(ctx)) {
            return false;
        }
        while (!ctx.token.className && ctx.token.string.trim().length === 0) {
            if (!moveFxn(ctx)) {
                return false;
            }
        }
        return true;
    }

   /**
     * @private
     * creates a context object
     * @param {CodeMirror} editor
     * @param {{ch:{string}, line:{number}} pos
     * @return {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}}
     */
    function _getInitialContext(editor, pos) {
        return {
            "editor": editor,
            "pos": pos,
            "token": editor.getTokenAt(pos)
        };
    }

    /**
     * @private
     * in the given context, get the character offset of pos from the start of the token
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} context
     * @return {number}
     */
    function _offsetInToken(ctx) {
        var offset = ctx.pos.ch - ctx.token.start;
        if (offset < 0) {
            console.log("CodeHintUtils: _offsetInToken - Invalid context: the pos what not in the current token!");
        }
        return offset;
    }

   /**
     * @private
     * Sometimes as attr values are getting typed, if the quotes aren't balanced yet
     * some extra 'non attribute value' text gets included in the token. This attempts
     * to assure the attribute value we grab is always good
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} context
     * @return { val:{string}, offset:{number}}
     */
    function _extractAttrVal(ctx) {
        var attrValue = ctx.token.string;
        var startChar = attrValue.charAt(0);
        var endChar = attrValue.charAt(attrValue.length - 1);
        var offset = _offsetInToken(ctx);

        //If this is a fully quoted value, return the whole
        //thing regardless of position
        if (attrValue.length > 1 &&
                (startChar === "'" || startChar === '"') &&
                endChar === startChar) {
            //strip the quotes and return;
            attrValue = attrValue.substring(1, attrValue.length - 1);
            offset = offset - 1 > attrValue.length ? attrValue.length : offset - 1;
            return {val: attrValue, offset: offset};
        }

        //The att value it getting edit in progress. There is possible extra
        //stuff in this token state since the quote isn't closed, so we assume
        //the stuff from the quote to the current pos is definitely in the attribute
        //value.
        if (offset > 0) {
            attrValue = attrValue.substring(0, offset);
        }

        //If the attrValue start with a quote, trim that now
        startChar = attrValue.charAt(0);
        if (startChar === "'" || startChar === '"') {
            attrValue = attrValue.substring(1);
            offset--;
        }

        return {val: attrValue, offset: offset};
    }

    /**
     * @private
     * Gets the tagname from where ever you are in the currect state
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} context
     * @return {string}
     */
    function _extractTagName(ctx) {
        if (ctx.token.state.tagName) {
            return ctx.token.state.tagName; //XML mode
        } else if (ctx.token.state.htmlState) {
            return ctx.token.state.htmlState.tagName; //HTML mode
        }
        // Some mixed modes that offer HTML as a nested mode don't actually expose the HTML state
        return null;
    }

    /**
     * Creates a tagInfo object and assures all the values are entered or are empty strings
     * @param {string} tokenType what is getting edited and should be hinted
     * @param {number} offset where the cursor is for the part getting hinted
     * @param {string} tagName The name of the tag
     * @param {string} attrName The name of the attribute
     * @param {string} attrValue The value of the attribute
     * @return {{tagName:string, attr{name:string, value:string}, hint:{type:{string}, offset{number}}}}
     *              A tagInfo object with some context about the current tag hint.
     */
    function createTagInfo(tokenType, offset, tagName, attrName, attrValue) {
        return { tagName: tagName || "",
                 attr:
                    { name: attrName || "",
                      value: attrValue || ""},
                 position:
                    { tokenType: tokenType || "",
                      offset: offset || 0} };
    }

    /**
     * @private
     * Gets the taginfo starting from the attribute value and moving backwards
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} context
     * @return {string}
     */
    function _getTagInfoStartingFromAttrValue(ctx) {
        // Assume we in the attr value
        // and validate that by going backwards
        var attrInfo = _extractAttrVal(ctx);
        var attrVal = attrInfo.val;
        var offset = attrInfo.offset;

        //Move to the prev token, and check if it's "="
        if (!_moveSkippingWhitespace(_movePrevToken, ctx) || ctx.token.string !== "=") {
            return createTagInfo();
        }

        //Move to the prev token, and check if it's an attribute
        if (!_moveSkippingWhitespace(_movePrevToken, ctx) || ctx.token.className !== "attribute") {
            return createTagInfo();
        }

        var attrName = ctx.token.string;
        var tagName = _extractTagName(ctx);

        //We're good.
        return createTagInfo(ATTR_VALUE, offset, tagName, attrName, attrVal);
    }

    /**
     * @private
     * Gets the taginfo starting from the attribute name and moving forwards
     * @param {editor:{CodeMirror}, pos:{ch:{string}, line:{number}}, token:{object}} context
     * @return {string}
     */
    function _getTagInfoStartingFromAttrName(ctx) {
        //Verify We're in the attribute name, move forward and try to extract the rest of
        //the info. If the user it typing the attr the rest might not be here
        if (ctx.token.className !== "attribute") {
            return createTagInfo();
        }

        var tagName = _extractTagName(ctx);
        var attrName = ctx.token.string;
        var offset = _offsetInToken(ctx);

        if (!_moveSkippingWhitespace(_moveNextToken, ctx) || ctx.token.string !== "=") {
            return createTagInfo(ATTR_NAME, offset, tagName, attrName);
        }

        if (!_moveSkippingWhitespace(_moveNextToken, ctx)) {
            return createTagInfo(ATTR_NAME, offset, tagName, attrName);
        }
        //this should be the attrvalue
        var attrInfo = _extractAttrVal(ctx);
        var attrVal = attrInfo.val;

        return createTagInfo(ATTR_NAME, offset, tagName, attrName, attrVal);
    }

    /**
     * Figure out if we're in a tag, and if we are return info about what to hint about it
     * An example token stream for this tag is  :
     *      className:tag       string:""
     * @param {Editor} editor An instance of a Brackets editor
     * @param {{ch: number, line: number}} constPos  A CM pos (likely from editor.getCursor())
     * @return {{tagName:string, attr{name:string, value:string}, hint:{type:{string}, offset{number}}}}
     *              A tagInfo object with some context about the current tag hint.
     */
    function getTagInfo(editor, constPos) {
        //we're going to changing pos a lot, but we don't want to mess up
        //the pos the caller passed in so we use extend to make a safe copy of it.
        //This is what pass by value in c++ would do.
        var pos = $.extend({}, constPos),
            ctx = _getInitialContext(editor._codeMirror, pos),
            offset = _offsetInToken(ctx),
            tagInfo,
            tokenType;

        //check and see where we are in the tag
        if (ctx.token.string.length > 0 && ctx.token.string.trim().length === 0) {

            // token at (i.e. before) pos is whitespace, so test token at next pos
            //
            // note: getTokenAt() does range checking for ch. If it detects that ch is past
            // EOL, it uses EOL, same token is returned, and the following condition fails,
            // so we don't need to worry about testPos being valid.
            var testPos = {ch: ctx.pos.ch + 1, line: ctx.pos.line},
                testToken = editor._codeMirror.getTokenAt(testPos);

            if (testToken.string.length > 0 && testToken.string.trim().length > 0) {
                // pos has whitespace before it and non-whitespace after it, so use token after
                ctx.pos = testPos;
                ctx.token = testToken;
                // Get the new offset from test token and subtract one for testPos adjustment
                offset = _offsetInToken(ctx) - 1;
            } else {
                // next, see what's before pos
                if (!_movePrevToken(ctx)) {
                    return createTagInfo();
                }

                if (ctx.token.className !== "tag") {
                    //if wasn't the tag name, assume it was an attr value
                    tagInfo = _getTagInfoStartingFromAttrValue(ctx);
                    //We don't want to give context for the previous attr
                    //and we want it to look like the user is going to add a new attr
                    if (tagInfo.tagName) {
                        return createTagInfo(ATTR_NAME, 0, tagInfo.tagName);
                    }
                    return createTagInfo();
                }

                //we know the tag was here, so they user is adding an attr name
                tokenType = ATTR_NAME;
                offset = 0;
            }
        }

        if (ctx.token.className === "tag") {
            //check to see if this is the closing of a tag (either the start or end)
            if (ctx.token.string === ">" ||
                    (ctx.token.string.charAt(0) === "<" && ctx.token.string.charAt(1) === "/")) {
                return createTagInfo();
            }

            if (!tokenType) {
                tokenType = TAG_NAME;
                offset--; //need to take off 1 for the leading "<"
            }

            //we're actually in the tag, just return that as we have no relevant
            //info about what attr is selected
            return createTagInfo(tokenType, offset, _extractTagName(ctx));
        }

        if (ctx.token.string === "=") {
            //we could be between the attr and the value
            //step back and check
            if (!_moveSkippingWhitespace(_movePrevToken, ctx) || ctx.token.className !== "attribute") {
                return createTagInfo();
            }

            //The "=" is added, time to hint for values
            tokenType = ATTR_VALUE;
            offset = 0;
        }

        if (ctx.token.className === "attribute") {
            tagInfo = _getTagInfoStartingFromAttrName(ctx);
        } else {
            // if we're not at a tag, "=", or attribute name, assume we're in the value
            tagInfo = _getTagInfoStartingFromAttrValue(ctx);
        }

        if (tokenType && tagInfo.tagName) {
            tagInfo.position.tokenType = tokenType;
            tagInfo.position.offset = offset;
        }

        return tagInfo;
    }

    /**
     * Returns an Array of info about all


<commit_before>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at https://raw.github.com/mozilla/butter/master/LICENSE */

define( [ "util/lang", "util/xhr", "util/keys", "util/mediatypes", "editor/editor",
 "util/time", "util/dragndrop", "text!layouts/media-editor.html" ],
  function( LangUtils, XHR, KeysUtils, MediaUtils, Editor, Time, DragNDrop, EDITOR_LAYOUT ) {

  var _parentElement =  LangUtils.domFragment( EDITOR_LAYOUT,".media-editor" ),
      _addMediaTitle = _parentElement.querySelector( ".add-new-media" ),
      _addMediaPanel = _parentElement.querySelector( ".add-media-panel" ),

      _urlInput = _addMediaPanel.querySelector( ".add-media-input" ),
      _addBtn = _addMediaPanel.querySelector( ".add-media-btn" ),
      _cancelBtn = _addMediaPanel.querySelector( ".add-media-cancel-btn" ),
      _errorMessage = _parentElement.querySelector( ".media-error-message" ),
      _oldValue,
      _loadingSpinner = _parentElement.querySelector( ".media-loading-spinner" ),

      _galleryPanel = _parentElement.querySelector( ".media-gallery" ),
      _galleryList = _galleryPanel.querySelector( ".media-gallery-list" ),
      _GALLERYITEM = LangUtils.domFragment( EDITOR_LAYOUT, ".media-gallery-item" ),

      _durationInput = _parentElement.querySelector( ".media-base-duration" ),

      _butter,
      _media,
      _this,
      _guid = 0;

  function toggleAddNewMediaPanel() {
    _parentElement.classList.toggle( "add-media-collapsed" );
  }

  function resetInput() {
    _urlInput.value = "";

    _urlInput.classList.remove( "error" );
    _errorMessage.classList.add( "hidden" );
    _loadingSpinner.classList.add( "hidden" );

    _addBtn.classList.add( "hidden" );
    _cancelBtn.classList.add( "hidden" );
  }

  function setBaseDuration( duration ) {
    if ( duration === "" ) {
      _durationInput.value = Time.toTimecode( _media.duration );
      return;
    }
    duration = Time.toTimecode( duration );
    if ( _durationInput.value !== duration ) {
      _durationInput.value = Time.toTimecode( duration );
    }
    if ( duration !== _media.duration ) {
      duration = Time.toSeconds( duration );
    }
    if ( duration === _media.duration ) {
      return;
    }
    if ( /[0-9]{1,9}/.test( duration ) ) {
      _media.url = "#t=," + duration;
    } else {
      _media.url = duration;
    }
  }

  function onSuccess( data ) {
    var el = _GALLERYITEM.cloneNode( true ),
        deleteBtn = el.querySelector( ".mg-delete-btn" ),
        thumbnailBtn = el.querySelector( ".mg-thumbnail" ),
        thumbnailImg,
        idx = _guid++;

    DragNDrop.helper( thumbnailBtn, {
      pluginOptions: {
        source: data.source,
        denied: data.denied,
        end: data.duration,
        from: data.from,
        title: data.title,
        duration: data.duration,
        hidden: data.hidden
      }
    });

    if ( !_media.clipData[ idx ] ) {
      _media.clipData[ idx ] = data.source;
      _butter.dispatch( "mediaclipadded" );

      el.classList.add( "new" );

      setTimeout(function() {
        el.classList.remove( "new" );
      }, 2000 );
    }

    thumbnailBtn.setAttribute( "data-popcorn-plugin-type", "sequencer" );
    thumbnailBtn.setAttribute( "data-butter-draggable-type", "plugin" );
    deleteBtn.addEventListener( "click", function() {

      thumbnailBtn.removeEventListener( "click", addEvent, false );
      _galleryList.removeChild( el );

      delete _media.clipData[ idx ];
      _butter.dispatch( "mediaclipremoved" );
    }, false );

    _loadingSpinner.classList.add( "hidden" );

    el.querySelector( ".mg-title" ).innerHTML = data.title;
    el.querySelector( ".mg-type" ).innerHTML = data.type;
    el.querySelector( ".mg-duration" ).innerHTML = Time.toTimecode( data.duration, 0 );
    if ( data.type === "html5" ) {
      thumbnailImg = data.thumbnail;
    } else {
      thumbnailImg = document.createElement( "img" );
      thumbnailImg.src = data.thumbnail;
    }
    thumbnailBtn.appendChild( thumbnailImg );
    thumbnailBtn.src = data.thumbnail;

    el.classList.add( "mg-" + data.type );

    if ( data.denied ) {
      el.querySelector( ".mg-error" ).innerHTML = "Embedding disabled by request";
    }

    function addEvent() {
      var start = _butter.currentTime,
          end = start + data.duration,
          trackEvent;

      function addTrackEvent() {
        trackEvent = _butter.generateSafeTrackEvent( "sequencer", start, end );

        trackEvent.update({
          source: data.source,
          denied: data.denied,
          start: start,
          end: end,
          from: data.from,
          title: data.title,
          duration: data.duration,
          hidden: data.hidden
        });
        _butter.deselectAllTrackEvents();
        trackEvent.selected = true;
      }

      if ( end > _media.duration ) {
        _butter.listen( "mediaready", function onMediaReady() {
          _butter.unlisten( "mediaready", onMediaReady );
          addTrackEvent();
        });

        setBaseDuration( end );
      } else {
        addTrackEvent();
      }
    }

    thumbnailBtn.addEventListener( "click", addEvent, false );

    _galleryList.insertBefore( el, _galleryList.firstChild );

    resetInput();
  }

  function addMediaToGallery() {
    var data = {};

    data.source = _urlInput.value;
    data.type = "sequencer";

    _loadingSpinner.classList.remove( "hidden" );
    MediaUtils.getMetaData( data.source, onSuccess );
  }

  function onFocus() {
    _oldValue = _urlInput.value;
  }

  function onInput() {
   if ( _oldValue !== _urlInput.value ) {
      _addBtn.classList.remove( "hidden" );
      _cancelBtn.classList.remove( "hidden" );
    } else {
      _addBtn.classList.add( "hidden" );
      _cancelBtn.classList.add( "hidden" );
    }
  }

  function onEnter( e ) {
    if ( e.keyCode === KeysUtils.ENTER ) {
      e.preventDefault();
      addMediaToGallery();
    }
  }

  function onBlur( e ) {
    e.preventDefault();
    setBaseDuration( _durationInput.value );
  }

  function setup() {
    _addMediaTitle.addEventListener( "click", toggleAddNewMediaPanel, false );

    _urlInput.addEventListener( "focus", onFocus, false );
    _urlInput.addEventListener( "input", onInput, false );
    _urlInput.addEventListener( "keydown", onEnter, false );

    _addBtn.addEventListener( "click", addMediaToGallery, false );
    _cancelBtn.addEventListener( "click", resetInput, false );

    _durationInput.addEventListener( "keydown", onDurationChange, false );
    _durationInput.addEventListener( "blur", onBlur, false );
  }

  function onDurationChange( e ) {
    if ( e.keyCode === KeysUtils.ENTER ) {
      e.preventDefault();
      setBaseDuration( _durationInput.value );
    }
  }

  Editor.register( "media-editor", null, function( rootElement, butter ) {
    rootElement = _parentElement;
    _this = this;
    _butter = butter;
    _media = _butter.currentMedia;

    // We keep track of clips that are in the media gallery for a project once it is saved
    // and every time after it is saved.
    var clips = _media.clipData;

    for ( var key in clips ) {
      if ( clips.hasOwnProperty( key ) ) {
        MediaUtils.getMetaData( clips[ key ], onSuccess );
      }
    }

    setup();

    Editor.BaseEditor.extend( _this, butter, rootElement, {
      open: function() {
        setBaseDuration( _media.duration );
      },
      close: function() {}
    });

  }, true );
});
<commit_msg>[t3253] Don't trigger media loading on empty url input<commit_after>/* This Source Code Form is subject to the terms of the MIT license
 * If a copy of the MIT license was not distributed with this file, you can
 * obtain one at https://raw.github.com/mozilla/butter/master/LICENSE */

define( [ "util/lang", "util/xhr", "util/keys", "util/mediatypes", "editor/editor",
 "util/time", "util/dragndrop", "text!layouts/media-editor.html" ],
  function( LangUtils, XHR, KeysUtils, MediaUtils, Editor, Time, DragNDrop, EDITOR_LAYOUT ) {

  var _parentElement =  LangUtils.domFragment( EDITOR_LAYOUT,".media-editor" ),
      _addMediaTitle = _parentElement.querySelector( ".add-new-media" ),
      _addMediaPanel = _parentElement.querySelector( ".add-media-panel" ),

      _urlInput = _addMediaPanel.querySelector( ".add-media-input" ),
      _addBtn = _addMediaPanel.querySelector( ".add-media-btn" ),
      _cancelBtn = _addMediaPanel.querySelector( ".add-media-cancel-btn" ),
      _errorMessage = _parentElement.querySelector( ".media-error-message" ),
      _oldValue,
      _loadingSpinner = _parentElement.querySelector( ".media-loading-spinner" ),

      _galleryPanel = _parentElement.querySelector( ".media-gallery" ),
      _galleryList = _galleryPanel.querySelector( ".media-gallery-list" ),
      _GALLERYITEM = LangUtils.domFragment( EDITOR_LAYOUT, ".media-gallery-item" ),

      _durationInput = _parentElement.querySelector( ".media-base-duration" ),

      _butter,
      _media,
      _this,
      _guid = 0;

  function toggleAddNewMediaPanel() {
    _parentElement.classList.toggle( "add-media-collapsed" );
  }

  function resetInput() {
    _urlInput.value = "";

    _urlInput.classList.remove( "error" );
    _errorMessage.classList.add( "hidden" );
    _loadingSpinner.classList.add( "hidden" );

    _addBtn.classList.add( "hidden" );
    _cancelBtn.classList.add( "hidden" );
  }

  function setBaseDuration( duration ) {
    if ( duration === "" ) {
      _durationInput.value = Time.toTimecode( _media.duration );
      return;
    }
    duration = Time.toTimecode( duration );
    if ( _durationInput.value !== duration ) {
      _durationInput.value = Time.toTimecode( duration );
    }
    if ( duration !== _media.duration ) {
      duration = Time.toSeconds( duration );
    }
    if ( duration === _media.duration ) {
      return;
    }
    if ( /[0-9]{1,9}/.test( duration ) ) {
      _media.url = "#t=," + duration;
    } else {
      _media.url = duration;
    }
  }

  function onSuccess( data ) {
    var el = _GALLERYITEM.cloneNode( true ),
        deleteBtn = el.querySelector( ".mg-delete-btn" ),
        thumbnailBtn = el.querySelector( ".mg-thumbnail" ),
        thumbnailImg,
        idx = _guid++;

    DragNDrop.helper( thumbnailBtn, {
      pluginOptions: {
        source: data.source,
        denied: data.denied,
        end: data.duration,
        from: data.from,
        title: data.title,
        duration: data.duration,
        hidden: data.hidden
      }
    });

    if ( !_media.clipData[ idx ] ) {
      _media.clipData[ idx ] = data.source;
      _butter.dispatch( "mediaclipadded" );

      el.classList.add( "new" );

      setTimeout(function() {
        el.classList.remove( "new" );
      }, 2000 );
    }

    thumbnailBtn.setAttribute( "data-popcorn-plugin-type", "sequencer" );
    thumbnailBtn.setAttribute( "data-butter-draggable-type", "plugin" );
    deleteBtn.addEventListener( "click", function() {

      thumbnailBtn.removeEventListener( "click", addEvent, false );
      _galleryList.removeChild( el );

      delete _media.clipData[ idx ];
      _butter.dispatch( "mediaclipremoved" );
    }, false );

    _loadingSpinner.classList.add( "hidden" );

    el.querySelector( ".mg-title" ).innerHTML = data.title;
    el.querySelector( ".mg-type" ).innerHTML = data.type;
    el.querySelector( ".mg-duration" ).innerHTML = Time.toTimecode( data.duration, 0 );
    if ( data.type === "html5" ) {
      thumbnailImg = data.thumbnail;
    } else {
      thumbnailImg = document.createElement( "img" );
      thumbnailImg.src = data.thumbnail;
    }
    thumbnailBtn.appendChild( thumbnailImg );
    thumbnailBtn.src = data.thumbnail;

    el.classList.add( "mg-" + data.type );

    if ( data.denied ) {
      el.querySelector( ".mg-error" ).innerHTML = "Embedding disabled by request";
    }

    function addEvent() {
      var start = _butter.currentTime,
          end = start + data.duration,
          trackEvent;

      function addTrackEvent() {
        trackEvent = _butter.generateSafeTrackEvent( "sequencer", start, end );

        trackEvent.update({
          source: data.source,
          denied: data.denied,
          start: start,
          end: end,
          from: data.from,
          title: data.title,
          duration: data.duration,
          hidden: data.hidden
        });
        _butter.deselectAllTrackEvents();
        trackEvent.selected = true;
      }

      if ( end > _media.duration ) {
        _butter.listen( "mediaready", function onMediaReady() {
          _butter.unlisten( "mediaready", onMediaReady );
          addTrackEvent();
        });

        setBaseDuration( end );
      } else {
        addTrackEvent();
      }
    }

    thumbnailBtn.addEventListener( "click", addEvent, false );

    _galleryList.insertBefore( el, _galleryList.firstChild );

    resetInput();
  }

  function addMediaToGallery() {
    var data = {},
        val = _urlInput.value;

    // Don't trigger with empty inputs
    if ( !val ) {
      return;
    }

    data.source = val;
    data.type = "sequencer";

    _loadingSpinner.classList.remove( "hidden" );
    MediaUtils.getMetaData( data.source, onSuccess );
  }

  function onFocus() {
    _oldValue = _urlInput.value;
  }

  function onInput() {
   if ( _oldValue !== _urlInput.value ) {
      _addBtn.classList.remove( "hidden" );
      _cancelBtn.classList.remove( "hidden" );
    } else {
      _addBtn.classList.add( "hidden" );
      _cancelBtn.classList.add( "hidden" );
    }
  }

  function onEnter( e ) {
    if ( e.keyCode === KeysUtils.ENTER ) {
      e.preventDefault();
      addMediaToGallery();
    }
  }

  function onBlur( e ) {
    e.preventDefault();
    setBaseDuration( _durationInput.value );
  }

  function setup() {
    _addMediaTitle.addEventListener( "click", toggleAddNewMediaPanel, false );

    _urlInput.addEventListener( "focus", onFocus, false );
    _urlInput.addEventListener( "input", onInput, false );
    _urlInput.addEventListener( "keydown", onEnter, false );

    _addBtn.addEventListener( "click", addMediaToGallery, false );
    _cancelBtn.addEventListener( "click", resetInput, false );

    _durationInput.addEventListener( "keydown", onDurationChange, false );
    _durationInput.addEventListener( "blur", onBlur, false );
  }

  function onDurationChange( e ) {
    if ( e.keyCode === KeysUtils.ENTER ) {
      e.preventDefault();
      setBaseDuration( _durationInput.value );
    }
  }

  Editor.register( "media-editor", null, function( rootElement, butter ) {
    rootElement = _parentElement;
    _this = this;
    _butter = butter;
    _media = _butter.currentMedia;

    // We keep track of clips that are in the media gallery for a project once it is saved
    // and every time after it is saved.
    var clips = _media.clipData;

    for ( var key in clips ) {
      if ( clips.hasOwnProperty( key ) ) {
        MediaUtils.getMetaData( clips[ key ], onSuccess );
      }
    }

    setup();

    Editor.BaseEditor.extend( _this, butter, rootElement, {
      open: function() {
        setBaseDuration( _media.duration );
      },
      close: function() {}
    });

  }, true );
});
<|endoftext|>


<commit_before>/**
 * This Source Code is licensed under the MIT license. If a copy of the
 * MIT-license was not distributed with this file, You can obtain one at:
 * http://opensource.org/licenses/mit-license.html.
 *
 * @author: Hein Rutjes (IjzerenHein)
 * @license MIT
 * @copyright Gloey Apps, 2014
 */

/*global define, console*/
/*eslint no-console: 0*/

/**
 * Lays-out renderables from left to right, in a grid with fixed number of
 * columns and rows.
 *
 * |options|type|description|
 * |---|---|---|
 * |`cells`|Size|Number of cells: [columns, rows]|
 * |`[margins]`|Number/Array|Margins shorthand (e.g. 5, [10, 20], [2, 5, 2, 10])|
 * |`[spacing]`|Size|Spacing between renderables. (e.g. [10, 10]|
 *
 * Example:
 *
 * ```javascript
 * var GridLayout = require('famous-flex/layouts/GridLayout');
 *
 * var layoutController = new LayoutController({
 *   layout: GridLayout,
 *   layoutOptions: {
 *     cells: [10, 5],            // 10 columns, 5 rows
 *     margins: [20, 20, 20, 20], // margins on the outside
 *     spacing: [10, 10]          // spacing between cells
 *   },
 *   dataSource: [
 *     new Surface({content: 'item 1'}),
 *     new Surface({content: 'item 2'}),
 *     new Surface({content: 'item 3'})
 *   ]
 * });
 * ```
 * @module
 */
define(function(require, exports, module) {

    // import dependencies
    var Utility = require('famous/utilities/Utility');
    var LayoutUtility = require('../LayoutUtility');

    // Define capabilities of this layout function
    var capabilities = {
        sequence: true,
        direction: [Utility.Direction.Y, Utility.Direction.X],
        scrolling: false
    };

    // Layout function
    function GridLayout(context, options) {

        // Do one-time stuff
        var size = context.size;
        if ((options.gutter !== undefined) && console.warn) {
            console.warn('gutter has been deprecated for GridLayout, use margins & spacing instead');
        }
        var spacing;
        if (options.gutter && !options.spacing) {
            spacing = options.gutter || 0;
        }
        else {
            spacing = options.spacing || 0;
        }
        spacing = Array.isArray(spacing) ? spacing : [spacing, spacing];
        var margins = LayoutUtility.normalizeMargins(options.margins);
        var nodeSize = [
            (size[0] - (((options.cells[0] - 1) * spacing[0]) + margins[1] + margins[3])) / options.cells[0],
            (size[1] - (((options.cells[1] - 1) * spacing[1]) + margins[0] + margins[2])) / options.cells[1]
        ];

        // Define size and position of grid-item
        function _layoutNode(node, col, row) {
            context.set(node, {
                size: nodeSize,
                translate: [
                    ((nodeSize[0] + spacing[0]) * col) + margins[3],
                    ((nodeSize[1] + spacing[1]) * row) + margins[0],
                    0
                ]
            });
        }

        // Create rows & columns
        var row;
        var col;
        var node;
        if (context.direction === Utility.Direction.Y) {
            for (col = 0; col < options.cells[0]; col++) {
                for (row = 0; row < options.cells[1]; row++) {
                    node = context.next();
                    if (!node) {
                        return;
                    }
                    _layoutNode(node, col, row);
                }
            }
        }
        else {
            for (row = 0; row < options.cells[1]; row++) {
                for (col = 0; col < options.cells[0]; col++) {
                    node = context.next();
                    if (!node) {
                        return;
                    }
                    _layoutNode(node, col, row);
                }
            }
        }
    }

    GridLayout.Capabilities = capabilities;
    module.exports = GridLayout;
});
<commit_msg>Simplified GridLayout implementation + added alignment support<commit_after>/**
 * This Source Code is licensed under the MIT license. If a copy of the
 * MIT-license was not distributed with this file, You can obtain one at:
 * http://opensource.org/licenses/mit-license.html.
 *
 * @author: Hein Rutjes (IjzerenHein)
 * @license MIT
 * @copyright Gloey Apps, 2014
 */

/*global define, console*/
/*eslint no-console: 0*/

/**
 * Lays-out renderables from left to right, in a grid with fixed number of
 * columns and rows.
 *
 * |options|type|description|
 * |---|---|---|
 * |`cells`|Size|Number of cells: [columns, rows]|
 * |`[margins]`|Number/Array|Margins shorthand (e.g. 5, [10, 20], [2, 5, 2, 10])|
 * |`[spacing]`|Size|Spacing between renderables. (e.g. [10, 10]|
 *
 * Example:
 *
 * ```javascript
 * var GridLayout = require('famous-flex/layouts/GridLayout');
 *
 * var layoutController = new LayoutController({
 *   layout: GridLayout,
 *   layoutOptions: {
 *     cells: [10, 5],            // 10 columns, 5 rows
 *     margins: [20, 20, 20, 20], // margins on the outside
 *     spacing: [10, 10]          // spacing between cells
 *   },
 *   dataSource: [
 *     new Surface({content: 'item 1'}),
 *     new Surface({content: 'item 2'}),
 *     new Surface({content: 'item 3'})
 *   ]
 * });
 * ```
 * @module
 */
define(function(require, exports, module) {

    // import dependencies
    var Utility = require('famous/utilities/Utility');
    var LayoutUtility = require('../LayoutUtility');

    // Define capabilities of this layout function
    var capabilities = {
        sequence: true,
        direction: [Utility.Direction.Y, Utility.Direction.X],
        scrolling: false
    };

    // Layout function
    function GridLayout(context, options) {

        // Do one-time stuff
        var revDirection = context.direction ? 0 : 1;
        if ((options.gutter !== undefined) && console.warn) {
            console.warn('gutter has been deprecated for GridLayout, use margins & spacing instead');
        }
        var spacing;
        if (options.gutter && !options.spacing) {
            spacing = options.gutter || 0;
        }
        else {
            spacing = options.spacing || 0;
        }
        spacing = Array.isArray(spacing) ? spacing : [spacing, spacing];
        var margins = LayoutUtility.normalizeMargins(options.margins);
        var nodeSize = [
            (context.size[0] - (((options.cells[0] - 1) * spacing[0]) + margins[1] + margins[3])) / options.cells[0],
            (context.size[1] - (((options.cells[1] - 1) * spacing[1]) + margins[0] + margins[2])) / options.cells[1]
        ];

        // Create rows & columns
        for (var a = 0; a < options.cells[revDirection]; a++) {
            for (var b = 0; b < options.cells[context.direction]; b++) {
                var node = context.alignment ? context.prev() : context.next();
                if (!node) {
                    return;
                }
                context.set(node, {
                    size: nodeSize,
                    translate: [
                        ((nodeSize[0] + spacing[0]) * (revDirection ? b : a)) + margins[3],
                        ((nodeSize[1] + spacing[1]) * (revDirection ? a : b)) + margins[0],
                        0
                    ]
                });
            }
        }
    }

    GridLayout.Capabilities = capabilities;
    module.exports = GridLayout;
});
<|endoftext|>


<commit_before>//
// leaflet.handlebars
//
// A Leaflet plugin for handlebars-driven popups
//

(function () {

    function defineLeafletHandlebars(L, Handlebars) {

        L.FeatureGroup.include({

            precompileTemplate: function () {
                if (!this.handlebarsTemplate && this.options && this.options.handlebarsTemplateSelector) {
                    // Pre-compile template
                    var source = $(this.options.handlebarsTemplateSelector).html();
                    this.handlebarsTemplate = Handlebars.compile(source);
                }
                return this.handlebarsTemplate;
            },

            getTemplateContext: function (layer) {
                if (this.options.getTemplateContext) {
                    return this.options.getTemplateContext(layer);
                }
                return {
                    feature: layer.feature
                };
            },

            addLayer: function (layer) {
                // Keep most of FeatureGroup's addLayer, but try to populate each
                // layer's popup with handlebars

                if (this.hasLayer(layer)) {
                    return this;
                }

                if ('on' in layer) {
                    layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
                }

                L.LayerGroup.prototype.addLayer.call(this, layer);

                // If we have a handlebars template use it
                var template = this.precompileTemplate();
                if (template) {
                    this._popupContent = this.handlebarsTemplate(this.getTemplateContext(layer));
                }

                if (this._popupContent && layer.bindPopup) {
                    layer.bindPopup(this._popupContent, this.options.popupOptions);
                }

                return this.fire('layeradd', {layer: layer});
            }

        });
    }

    if (typeof define === 'function' && define.amd) {
        // Try to add leaflet.handlebars to Leaflet using AMD
        define(['leaflet', 'handlebars'], function (L, Handlebars) {
            defineLeafletHandlebars(L, Handlebars);
        });
    }
    else {
        // Else use the global L and Handlebars
        defineLeafletHandlebars(L, Handlebars);
    }
})();
<commit_msg>Watch out for exceptions<commit_after>//
// leaflet.handlebars
//
// A Leaflet plugin for handlebars-driven popups
//

(function () {

    function defineLeafletHandlebars(L, Handlebars) {

        L.FeatureGroup.include({

            precompileTemplate: function () {
                if (!this.handlebarsTemplate && this.options && this.options.handlebarsTemplateSelector) {
                    // Pre-compile template
                    var source = $(this.options.handlebarsTemplateSelector).html();
                    this.handlebarsTemplate = Handlebars.compile(source);
                }
                return this.handlebarsTemplate;
            },

            getTemplateContext: function (layer) {
                if (this.options.getTemplateContext) {
                    return this.options.getTemplateContext(layer);
                }
                return {
                    feature: layer.feature
                };
            },

            addLayer: function (layer) {
                // Keep most of FeatureGroup's addLayer, but try to populate each
                // layer's popup with handlebars

                if (this.hasLayer(layer)) {
                    return this;
                }

                if ('on' in layer) {
                    layer.on(L.FeatureGroup.EVENTS, this._propagateEvent, this);
                }

                L.LayerGroup.prototype.addLayer.call(this, layer);

                // If we have a handlebars template use it
                var template = this.precompileTemplate();
                if (template) {
                    try {
                        this._popupContent = this.handlebarsTemplate(this.getTemplateContext(layer));
                    }
                    catch (e) {
                        //
                    }
                }

                if (this._popupContent && layer.bindPopup) {
                    layer.bindPopup(this._popupContent, this.options.popupOptions);
                }

                return this.fire('layeradd', {layer: layer});
            }

        });
    }

    if (typeof define === 'function' && define.amd) {
        // Try to add leaflet.handlebars to Leaflet using AMD
        define(['leaflet', 'handlebars'], function (L, Handlebars) {
            defineLeafletHandlebars(L, Handlebars);
        });
    }
    else {
        // Else use the global L and Handlebars
        defineLeafletHandlebars(L, Handlebars);
    }
})();
<|endoftext|>


<commit_before>'use strict';

import React from 'react';
import ReactNative from 'react-native';
import {Field} from './Field.js';

const {View, StyleSheet, TextInput, Text} = ReactNative;

function validateEmail(email) {
  var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  if(re.test(email)) return true;
  return 'Invalid email';
}

export class InputComponent extends React.Component{
  constructor(props){
    super(props);

    this.triggerValidation = this.triggerValidation.bind(this);
    // this.validate = this.validate.bind(this)
    this.validate(props.value);
    this.validationErrors = [];
    this.state = {
      labelWidth: 0,
      value: props.value,
      minFieldHeight: props.height || 44,
      inputHeight: Math.max(props.height || 44),
      // isValid:
    };

  }

  setValue(value){
    this.setState({value:value});
    if(this.props.onChange)      this.props.onChange(value);
    if(this.props.onValueChange) this.props.onValueChange(value);
  }

  triggerValidation() {
    this.setState({isValid:this.validate(this.state.value)});
  }
  validate(value){
    let validationResult;
    this.validationErrors = [];

    if(!!this.props.validationFunction) {
      if(this.props.validationFunction.constructor === Array){
        /*
        validationFunction has to return an object in case of error,
          true in case of successful validation
         */
        this.props.validationFunction.map((valFn, i)=>{

          let validationResult = valFn(value, this);
          if(validationResult === true){
            this.valid = (this.valid !== false)? validationResult : this.valid;
          } else{
            this.validationErrors.push(validationResult);
            this.valid = false;
          }

        })
      } else {
        let validationResult = this.props.validationFunction(value, this);
        if(validationResult === true){
          this.valid = true;
        } else{
          this.validationErrors.push(validationResult);
          this.valid = false;
        }
      }

    } else
    if(this.props.keyboardType){
      switch (this.props.keyboardType) {
        case 'email-address':
          validationResult = validateEmail(value);
          break;
      }
      if(validationResult === true){
        this.valid = true;
      } else{
        this.validationErrors.push(validationResult);
        this.valid = false;
      }
    }
    this.props.onValidation(this.valid, this.validationErrors);
    return this.valid;
  }
  handleLayoutChange(e){
    let {x, y, width, height} = {... e.nativeEvent.layout};

    this.setState(e.nativeEvent.layout);
    //e.nativeEvent.layout: {x, y, width, height}}}.
  }

  handleLabelLayoutChange(e){
    let {x, y, width, height} = {... e.nativeEvent.layout};

    this.setState({labelWidth:width});
    //e.nativeEvent.layout: {x, y, width, height}}}.
  }
  handleChange(event){
    const value = event.nativeEvent.text;

    this.validate(value);

    this.setState({value,
      inputHeight: Math.max(this.state.minFieldHeight,
        (event.nativeEvent.contentSize && this.props.multiline)
          ? event.nativeEvent.contentSize.height
          : 0)
      });
    //this.props.onChange(this.props.fieldRef, value);
    if(this.props.onChange)      this.props.onChange(value, this.valid);
    if(this.props.onValueChange) this.props.onValueChange(value,this.valid);
  }

  _scrollToInput (event) {
    //debugger;
    if (this.props.onFocus) {
      let handle = ReactNative.findNodeHandle(this.refs.inputBox);
      this.props.onFocus(
        event,
        handle
      )
    }
  }
  handleFieldPress(event){
    this.refs.inputBox.focus();
  }
  render(){
 // style={[formStyles.fieldContainer,
 //     formStyles.horizontalContainer,
 //     this.props.containerStyle,
 //     {height: this.state.inputHeight+1}
 //   ]}
    return(<Field {...this.props}>
        <View
          onLayout={this.handleLayoutChange.bind(this)}
          style={[
              this.props.containerStyle,

            ]}>
          {(this.props.iconLeft)
            ? this.props.iconLeft
            : null
          }
          {(this.props.label)
            ?
            <Text style={this.props.labelStyle}
              onLayout={this.handleLabelLayoutChange.bind(this)}
              onPress={this.handleFieldPress.bind(this)}
              >{this.props.label}</Text>
            : null
          }
          <TextInput
            {...this.props}
            ref='inputBox'
            keyboardType = {this.props.keyboardType}
            style={[
                this.props.inputStyle,
                {height: this.state.inputHeight}
              ]}

            onChange={this.handleChange.bind(this)}
            onFocus={this._scrollToInput.bind(this)}
            placeholder={this.props.placeholder}
            value={this.state.value}
            width={this.state.width-this.state.labelWidth
                -((this.props.iconRight)?this.props.iconRight.props.size:0)
                -((this.props.iconLeft)?this.props.iconLeft.props.size:0)
              }

            />
          {(this.props.iconRight)
              ? this.props.iconRight
              : null
            }
        </View>
      </Field>
    )
  }

}

// InputComponent.propTypes = {
//   multiline: React.PropTypes.bool,
//   placeholder:React.PropTypes.string,
// }

InputComponent.propTypes = {
  labelStyle: Text.propTypes.style,
  inputStyle: TextInput.propTypes.style,
  containerStyle: View.propTypes.style
}
<commit_msg>Updated InputComponent<commit_after>'use strict';

import React from 'react';
import ReactNative from 'react-native';
import {Field} from './Field.js';

const {View, StyleSheet, TextInput, Text} = ReactNative;

function validateEmail(email) {
  var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
  if(re.test(email)) return true;
  return 'Invalid email';
}

export class InputComponent extends React.Component{
  constructor(props){
    super(props);

    this.triggerValidation = this.triggerValidation.bind(this);
    // this.validate = this.validate.bind(this)
    this.validate(props.value);
    this.validationErrors = [];
    this.state = {
      labelWidth: 0,
      value: props.value,
      minFieldHeight: props.height || 44,
      inputHeight: Math.max(props.height || 44),
      // isValid:
    };

  }

  setValue(value){
    this.setState({value:value});
    if(this.props.onChange)      this.props.onChange(value);
    if(this.props.onValueChange) this.props.onValueChange(value);
  }

  triggerValidation() {
    this.setState({isValid:this.validate(this.state.value)});
  }
  validate(value){
    let validationResult;
    this.validationErrors = [];

    if(!!this.props.validationFunction) {
      if(this.props.validationFunction.constructor === Array){
        /*
        validationFunction has to return an object in case of error,
          true in case of successful validation
         */
        this.props.validationFunction.map((valFn, i)=>{

          let validationResult = valFn(value, this);
          if(validationResult === true){
            this.valid = (this.valid !== false)? validationResult : this.valid;
          } else{
            this.validationErrors.push(validationResult);
            this.valid = false;
          }

        })
      } else {
        let validationResult = this.props.validationFunction(value, this);
        if(validationResult === true){
          this.valid = true;
        } else{
          this.validationErrors.push(validationResult);
          this.valid = false;
        }
      }

    } else
    if(this.props.keyboardType){
      switch (this.props.keyboardType) {
        case 'email-address':
          validationResult = validateEmail(value);
          break;
      }
      if(validationResult === true){
        this.valid = true;
      } else{
        this.validationErrors.push(validationResult);
        this.valid = false;
      }
    }
    this.props.onValidation(this.valid, this.validationErrors);
    return this.valid;
  }
  handleLayoutChange(e){
    let {x, y, width, height} = {... e.nativeEvent.layout};

    this.setState(e.nativeEvent.layout);
    //e.nativeEvent.layout: {x, y, width, height}}}.
  }

  handleLabelLayoutChange(e){
    let {x, y, width, height} = {... e.nativeEvent.layout};

    this.setState({labelWidth:width});
    //e.nativeEvent.layout: {x, y, width, height}}}.
  }
  handleChange(event){
    const value = event.nativeEvent.text;

    this.validate(value);

    this.setState({value,
      inputHeight: Math.max(this.state.minFieldHeight,
        (event.nativeEvent.contentSize && this.props.multiline)
          ? event.nativeEvent.contentSize.height
          : 0)
      });
    //this.props.onChange(this.props.fieldRef, value);
    if(this.props.onChange)      this.props.onChange(value, this.valid);
    if(this.props.onValueChange) this.props.onValueChange(value,this.valid);
  }

  _scrollToInput (event) {
    //debugger;
    if (this.props.onFocus) {
      let handle = ReactNative.findNodeHandle(this.refs.inputBox);
      this.props.onFocus(
        event,
        handle
      )
    }
  }
  handleFieldPress(event){
    this.refs.inputBox.focus();
  }
  render(){
 // style={[formStyles.fieldContainer,
 //     formStyles.horizontalContainer,
 //     this.props.containerStyle,
 //     {height: this.state.inputHeight+1}
 //   ]}
    return(<Field {...this.props}>
        <View
          onLayout={this.handleLayoutChange.bind(this)}
          style={[
              this.props.containerStyle,

            ]}>
          {(this.props.iconLeft)
            ? this.props.iconLeft
            : null
          }
          {(this.props.label)
            ?
            <Text style={this.props.labelStyle}
              onLayout={this.handleLabelLayoutChange.bind(this)}
              onPress={this.handleFieldPress.bind(this)}
              suppressHighlighting={true}
              >{this.props.label}</Text>
            : null
          }
          <TextInput
            {...this.props}
            ref='inputBox'
            keyboardType = {this.props.keyboardType}
            style={[
                this.props.inputStyle,
                {height: this.state.inputHeight}
              ]}

            onChange={this.handleChange.bind(this)}
            onFocus={this._scrollToInput.bind(this)}
            placeholder={this.props.placeholder}
            value={this.state.value}
            width={this.state.width-this.state.labelWidth
                -((this.props.iconRight)?this.props.iconRight.props.size:0)
                -((this.props.iconLeft)?this.props.iconLeft.props.size:0)
              }

            />
          {(this.props.iconRight)
              ? this.props.iconRight
              : null
            }
        </View>
      </Field>
    )
  }

}

// InputComponent.propTypes = {
//   multiline: React.PropTypes.bool,
//   placeholder:React.PropTypes.string,
// }

InputComponent.propTypes = {
  labelStyle: Text.propTypes.style,
  inputStyle: TextInput.propTypes.style,
  containerStyle: View.propTypes.style
}
<|endoftext|>


<commit_before>var
  // Basic methods that DSL will curry for build complex custom filters
  methods = require('./methods'),
  async = require('async'),
  _ = require('lodash'),
  stringify = require('json-stable-stringify'),
  crypto = require('crypto'),
  q = require('q');

module.exports = function Dsl (kuzzle) {

  /**
   * Allow to send a collection and a list of filter and return all "curried" names for each filters
   *
   * @param {String} collection
   * @param {Object} filters
   * @returns {Promise} promise
   */
  this.getFunctionsNames = function (collection, filters) {
    var
      deferred = q.defer(),
      filtersNames = {};

    async.each(Object.keys(filters), function (fn, callback) {
      var
        field = Object.keys(filters[fn])[0],
        name = filters[fn][field];

      name = stringify(name);
      name = crypto.createHash('md5').update(name).digest('hex');
      name = fn+field+'-'+name;

      filtersNames[name] = {};
      filtersNames[name][fn] = filters[fn];

      callback();
    }, function () {
      deferred.resolve(filtersNames);
    });

    return deferred.promise;
  };

  /**
   * Create a curried function according to filter
   *
   * @param name
   * @param filter
   * @returns {String} a new curried function
   */
  this.createCurriedFunction = function (name, filter) {
    var
      fn = Object.keys(filter)[0],
      field = Object.keys(filter[fn])[0],
      value = filter[fn][field];

    curried = _.curry(methods[fn]);
    return _.curry(curried(value));
  };

  /**
   * Test all filters in filtersTree for test which room to notify
   *
   * @param {Object} data
   * @returns {Promise} promise. Resolve a rooms list that we need to notify
   */
  this.testFilters = function (data) {
    var
      deferred = q.defer(),
      rooms = [];

    if (!data.collection) {
      deferred.reject('The data doesn\'t contain a collection');
      return deferred.promise;
    }

    if (!kuzzle.hotelClerk.filtersTree[data.collection]) {
      deferred.reject();
      return deferred.promise;
    }

    async.each(Object.keys(data.content), function (field, callbackContent) {
      var fieldFilters = kuzzle.hotelClerk.filtersTree[data.collection][field];

      if (!fieldFilters) {
        callbackContent();
        return false;
      }

      async.each(Object.keys(fieldFilters), function (functionName, callbackField) {
        if (fieldFilters[functionName].fn(data.content[field])) {
          rooms = rooms.concat(fieldFilters[functionName].rooms);
        }

        callbackField();
      }, function () {
        callbackContent();
      });
    }, function () {
      deferred.resolve( rooms );
    });

    return deferred.promise;
  };

};<commit_msg>Fix syntax nitpicking: no space inside of parenthesis<commit_after>var
  // Basic methods that DSL will curry for build complex custom filters
  methods = require('./methods'),
  async = require('async'),
  _ = require('lodash'),
  stringify = require('json-stable-stringify'),
  crypto = require('crypto'),
  q = require('q');

module.exports = function Dsl (kuzzle) {

  /**
   * Allow to send a collection and a list of filter and return all "curried" names for each filters
   *
   * @param {String} collection
   * @param {Object} filters
   * @returns {Promise} promise
   */
  this.getFunctionsNames = function (collection, filters) {
    var
      deferred = q.defer(),
      filtersNames = {};

    async.each(Object.keys(filters), function (fn, callback) {
      var
        field = Object.keys(filters[fn])[0],
        name = filters[fn][field];

      name = stringify(name);
      name = crypto.createHash('md5').update(name).digest('hex');
      name = fn+field+'-'+name;

      filtersNames[name] = {};
      filtersNames[name][fn] = filters[fn];

      callback();
    }, function () {
      deferred.resolve(filtersNames);
    });

    return deferred.promise;
  };

  /**
   * Create a curried function according to filter
   *
   * @param name
   * @param filter
   * @returns {String} a new curried function
   */
  this.createCurriedFunction = function (name, filter) {
    var
      fn = Object.keys(filter)[0],
      field = Object.keys(filter[fn])[0],
      value = filter[fn][field];

    curried = _.curry(methods[fn]);
    return _.curry(curried(value));
  };

  /**
   * Test all filters in filtersTree for test which room to notify
   *
   * @param {Object} data
   * @returns {Promise} promise. Resolve a rooms list that we need to notify
   */
  this.testFilters = function (data) {
    var
      deferred = q.defer(),
      rooms = [];

    if (!data.collection) {
      deferred.reject('The data doesn\'t contain a collection');
      return deferred.promise;
    }

    if (!kuzzle.hotelClerk.filtersTree[data.collection]) {
      deferred.reject();
      return deferred.promise;
    }

    async.each(Object.keys(data.content), function (field, callbackContent) {
      var fieldFilters = kuzzle.hotelClerk.filtersTree[data.collection][field];

      if (!fieldFilters) {
        callbackContent();
        return false;
      }

      async.each(Object.keys(fieldFilters), function (functionName, callbackField) {
        if (fieldFilters[functionName].fn(data.content[field])) {
          rooms = rooms.concat(fieldFilters[functionName].rooms);
        }

        callbackField();
      }, function () {
        callbackContent();
      });
    }, function () {
      deferred.resolve(rooms);
    });

    return deferred.promise;
  };

};<|endoftext|>


<commit_before>
import redboxWrapper from './redboxWrapper'
import { destroyPlugin, destroy } from './destroy'

/**
 * @param {object}
 */
export default function createCreateInstance(PluginApi) {

	/**
	 * @param {object}
	 * @param {object}
	 * @return {object}
	 */
	return function createInstance(pluginObj, createPlugin) {
		pluginObj.plugin = createPlugin;
		pluginObj.hotReload = function(newPlugin) {
			redboxWrapper(pluginObj, () => destroyPlugin(pluginObj, newPlugin!==null));

			pluginObj.plugin = newPlugin===null ? null : (newPlugin || pluginObj.plugin);
			pluginObj.pluginApi = undefined;
			pluginObj.api = function(name) {};
			pluginObj.instances = [];

			pluginObj.plugin && redboxWrapper(pluginObj, function() {
				const pluginApi = new PluginApi({
					$element: pluginObj.$element,
					pluginName: pluginObj.pluginName,
					pluginId: pluginObj.pluginId,
					pluginObj: pluginObj,
					state: pluginObj.state,
					name: pluginObj.name,
				}, pluginObj.hotReload);

				pluginObj.pluginApi = pluginApi;
				pluginObj.api = pluginApi.eachApi.bind(pluginApi);
				pluginObj.pluginApi.createInstance = function(createPlugin, plugin) {
					plugin = plugin || pluginObj.pluginArgumentsObj;
					plugin = {...plugin}

					if (plugin.state) {
						plugin.state = plugin.state(createPlugin, pluginObj.instances.length);
					}

					const _pluginApi = pluginApi.spawn({
						$element: plugin.$element || pluginObj.$element,
						pluginName: pluginObj.pluginName,
						pluginId: pluginObj.pluginId,
						pluginObj: pluginObj,
						state: plugin.state,
						name: pluginObj.name,
					});

					const instance = createPlugin.call(_pluginApi, plugin)||{};
					pluginObj.instances.push(instance);

					return function() {
						if (pluginObj.instances.indexOf(instance)!==-1) {
							pluginObj.instances.splice(pluginObj.instances.indexOf(instance), 1);
						}

						destroy(instance);
					}
				}

				if (pluginObj.plugin.argumentObj) {
					pluginObj.instances.push(pluginObj.plugin.call(pluginApi, pluginObj.pluginArgumentsObj||{})||{});

				} else {
					pluginObj.instances.push(pluginObj.plugin.apply(pluginApi, pluginObj.pluginArguments||[])||{});
				}
			});
		}

		pluginObj.hotReload();
		return pluginObj;
	}
}
<commit_msg>Add pluginObj.reload method<commit_after>
import redboxWrapper from './redboxWrapper'
import { destroyPlugin, destroy } from './destroy'

/**
 * @param {object}
 */
export default function createCreateInstance(PluginApi) {

	/**
	 * @param {object}
	 * @param {object}
	 * @return {object}
	 */
	return function createInstance(pluginObj, createPlugin) {
		pluginObj.plugin = createPlugin;
		pluginObj.reload = function() {
			pluginObj.reloadData && pluginObj.reloadData();
			pluginObj.hotReload();
		}
		pluginObj.hotReload = function(newPlugin) {
			redboxWrapper(pluginObj, () => destroyPlugin(pluginObj, newPlugin!==null));

			pluginObj.plugin = newPlugin===null ? null : (newPlugin || pluginObj.plugin);
			pluginObj.pluginApi = undefined;
			pluginObj.api = function(name) {};
			pluginObj.instances = [];

			pluginObj.plugin && redboxWrapper(pluginObj, function() {
				const pluginApi = new PluginApi({
					$element: pluginObj.$element,
					pluginName: pluginObj.pluginName,
					pluginId: pluginObj.pluginId,
					pluginObj: pluginObj,
					state: pluginObj.state,
					name: pluginObj.name,
				}, pluginObj.hotReload);

				pluginObj.pluginApi = pluginApi;
				pluginObj.api = pluginApi.eachApi.bind(pluginApi);
				pluginObj.pluginApi.createInstance = function(createPlugin, plugin) {
					plugin = plugin || pluginObj.pluginArgumentsObj;
					plugin = {...plugin}

					if (plugin.state) {
						plugin.state = plugin.state(createPlugin, pluginObj.instances.length);
					}

					const _pluginApi = pluginApi.spawn({
						$element: plugin.$element || pluginObj.$element,
						pluginName: pluginObj.pluginName,
						pluginId: pluginObj.pluginId,
						pluginObj: pluginObj,
						state: plugin.state,
						name: pluginObj.name,
					});

					const instance = createPlugin.call(_pluginApi, plugin)||{};
					pluginObj.instances.push(instance);

					return function() {
						if (pluginObj.instances.indexOf(instance)!==-1) {
							pluginObj.instances.splice(pluginObj.instances.indexOf(instance), 1);
						}

						destroy(instance);
					}
				}

				if (pluginObj.plugin.argumentObj) {
					pluginObj.instances.push(pluginObj.plugin.call(pluginApi, pluginObj.pluginArgumentsObj||{})||{});

				} else {
					pluginObj.instances.push(pluginObj.plugin.apply(pluginApi, pluginObj.pluginArguments||[])||{});
				}
			});
		}

		pluginObj.hotReload();
		return pluginObj;
	}
}
<|endoftext|>


<commit_before>import './Job'
import './Queue'

import './Drivers/BaseDriver'
import './Drivers/BeanstalkDriver'
import './Drivers/RabbitDriver'

export class QueueFactory {
	app = null
	connections = { }
	jobs = { }
	drivers = {
		beanstalk: BeanstalkDriver,
		beanstalkd: BeanstalkDriver,
		rabbit: RabbitDriver,
		rabbitmq: RabbitDriver,
		amqp: RabbitDriver
	}

	constructor(app) {
		this.app = app
	}

	dispatch(job, connection = null) {
		return this.get(connection).dispatch(job)
	}

	status(job, connection = null) {
		return this.get(connection).status(job)
	}

	get(connection) {
		let name = null

		if(connection.isNil) {
			connection = this.app.config.get('queue.default')
		}

		if(typeof connection === 'string') {
			const q = this.connections[connection]

			if(!q.isNil) {
				return q
			}

			name = connection
			connection = this.app.config.get(`queue.connections.${name}`)
		}

		if(connection.isNil || typeof connection !== 'object') {
			throw new Error('Invalid config')
		}

		const config = { ...connection }
		const driverClass = this.drivers[config.driver]

		if(driverClass.isNil) {
			throw new Error(`Unsupported queue driver: ${config.driver}`)
		}

		connection = this.make(driverClass, config)

		if(!name.isNil) {
			this.connections[name] = connection
		}

		return connection
	}

	make(driverClass, config) {
		return new Queue(this.app, this, new driverClass(this.app, config))
	}

	registerDriver(name, driverClass) {
		if(!(driverClass.prototype instanceof BaseDriver)) {
			throw new Error('All queue driver classes must inherit from BaseDriver')
		}

		this.drivers[name] = driverClass
	}

	register(jobClass) {
		if(!(jobClass.prototype instanceof Job)) {
			throw new Error('All job classes must inherit from Job')
		} else if(jobClass.jobName.isNil) {
			throw new Error('Invalid Job, must have jobName set.')
		}

		this.jobs[jobClass.jobName] = jobClass
	}

	destroy() {
		return Promise.all(Object.values(this.connections).map(connection => connection.destroy()))
	}

}
<commit_msg>Registered FaktoryDriver with QueueFactory<commit_after>import './Job'
import './Queue'

import './Drivers/BaseDriver'
import './Drivers/BeanstalkDriver'
import './Drivers/FaktoryDriver'
import './Drivers/RabbitDriver'

export class QueueFactory {
	app = null
	connections = { }
	jobs = { }
	drivers = {
		beanstalk: BeanstalkDriver,
		beanstalkd: BeanstalkDriver,
		faktory: FaktoryDriver,
		rabbit: RabbitDriver,
		rabbitmq: RabbitDriver,
		amqp: RabbitDriver
	}

	constructor(app) {
		this.app = app
	}

	dispatch(job, connection = null) {
		return this.get(connection).dispatch(job)
	}

	status(job, connection = null) {
		return this.get(connection).status(job)
	}

	get(connection) {
		let name = null

		if(connection.isNil) {
			connection = this.app.config.get('queue.default')
		}

		if(typeof connection === 'string') {
			const q = this.connections[connection]

			if(!q.isNil) {
				return q
			}

			name = connection
			connection = this.app.config.get(`queue.connections.${name}`)
		}

		if(connection.isNil || typeof connection !== 'object') {
			throw new Error('Invalid config')
		}

		const config = { ...connection }
		const driverClass = this.drivers[config.driver]

		if(driverClass.isNil) {
			throw new Error(`Unsupported queue driver: ${config.driver}`)
		}

		connection = this.make(driverClass, config)

		if(!name.isNil) {
			this.connections[name] = connection
		}

		return connection
	}

	make(driverClass, config) {
		return new Queue(this.app, this, new driverClass(this.app, config))
	}

	registerDriver(name, driverClass) {
		if(!(driverClass.prototype instanceof BaseDriver)) {
			throw new Error('All queue driver classes must inherit from BaseDriver')
		}

		this.drivers[name] = driverClass
	}

	register(jobClass) {
		if(!(jobClass.prototype instanceof Job)) {
			throw new Error('All job classes must inherit from Job')
		} else if(jobClass.jobName.isNil) {
			throw new Error('Invalid Job, must have jobName set.')
		}

		this.jobs[jobClass.jobName] = jobClass
	}

	destroy() {
		return Promise.all(Object.values(this.connections).map(connection => connection.destroy()))
	}

}
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

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.
*/

var MatrixClientPeg = require("./MatrixClientPeg");
var CallHandler = require("./CallHandler");

function textForMemberEvent(ev) {
    // XXX: SYJS-16 "sender is sometimes null for join messages"
    var senderName = ev.sender ? ev.sender.name : ev.getSender();
    var targetName = ev.target ? ev.target.name : ev.getStateKey();
    var ConferenceHandler = CallHandler.getConferenceHandler();
    var reason = ev.getContent().reason ? (
        " Reason: " + ev.getContent().reason
    ) : "";
    switch (ev.getContent().membership) {
        case 'invite':
            var threePidContent = ev.getContent().third_party_invite;
            if (threePidContent) {
                if (threePidContent.display_name) {
                    return targetName + " accepted the invitation for " +
                        threePidContent.display_name + ".";
                } else {
                    return targetName + " accepted an invitation.";
                }
            }
            else {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return senderName + " requested a VoIP conference";
                }
                else {
                    return senderName + " invited " + targetName + ".";
                }
            }
        case 'ban':
            return senderName + " banned " + targetName + "." + reason;
        case 'join':
            if (ev.getPrevContent() && ev.getPrevContent().membership == 'join') {
                if (ev.getPrevContent().displayname && ev.getContent().displayname && ev.getPrevContent().displayname != ev.getContent().displayname) {
                    return ev.getSender() + " changed their display name from " +
                        ev.getPrevContent().displayname + " to " +
                        ev.getContent().displayname;
                } else if (!ev.getPrevContent().displayname && ev.getContent().displayname) {
                    return ev.getSender() + " set their display name to " + ev.getContent().displayname;
                } else if (ev.getPrevContent().displayname && !ev.getContent().displayname) {
                    return ev.getSender() + " removed their display name";
                } else if (ev.getPrevContent().avatar_url && !ev.getContent().avatar_url) {
                    return ev.getSender() + " removed their profile picture";
                } else if (ev.getPrevContent().avatar_url && ev.getContent().avatar_url && ev.getPrevContent().avatar_url != ev.getContent().avatar_url) {
                    return ev.getSender() + " changed their profile picture";
                } else if (!ev.getPrevContent().avatar_url && ev.getContent().avatar_url) {
                    return ev.getSender() + " set a profile picture";
                }
            } else {
                if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return "VoIP conference started";
                }
                else {
                    return targetName + " joined the room.";
                }
            }
            return '';
        case 'leave':
            if (ev.getSender() === ev.getStateKey()) {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return "VoIP conference finished";
                }
                else if (ev.getPrevContent().membership === "invite") {
                    return targetName + " rejected the invitation.";
                }
                else {
                    return targetName + " left the room.";
                }
            }
            else if (ev.getPrevContent().membership === "ban") {
                return senderName + " unbanned " + targetName + ".";
            }
            else if (ev.getPrevContent().membership === "join") {
                return senderName + " kicked " + targetName + "." + reason;
            }
            else if (ev.getPrevContent().membership === "invite") {
                return senderName + " withdrew " + targetName + "'s invitation." + reason;
            }
            else {
                return targetName + " left the room.";
            }
    }
};

function textForTopicEvent(ev) {
    var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    return senderDisplayName + ' changed the topic to "' + ev.getContent().topic + '"';
};

function textForRoomNameEvent(ev) {
    var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    return senderDisplayName + ' changed the room name to "' + ev.getContent().name + '"';
};

function textForMessageEvent(ev) {
    var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    var message = senderDisplayName + ': ' + ev.getContent().body;
    if (ev.getContent().msgtype === "m.emote") {
        message = "* " + senderDisplayName + " " + message;
    } else if (ev.getContent().msgtype === "m.image") {
        message = senderDisplayName + " sent an image.";
    }
    return message;
};

function textForCallAnswerEvent(event) {
    var senderName = event.sender ? event.sender.name : "Someone";
    var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)";
    return senderName + " answered the call." + supported;
};

function textForCallHangupEvent(event) {
    var senderName = event.sender ? event.sender.name : "Someone";
    var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)";
    return senderName + " ended the call." + supported;
};

function textForCallInviteEvent(event) {
    var senderName = event.sender ? event.sender.name : "Someone";
    // FIXME: Find a better way to determine this from the event?
    var type = "voice";
    if (event.getContent().offer && event.getContent().offer.sdp &&
            event.getContent().offer.sdp.indexOf('m=video') !== -1) {
        type = "video";
    }
    var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)";
    return senderName + " placed a " + type + " call." + supported;
};

function textForThreePidInviteEvent(event) {
    var senderName = event.sender ? event.sender.name : event.getSender();
    return senderName + " sent an invitation to " + event.getContent().display_name +
     " to join the room.";
};

function textForHistoryVisibilityEvent(event) {
    var senderName = event.sender ? event.sender.name : event.getSender();
    var vis = event.getContent().history_visibility;
    var text = senderName + " made future room history visible to ";
    if (vis === "invited") {
        text += "all room members, from the point they are invited.";
    }
    else if (vis === "joined") {
        text += "all room members, from the point they joined.";
    }
    else if (vis === "shared") {
        text += "all room members.";
    }
    else if (vis === "world_readable") {
        text += "anyone.";
    }
    else {
        text += " unknown (" + vis + ")";
    }
    return text;
};

var handlers = {
    'm.room.message': textForMessageEvent,
    'm.room.name':    textForRoomNameEvent,
    'm.room.topic':   textForTopicEvent,
    'm.room.member':  textForMemberEvent,
    'm.call.invite':  textForCallInviteEvent,
    'm.call.answer':  textForCallAnswerEvent,
    'm.call.hangup':  textForCallHangupEvent,
    'm.room.third_party_invite': textForThreePidInviteEvent,
    'm.room.history_visibility': textForHistoryVisibilityEvent,
};

module.exports = {
    textForEvent: function(ev) {
        var hdlr = handlers[ev.getType()];
        if (!hdlr) return "";
        return hdlr(ev);
    }
}
<commit_msg>fix leaked user_id on various textual events<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

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.
*/

var MatrixClientPeg = require("./MatrixClientPeg");
var CallHandler = require("./CallHandler");

function textForMemberEvent(ev) {
    // XXX: SYJS-16 "sender is sometimes null for join messages"
    var senderName = ev.sender ? ev.sender.name : ev.getSender();
    var targetName = ev.target ? ev.target.name : ev.getStateKey();
    var ConferenceHandler = CallHandler.getConferenceHandler();
    var reason = ev.getContent().reason ? (
        " Reason: " + ev.getContent().reason
    ) : "";
    switch (ev.getContent().membership) {
        case 'invite':
            var threePidContent = ev.getContent().third_party_invite;
            if (threePidContent) {
                if (threePidContent.display_name) {
                    return targetName + " accepted the invitation for " +
                        threePidContent.display_name + ".";
                } else {
                    return targetName + " accepted an invitation.";
                }
            }
            else {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return senderName + " requested a VoIP conference";
                }
                else {
                    return senderName + " invited " + targetName + ".";
                }
            }
        case 'ban':
            return senderName + " banned " + targetName + "." + reason;
        case 'join':
            if (ev.getPrevContent() && ev.getPrevContent().membership == 'join') {
                if (ev.getPrevContent().displayname && ev.getContent().displayname && ev.getPrevContent().displayname != ev.getContent().displayname) {
                    return ev.getSender() + " changed their display name from " +
                        ev.getPrevContent().displayname + " to " +
                        ev.getContent().displayname;
                } else if (!ev.getPrevContent().displayname && ev.getContent().displayname) {
                    return ev.getSender() + " set their display name to " + ev.getContent().displayname;
                } else if (ev.getPrevContent().displayname && !ev.getContent().displayname) {
                    return ev.getSender() + " removed their display name (" + ev.getPrevContent().displayname + ")";
                } else if (ev.getPrevContent().avatar_url && !ev.getContent().avatar_url) {
                    return senderName + " removed their profile picture";
                } else if (ev.getPrevContent().avatar_url && ev.getContent().avatar_url && ev.getPrevContent().avatar_url != ev.getContent().avatar_url) {
                    return senderName + " changed their profile picture";
                } else if (!ev.getPrevContent().avatar_url && ev.getContent().avatar_url) {
                    return senderName + " set a profile picture";
                }
            } else {
                if (!ev.target) console.warn("Join message has no target! -- " + ev.getContent().state_key);
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return "VoIP conference started";
                }
                else {
                    return targetName + " joined the room.";
                }
            }
            return '';
        case 'leave':
            if (ev.getSender() === ev.getStateKey()) {
                if (ConferenceHandler && ConferenceHandler.isConferenceUser(ev.getStateKey())) {
                    return "VoIP conference finished";
                }
                else if (ev.getPrevContent().membership === "invite") {
                    return targetName + " rejected the invitation.";
                }
                else {
                    return targetName + " left the room.";
                }
            }
            else if (ev.getPrevContent().membership === "ban") {
                return senderName + " unbanned " + targetName + ".";
            }
            else if (ev.getPrevContent().membership === "join") {
                return senderName + " kicked " + targetName + "." + reason;
            }
            else if (ev.getPrevContent().membership === "invite") {
                return senderName + " withdrew " + targetName + "'s invitation." + reason;
            }
            else {
                return targetName + " left the room.";
            }
    }
};

function textForTopicEvent(ev) {
    var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    return senderDisplayName + ' changed the topic to "' + ev.getContent().topic + '"';
};

function textForRoomNameEvent(ev) {
    var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    return senderDisplayName + ' changed the room name to "' + ev.getContent().name + '"';
};

function textForMessageEvent(ev) {
    var senderDisplayName = ev.sender && ev.sender.name ? ev.sender.name : ev.getSender();

    var message = senderDisplayName + ': ' + ev.getContent().body;
    if (ev.getContent().msgtype === "m.emote") {
        message = "* " + senderDisplayName + " " + message;
    } else if (ev.getContent().msgtype === "m.image") {
        message = senderDisplayName + " sent an image.";
    }
    return message;
};

function textForCallAnswerEvent(event) {
    var senderName = event.sender ? event.sender.name : "Someone";
    var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)";
    return senderName + " answered the call." + supported;
};

function textForCallHangupEvent(event) {
    var senderName = event.sender ? event.sender.name : "Someone";
    var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)";
    return senderName + " ended the call." + supported;
};

function textForCallInviteEvent(event) {
    var senderName = event.sender ? event.sender.name : "Someone";
    // FIXME: Find a better way to determine this from the event?
    var type = "voice";
    if (event.getContent().offer && event.getContent().offer.sdp &&
            event.getContent().offer.sdp.indexOf('m=video') !== -1) {
        type = "video";
    }
    var supported = MatrixClientPeg.get().supportsVoip() ? "" : " (not supported by this browser)";
    return senderName + " placed a " + type + " call." + supported;
};

function textForThreePidInviteEvent(event) {
    var senderName = event.sender ? event.sender.name : event.getSender();
    return senderName + " sent an invitation to " + event.getContent().display_name +
     " to join the room.";
};

function textForHistoryVisibilityEvent(event) {
    var senderName = event.sender ? event.sender.name : event.getSender();
    var vis = event.getContent().history_visibility;
    var text = senderName + " made future room history visible to ";
    if (vis === "invited") {
        text += "all room members, from the point they are invited.";
    }
    else if (vis === "joined") {
        text += "all room members, from the point they joined.";
    }
    else if (vis === "shared") {
        text += "all room members.";
    }
    else if (vis === "world_readable") {
        text += "anyone.";
    }
    else {
        text += " unknown (" + vis + ")";
    }
    return text;
};

var handlers = {
    'm.room.message': textForMessageEvent,
    'm.room.name':    textForRoomNameEvent,
    'm.room.topic':   textForTopicEvent,
    'm.room.member':  textForMemberEvent,
    'm.call.invite':  textForCallInviteEvent,
    'm.call.answer':  textForCallAnswerEvent,
    'm.call.hangup':  textForCallHangupEvent,
    'm.room.third_party_invite': textForThreePidInviteEvent,
    'm.room.history_visibility': textForHistoryVisibilityEvent,
};

module.exports = {
    textForEvent: function(ev) {
        var hdlr = handlers[ev.getType()];
        if (!hdlr) return "";
        return hdlr(ev);
    }
}
<|endoftext|>


<commit_before>import AmpEnvelope from "../Components/AmpEnvelope";

export default class Voice {
	constructor(context, type ="sawtooth") {
		this.context = context;
		this.type = type;
		this.value = -1;
		this.gain = 0.1;
		this.output = this.context.createGain();
		this.partials = [];
		this.output.gain.value = this.gain;
		this.ampEnvelope = new AmpEnvelope(this.context);
		this.ampEnvelope.connect(this.output);
		this.voicePartials();
	}

	voicePartials() {
		let osc = this.context.createOscillator();
			osc.type = this.type;
			osc.connect(this.ampEnvelope.output);
			osc.start(this.context.currentTime);
		this.partials.push(osc);
	}

	on(MidiEvent) {
		this.value = MidiEvent.value;
		this.partials.forEach((osc) => {
			osc.frequency.value = MidiEvent.frequency;
		});
		this.ampEnvelope.on(MidiEvent.velocity);
	}

	off(MidiEvent) {
		this.ampEnvelope.off(MidiEvent);
		this.partials.forEach((osc) => {
			osc.stop(this.context.currentTime + this.ampEnvelope.release * 4);
		});
	}

	connect(destination) {
		this.output.connect(destination);
	}
}<commit_msg>Voices can choose to skip creation of partials on creation.<commit_after>import AmpEnvelope from "../Components/AmpEnvelope";

export default class Voice {
	constructor(context, type ="sawtooth") {
		this.context = context;
		this.type = type;
		this.value = -1;
		this.gain = 0.1;
		this.output = this.context.createGain();
		this.partials = [];
		this.output.gain.value = this.gain;
		this.ampEnvelope = new AmpEnvelope(this.context);
		this.ampEnvelope.connect(this.output);
		if(type != "none") {
			this.voicePartials();
		}
	}

	voicePartials() {
		let osc = this.context.createOscillator();
			osc.type = this.type;
			osc.connect(this.ampEnvelope.output);
			osc.start(this.context.currentTime);
		this.partials.push(osc);
	}

	on(MidiEvent) {
		this.value = MidiEvent.value;
		this.partials.forEach((osc) => {
			osc.frequency.value = MidiEvent.frequency;
		});
		this.ampEnvelope.on(MidiEvent.velocity || MidiEvent);
	}

	off(MidiEvent) {
		this.ampEnvelope.off(MidiEvent);
		this.partials.forEach((osc) => {
			osc.stop(this.context.currentTime + this.ampEnvelope.release * 4);
		});
	}

	connect(destination) {
		this.output.connect(destination);
	}
}<|endoftext|>