<commit_before>/*!
 * Original idea: https://github.com/Nycto/PicoModal
 * Accessibility inspiration: https://github.com/nico3333fr/jquery-accessible-modal-window-aria
 * MIT License (https://github.com/Aymkdn/picoModal-Accessible/blob/master/LICENSE)
*/
!function(name, definition) {
  if (typeof module != 'undefined') module.exports = definition()
  else if (typeof define == 'function' && typeof define.amd == 'object') define(definition)
  else this[name] = definition()
}('picoModal', function() {

  var picoModal = (function(window, document) {
    "use strict";

    // Generates observable objects that can be watched and triggered
    var observable = function() {
      var callbacks = [];
      return {
        watch: function(callback) {
          callbacks.push(callback);
        },
        trigger: function() {
          for (var i = 0; i < callbacks.length; i++) {
            window.setTimeout(callbacks[i], 1);
          }
        }
      };
    };

    // A small interface for creating and managing a dom element
    var make = function(parent, tag) {
      if (arguments.length == 1 && typeof parent === "string") {
        tag = parent;
        parent = null;
      }
      tag = tag || 'div';

      var elem = document.createElement(tag);
      (parent || document.body).appendChild(elem);

      var iface = {

        elem: elem,

        // Creates a child of this node
        child: function(tag) {
          return make(elem, tag || 'a');
        },

        // Applies a set of styles to an element
        stylize: function(styles) {
          styles = styles || {};

          if (typeof styles.opacity !== "undefined") {
            styles.filter =
              "alpha(opacity=" + (styles.opacity * 100) + ")";
          }

          for (var prop in styles) {
            if (styles.hasOwnProperty(prop)) {
              elem.style[prop] = styles[prop];
            }
          }

          return iface;
        },

        // Adds a class name
        clazz: function(clazz) {
          elem.className += clazz;
          return iface;
        },
        // set attributes
        setAttr: function(attr) {
          for (var a in attr) {
            if (attr.hasOwnProperty(a)) {
              elem.setAttribute(a, attr[a]);
            }
          }
          return iface;
        },

        // set an element invisible for users but not readers
        invisible: function() {
          this.stylize({
            "border":"0 none",
            "clip":"rect(0px, 0px, 0px, 0px)",
            "height":"1px",
            "margin":"-1px",
            "overflow":"hidden",
            "padding":"0",
            "position":"absolute",
            "width":"1px"
          });
          return iface;
        },

        // Sets the HTML
        html: function(content) {
          elem.innerHTML = content;
          return iface;
        },

        // Returns the width of this element
        getWidth: function() {
          return elem.clientWidth;
        },

        // Adds a click handler to this element
        onClick: function(callback) {
          if (elem.attachEvent) {
            elem.attachEvent('onclick', callback);
          } else {
            elem.addEventListener('click', callback);
          }

          return iface;
        },

        // Removes this element from the DOM
        destroy: function() {
          document.body.removeChild(elem);
          return iface;
        }

      };

      return iface;
    };

    // An interface for generating the grey-out effect
    var overlay = function(getOption) {

      // The registered on click events
      var clickCallbacks = observable();

      // The overlay element
      var elem = make()
        .setAttr({"title":"Close this windows"})
        .clazz("pico-overlay")
        .stylize({
          display: "block",
          position: "fixed",
          top: "0px",
          left: "0px",
          height: "100%",
          width: "100%",
          zIndex: 10000
        })
        .stylize(getOption('overlayStyles', {
          opacity: 0.5,
          background: "#000"
        }))
        .onClick(clickCallbacks.trigger);

      // create a hidden element that permits to be read and that explains we can close the overlay by clicking
      elem.child('span')
        .invisible()
        .setAttr({"tabindex":"0"})
        .html(getOption('closeHtml', "Close"));

      return {
        elem: elem.elem,
        destroy: elem.destroy,
        onClick: clickCallbacks.watch
      };
    };

    // Wrap an HTMLElement around another HTMLElement or an array of them.
    // source: http://stackoverflow.com/questions/3337587/wrapping-a-set-of-dom-elements-using-javascript/13169465#13169465
    var wrapAll = function(father, elms) {
        var el = elms.length ? elms[0] : elms;

        // Cache the current parent and sibling of the first element.
        var parent  = el.parentNode;
        var sibling = el.nextSibling;

        // Wrap the first element (is automatically removed from its
        // current parent).
        father.appendChild(el);

        // Wrap all other elements (if applicable). Each element is
        // automatically removed from its current parent and from the elms
        // array.
        while (elms.length) {
            father.appendChild(elms[0]);
        }

        // If the first element had a sibling, insert the wrapper before the
        // sibling to maintain the HTML structure; otherwise, just append it
        // to the parent.
        if (sibling) {
            try { parent.insertBefore(father, sibling) } catch(e) {}
        } else {
            try { parent.appendChild(father) } catch(e) {}
        }
    };

    // A function for easily displaying a modal with the given content
    return function(options) {

      if (typeof options === "string") {
        options = {
          content: options
        };
      }

      // we record the focused element
      var focusElement = document.activeElement;

      // the body content must be grouped into a 'div' in order to use aria-hidden on it
      !function() {
        var frag = document.createDocumentFragment();
        var father = document.createElement('div');
        father.setAttribute("aria-hidden", "true");
        father.setAttribute("id", "picoModalProtect");
        wrapAll(father, document.body.children);
        document.body.appendChild(father);
      }();

      // Returns a named option if it has been explicitly defined. Otherwise,
      // it returns the given default value
      function getOption(opt, defaultValue) {
        return options[opt] === void(0) ? defaultValue : options[opt];
      }
      var closeCallbacks = observable();

      var elem = make('dialog')
        .clazz("pico-content")
        .stylize({
          display: 'block',
          position: 'fixed',
          zIndex: 10001,
          left: "50%",
          top: "50px"
        })
        .setAttr({"role":"dialog"})
        .html(options.content);

      var close = function() {
        shadow.destroy();
        elem.destroy();
        // remove picoModalProtect
        var body = document.body;
        var father = document.getElementById('picoModalProtect');
        wrapAll(body, father.children);
        father.parentNode.removeChild(father);
        // get back the focus
        if (focusElement) focusElement.focus();
        closeCallbacks.trigger();
      };

      // the close button at first
      var closeButton;
      if (getOption('closeButton', true)) {
        closeButton = elem.html("").child('button')
          .html(getOption('closeHtml', "Close"))
          .clazz("pico-close")
          .stylize(getOption('closeStyles', {
            borderRadius: "2px",
            cursor: "pointer",
            height: "auto",
            width: "auto",
            position: "absolute",
            top: "5px",
            right: "5px",
            fontSize: "16px",
            textAlign: "center",
            lineHeight: "15px",
            background: "#CCC"
          }))
          .setAttr({"tabindex":"0"})
          .onClick(close);
          // move the button at the top of the modal
          closeButton.elem.insertAdjacentHTML('afterend', options.content);
      }

      var width = getOption('width', elem.getWidth());

      elem.stylize({
          width: width + "px",
          margin: "0 0 0 " + (-(width / 2) + "px")
        })
        .stylize(getOption('modalStyles', {
          backgroundColor: "white",
          padding: "20px",
          borderRadius: "5px"
        }));

      var shadow = overlay(getOption);
      if (getOption('overlayClose', true)) {
        shadow.onClick(close);
      }

      // get focus on the close element or on a special message created inside the modal
      var focusInModal;
      if (!options.focusOn) {
        if (getOption('closeButton', true)) {
          closeButton.elem.focus();
        } else {
          !function() {
            focusInModal = elem.html("").child('span').setAttr({"lang":"en","tabindex":"0"}).html('popup');
            elem.child('div').html(options.content);
            focusInModal.elem.focus();
            setTimeout(function() { focusInModal.invisible() }, 250);
          }();
        }
      } else {
        focusInModal = document.querySelector(getOption('focusOn'));
        if (focusInModal) {
          focusInModal.setAttribute("tabindex","0");
          focusInModal.focus();
        }
      }

      return {
        modalElem: elem.elem,
        closeElem: closeButton ? closeButton.elem : null,
        overlayElem: shadow.elem,
        close: close,
        onClose: closeCallbacks.watch
      };
    };

  }(window, document));

  return picoModal;

});
<commit_msg>Fix issue<commit_after>/*!
 * Original idea: https://github.com/Nycto/PicoModal
 * Accessibility inspiration: https://github.com/nico3333fr/jquery-accessible-modal-window-aria
 * MIT License (https://github.com/Aymkdn/picoModal-Accessible/blob/master/LICENSE)
*/
!function(name, definition) {
  if (typeof module != 'undefined') module.exports = definition()
  else if (typeof define == 'function' && typeof define.amd == 'object') define(definition)
  else this[name] = definition()
}('picoModal', function() {

  var picoModal = (function(window, document) {
    "use strict";

    // Generates observable objects that can be watched and triggered
    var observable = function() {
      var callbacks = [];
      return {
        watch: function(callback) {
          callbacks.push(callback);
        },
        trigger: function() {
          for (var i = 0; i < callbacks.length; i++) {
            window.setTimeout(callbacks[i], 1);
          }
        }
      };
    };

    // A small interface for creating and managing a dom element
    var make = function(parent, tag) {
      if (arguments.length == 1 && typeof parent === "string") {
        tag = parent;
        parent = null;
      }
      tag = tag || 'div';

      var elem = document.createElement(tag);
      (parent || document.body).appendChild(elem);

      var iface = {

        elem: elem,

        // Creates a child of this node
        child: function(tag) {
          return make(elem, tag || 'a');
        },

        // Applies a set of styles to an element
        stylize: function(styles) {
          styles = styles || {};

          if (typeof styles.opacity !== "undefined") {
            styles.filter =
              "alpha(opacity=" + (styles.opacity * 100) + ")";
          }

          for (var prop in styles) {
            if (styles.hasOwnProperty(prop)) {
              elem.style[prop] = styles[prop];
            }
          }

          return iface;
        },

        // Adds a class name
        clazz: function(clazz) {
          elem.className += clazz;
          return iface;
        },
        // set attributes
        setAttr: function(attr) {
          for (var a in attr) {
            if (attr.hasOwnProperty(a)) {
              elem.setAttribute(a, attr[a]);
            }
          }
          return iface;
        },

        // set an element invisible for users but not readers
        invisible: function() {
          this.stylize({
            "border":"0 none",
            "clip":"rect(0px, 0px, 0px, 0px)",
            "height":"1px",
            "margin":"-1px",
            "overflow":"hidden",
            "padding":"0",
            "position":"absolute",
            "width":"1px"
          });
          return iface;
        },

        // Sets the HTML
        html: function(content) {
          elem.innerHTML = content;
          return iface;
        },

        // Returns the width of this element
        getWidth: function() {
          return elem.clientWidth;
        },

        // Adds a click handler to this element
        onClick: function(callback) {
          if (elem.attachEvent) {
            elem.attachEvent('onclick', callback);
          } else {
            elem.addEventListener('click', callback);
          }

          return iface;
        },

        // Removes this element from the DOM
        destroy: function() {
          document.body.removeChild(elem);
          return iface;
        }

      };

      return iface;
    };

    // An interface for generating the grey-out effect
    var overlay = function(getOption) {

      // The registered on click events
      var clickCallbacks = observable();

      // The overlay element
      var elem = make()
        .setAttr({"title":"Close this windows"})
        .clazz("pico-overlay")
        .stylize({
          display: "block",
          position: "fixed",
          top: "0px",
          left: "0px",
          height: "100%",
          width: "100%",
          zIndex: 10000
        })
        .stylize(getOption('overlayStyles', {
          opacity: 0.5,
          background: "#000"
        }))
        .onClick(clickCallbacks.trigger);

      // create a hidden element that permits to be read and that explains we can close the overlay by clicking
      if (getOption('overlayClose', true)) {
        elem.child('span')
          .invisible()
          .setAttr({"tabindex":"0"})
          .html(getOption('closeHtml', "Close"));
      }

      return {
        elem: elem.elem,
        destroy: elem.destroy,
        onClick: clickCallbacks.watch
      };
    };

    // Wrap an HTMLElement around another HTMLElement or an array of them.
    // source: http://stackoverflow.com/questions/3337587/wrapping-a-set-of-dom-elements-using-javascript/13169465#13169465
    var wrapAll = function(father, elms) {
        var el = elms.length ? elms[0] : elms;

        // Cache the current parent and sibling of the first element.
        var parent  = el.parentNode;
        var sibling = el.nextSibling;

        // Wrap the first element (is automatically removed from its
        // current parent).
        father.appendChild(el);

        // Wrap all other elements (if applicable). Each element is
        // automatically removed from its current parent and from the elms
        // array.
        while (elms.length) {
            father.appendChild(elms[0]);
        }

        // If the first element had a sibling, insert the wrapper before the
        // sibling to maintain the HTML structure; otherwise, just append it
        // to the parent.
        if (sibling) {
            try { parent.insertBefore(father, sibling) } catch(e) {}
        } else {
            try { parent.appendChild(father) } catch(e) {}
        }
    };

    // A function for easily displaying a modal with the given content
    return function(options) {

      if (typeof options === "string") {
        options = {
          content: options
        };
      }

      // we record the focused element
      var focusElement = document.activeElement;

      // the body content must be grouped into a 'div' in order to use aria-hidden on it
      !function() {
        var frag = document.createDocumentFragment();
        var father = document.createElement('div');
        father.setAttribute("aria-hidden", "true");
        father.setAttribute("id", "picoModalProtect");
        wrapAll(father, document.body.children);
        document.body.appendChild(father);
      }();

      // Returns a named option if it has been explicitly defined. Otherwise,
      // it returns the given default value
      function getOption(opt, defaultValue) {
        return options[opt] === void(0) ? defaultValue : options[opt];
      }
      var closeCallbacks = observable();

      var elem = make('dialog')
        .clazz("pico-content")
        .stylize({
          display: 'block',
          position: 'fixed',
          zIndex: 10001,
          left: "50%",
          top: "50px"
        })
        .setAttr({"role":"dialog"})
        .html(options.content);

      var close = function() {
        shadow.destroy();
        elem.destroy();
        // remove picoModalProtect
        var body = document.body;
        var father = document.getElementById('picoModalProtect');
        wrapAll(body, father.children);
        father.parentNode.removeChild(father);
        // get back the focus
        if (focusElement) focusElement.focus();
        closeCallbacks.trigger();
      };

      // the close button at first
      var closeButton;
      if (getOption('closeButton', true)) {
        closeButton = elem.html("").child('button')
          .html(getOption('closeHtml', "Close"))
          .clazz("pico-close")
          .stylize(getOption('closeStyles', {
            borderRadius: "2px",
            cursor: "pointer",
            height: "auto",
            width: "auto",
            position: "absolute",
            top: "5px",
            right: "5px",
            fontSize: "16px",
            textAlign: "center",
            lineHeight: "15px",
            background: "#CCC"
          }))
          .setAttr({"tabindex":"0"})
          .onClick(close);
          // move the button at the top of the modal
          closeButton.elem.insertAdjacentHTML('afterend', options.content);
      }

      var width = getOption('width', elem.getWidth());

      elem.stylize({
          width: width + "px",
          margin: "0 0 0 " + (-(width / 2) + "px")
        })
        .stylize(getOption('modalStyles', {
          backgroundColor: "white",
          padding: "20px",
          borderRadius: "5px"
        }));

      var shadow = overlay(getOption);
      if (getOption('overlayClose', true)) {
        shadow.onClick(close);
      }

      // get focus on the close element or on a special message created inside the modal
      var focusInModal;
      if (!options.focusOn) {
        if (getOption('closeButton', true)) {
          closeButton.elem.focus();
        } else {
          !function() {
            focusInModal = elem.html("").child('span').setAttr({"lang":"en","tabindex":"0"}).html('popup');
            elem.child('div').html(options.content);
            focusInModal.elem.focus();
            setTimeout(function() { focusInModal.invisible() }, 250);
          }();
        }
      } else {
        focusInModal = document.querySelector(getOption('focusOn'));
        if (focusInModal) {
          focusInModal.setAttribute("tabindex","0");
          focusInModal.focus();
        }
      }

      return {
        modalElem: elem.elem,
        closeElem: closeButton ? closeButton.elem : null,
        overlayElem: shadow.elem,
        close: close,
        onClose: closeCallbacks.watch
      };
    };

  }(window, document));

  return picoModal;

});
<|endoftext|>


<commit_before>import React, { Component } from 'react'
import classNames from 'classnames'
import styles from './styles.less'
import formStyles from '../styles.less'

export default class Textarea extends Component {
   static propTypes = {
      className: React.PropTypes.string,
	   disabled: React.PropTypes.bool,
      error: React.PropTypes.string,
      id: React.PropTypes.string,
      label: React.PropTypes.string,
      name: React.PropTypes.string,
      onBlur: React.PropTypes.func,
      onChange: React.PropTypes.func,
      placeholder: React.PropTypes.string,
      rows: React.PropTypes.string,
      touched: React.PropTypes.bool,
      value: React.PropTypes.string
   }

   static defaultProps = {
 	   disabled: false,
      rows: '5',
      value: ''
   }

   constructor(props, context) {
      super(props, context)
      this.handleChange = this.handleChange.bind(this)
      this.state = {
         value: props.value
      }
   }

   componentWillReceiveProps(newProps) {
      if (newProps.value !== this.state.value) {
         this.setState({ value: newProps.value })
      }
   }

   handleChange(event) {
      this.setState({ value: event.target.value })
      if (this.props.onChange) {
         this.props.onChange(event, event.target.value)
      }
   }

   render() {
      const classes = [styles.textarea, this.props.className]

      return (

            {this.props.label && {this.props.label}}
            <textarea
               className={classNames(classes)}
               disabled={this.props.disabled}
               id={this.props.id}
               onBlur={this.props.onBlur}
               onChange={this.handleChange}
               name={this.props.name}
               placeholder={this.props.placeholder}
               value={this.state.value}
               rows={this.props.rows}
            />
            {this.props.touched && this.props.error &&

                  {this.props.error}

            }

      )
   }
}
<commit_msg>minor space fixes<commit_after>import React, { Component } from 'react'
import classNames from 'classnames'
import styles from './styles.less'
import formStyles from '../styles.less'

export default class Textarea extends Component {
   static propTypes = {
      className: React.PropTypes.string,
      disabled: React.PropTypes.bool,
      error: React.PropTypes.string,
      id: React.PropTypes.string,
      label: React.PropTypes.string,
      name: React.PropTypes.string,
      onBlur: React.PropTypes.func,
      onChange: React.PropTypes.func,
      placeholder: React.PropTypes.string,
      rows: React.PropTypes.string,
      touched: React.PropTypes.bool,
      value: React.PropTypes.string
   }

   static defaultProps = {
      disabled: false,
      rows: '5',
      value: ''
   }

   constructor(props, context) {
      super(props, context)
      this.handleChange = this.handleChange.bind(this)
      this.state = {
         value: props.value
      }
   }

   componentWillReceiveProps(newProps) {
      if (newProps.value !== this.state.value) {
         this.setState({ value: newProps.value })
      }
   }

   handleChange(event) {
      this.setState({ value: event.target.value })
      if (this.props.onChange) {
         this.props.onChange(event, event.target.value)
      }
   }

   render() {
      const classes = [styles.textarea, this.props.className]

      return (

            {this.props.label && {this.props.label}}
            <textarea
               className={classNames(classes)}
               disabled={this.props.disabled}
               id={this.props.id}
               onBlur={this.props.onBlur}
               onChange={this.handleChange}
               name={this.props.name}
               placeholder={this.props.placeholder}
               value={this.state.value}
               rows={this.props.rows}
            />
            {this.props.touched && this.props.error &&

                  {this.props.error}

            }

      )
   }
}
<|endoftext|>


<commit_before>// ==UserScript==
// @name            Scroll 1px on Wheel over AutoScroll
// @include         main
// @startup         UC.WheelAutoScroll_1px.exec(win);
// @shutdown        UC.WheelAutoScroll_1px.destroy();
// @author          xiaoxiaoflood
// @note            if apz.autoscroll.enabled = true, restart is needed
// @onlyonce
// ==/UserScript==

(function () {

  UC.WheelAutoScroll_1px = {
    exec: function (win) {
      var document = win.document;
      eval('document.querySelector(\'browser\').__proto__.startScroll = function ' +
           document.querySelector('browser').__proto__.startScroll.toString().
             replace(/window\.addEventListener\("DOMMouseScroll", this, true\);/,
                     'window.addEventListener("DOMMouseScroll", this, { passive: false, capture: true });').
             replace(/^function /,
                     ''));
      eval('document.querySelector(\'browser\').__proto__.handleEvent = function ' +
           document.querySelector('browser').__proto__.handleEvent.toString().
             replace(/(case "DOMMouseScroll": {)(\s+)([\s\S]+?)\n([\s\S]+?)\n/,
                     '$1$2var x = aEvent.screenX - this._startX;$2var y = aEvent.screenY - this._startY;\n$2if ((x > this._AUTOSCROLL_SNAP || x < -this._AUTOSCROLL_SNAP) ||$2    (y > this._AUTOSCROLL_SNAP || y < -this._AUTOSCROLL_SNAP)) {$2  $3$2} else {$2  gBrowser.selectedBrowser.messageManager.sendAsyncMessage(\'autoscroll\', aEvent.detail);$2}\n$4\n').
             replace(/^function /,
                     ''));
    },

    startScroll_orig: document.querySelector('browser').__proto__.startScroll.toString().replace(/^function /, ''),
    handleEvent_orig: document.querySelector('browser').__proto__.handleEvent.toString().replace(/^function /, ''),

    frameScript: 'data:application/javascript;charset=UTF-8,' + encodeURIComponent('(' + (function () {
      content.contentListener = function (msg) {
        if (msg.data < 0) {
          content.scrollBy(0, -1);
        } else {
          content.scrollBy(0, 1);
        }
      }
      addMessageListener('autoscroll', content.contentListener);
    }).toString() + ').call(this);'),

    init: function () {
      xPref.lock('apz.autoscroll.enabled', false);
      Services.mm.loadFrameScript(UC.WheelAutoScroll_1px.frameScript, true);
    },

    destroy: function () {
      xPref.unlock('apz.autoscroll.enabled');
      Services.mm.removeDelayedFrameScript(UC.WheelAutoScroll_1px.frameScript);
      Services.mm.loadFrameScript('data:application/javascript;charset=UTF-8,' + encodeURIComponent('(' + (function () {
        removeMessageListener('autoscroll', content.contentListener);
        delete content.contentListener;
      }).toString() + ')();'), false);
      var enumerator = Services.wm.getEnumerator('navigator:browser');
      while (enumerator.hasMoreElements()) {
        var win = enumerator.getNext();
        win.eval('document.querySelector(\'browser\').__proto__.startScroll = function ' +
             UC.WheelAutoScroll_1px.startScroll_orig);
        win.eval('document.querySelector(\'browser\').__proto__.handleEvent = function ' +
             UC.WheelAutoScroll_1px.handleEvent_orig);
      }
      delete UC.WheelAutoScroll_1px;
    }
  }

  UC.WheelAutoScroll_1px.init();

})()<commit_msg>WheelAutoScroll_1px almost rewritten. Now we can use it with apz.autoscroll.enabled = true.<commit_after>// ==UserScript==
// @name            Scroll 1px on Wheel over AutoScroll
// @author          xiaoxiaoflood
// @include         main
// @startup         UC.WheelAutoScroll_1px.exec(win);
// @shutdown        UC.WheelAutoScroll_1px.destroy();
// @onlyonce
// ==/UserScript==

UC.WheelAutoScroll_1px = {
  exec: function (win) {
    let customElements = win.customElements;
    win.eval('customElements.get(\'browser\').prototype.startScroll = function ' +
             customElements.get('browser').prototype.startScroll.toString().
               replace(/window\.addEventListener\("DOMMouseScroll", this, true\);/,
                       `this.handleEventWrapper = (e) => {
                          this.handleEvent(e, arguments[0]);
                        };
                        window.addEventListener("DOMMouseScroll", this.handleEventWrapper, true);`).
               replace(/^function /,
                       ''));
    eval('customElements.get(\'browser\').prototype.stopScroll = function ' +
         customElements.get('browser').prototype.stopScroll.toString().
           replace(/window\.removeEventListener\("DOMMouseScroll", this, true\);/,
                   `window.removeEventListener("DOMMouseScroll", this.handleEventWrapper, true);`).
           replace(/^function /,
                   ''));
    eval('customElements.get(\'browser\').prototype.handleEvent = function ' +
         customElements.get('browser').prototype.handleEvent.toString().
           replace(/case "DOMMouseScroll": {\s+[\s\S]+?\n[\s\S]+?\n/,
                   `case "DOMMouseScroll": {
                    let data = arguments[1];
                    if (!this._autoScrollPopup._hidePopup) {
                      this._autoScrollPopup._hidePopup = this._autoScrollPopup.hidePopup;
                    }
                    this._autoScrollPopup.hidePopup = () => {};
                    setTimeout(() => {
                      this._autoScrollPopup.hidePopup = this._autoScrollPopup._hidePopup;
                      this.stopScroll();
                      this.startScroll(data);
                    });
                    gBrowser.selectedBrowser.messageManager.sendAsyncMessage('autoscroll', aEvent.detail);
                    aEvent.preventDefault();`).
           replace(/^function /,
                   ''));
  },

  startScroll_orig: customElements.get('browser').prototype.startScroll.toString().replace(/^function /, ''),
  stopScroll_orig: customElements.get('browser').prototype.stopScroll.toString().replace(/^function /, ''),
  handleEvent_orig: customElements.get('browser').prototype.handleEvent.toString().replace(/^function /, ''),

  frameScript: 'data:application/javascript;charset=UTF-8,' + encodeURIComponent('(' + (function () {
    this.contentListener = (msg) => {
      if (msg.data < 0) {
        content.scrollBy(0, -1);
      } else if (msg.data > 0) {
        content.scrollBy(0, 1);
      } else if (msg.data == 'destroy') {
        removeMessageListener('autoscroll', this.contentListener);
      }
    }
    addMessageListener('autoscroll', this.contentListener);
  }).toString() + ')();'),

  init: function () {
    Services.mm.loadFrameScript(this.frameScript, true);
  },

  destroy: function () {
    Services.mm.removeDelayedFrameScript(this.frameScript);
    Services.mm.broadcastAsyncMessage('autoscroll', 'destroy');
    _uc.windows((doc, win) => {
      let customElements = win.customElements;
      let eval = win.eval;
      eval('customElements.get(\'browser\').prototype.startScroll = function ' +
               this.startScroll_orig);
      eval('customElements.get(\'browser\').prototype.stopScroll = function ' +
               this.stopScroll_orig);
      eval('customElements.get(\'browser\').prototype.handleEvent = function ' +
               this.handleEvent_orig);
      win.gBrowser.browsers.forEach(browser => {
        if ('handleEventWrapper' in browser) {
          delete browser.handleEventWrapper;
        }
      });
    });
    delete UC.WheelAutoScroll_1px;
  }
}

UC.WheelAutoScroll_1px.init();<|endoftext|>


<commit_before>$(document).ready(function() {
    updateSlider(2);
    $('#submitButton').click(function() {
      var numFunc = $('input[name="numFunc"]').val();
      //console.log(numFunc);
      var funcBoundPairs = [];
      for (i = 1; i <= numFunc; i++) {
      	var funcId = "#inputFunc".concat(i.toString());
      	var boundId = "#bound".concat(i.toString());
      	var func = $(funcId);
      	var bound = $(boundId);
      	var pair = [func, bound];
      	funcBoundPairs.push(pair);
      }
      //console.log(funcBoundPairs);
      input($("#inputFuncLetter"), $("#inputVars"), numFunc, funcBoundPairs);
      return false;
    });
});

var input = function(funcLetter, inputVars, numFunc, funcBoundPairs) {
	var funcLetter = JSON.parse(inputFuncLetter);
	var vars = JSON.parse(inputVars);
	var stringPairs = [];
	for (i = 0; i < numFunc; i++) {
		var func = JSON.parse(funcBoundPairs[i][0]);
		var bound = JSON.parse(funcBoundPairs[i][1]);
		stringPairs.push([func, bound]);
	}
	var latexResult = latexifyFunc(letter, vars, numFunc, stringPairs);
	$("#result").val(latexResult);
}

var latexifyFunc = function(funcLetter, vars, numFunc, stringPairs) {
	var result = "\\[\n   ";
	result.concat(funcLetter);
	result.concat("(".concat(vars.concat(")")));
	result.concat("\n \\begin{cases}");
	for (var i = 0; i < numFunc; i++) {
		var expression = latexifyExpr(stringPairs[i][0]);
		var bounds = latexifyBounds(stringPairs[i][1], vars);
		result.concat("\n \\hfill ");
		result.concat(expression);
		result.concat("\\hfill &");
		result.concat(bounds);
		result.concat("\\\\\n");//Dunno about this
	}
	result = result.concat("\\end{cases}");
	result.concat("\n \\]")
	return result;
	//window.alert(result);
}
var latexifyBounds = function(boundString, vars){
	var inclusiveLower = boundString.charAt(0) === "[";
	var inclusiveUpper = boundString.charAt(boundString.length - 1) === "]";
	var boundArr = boundString.substring(1, boundString.length-1).split(",");
	var boundVar = vars.split(",")[0];
	var result = "".concat(boundArr[0]);
	if (inclusiveLower){
		result.concat(" \\leq ".append(boundVar));
	}
	else {
		result.concat(" < ".append(boundVar));
	}
	if (inclusiveUpper){
		result.concat(" \\leq ".append(boundArr[1]));
	}
	else {
		result.concat(" < ".append(boundArr[1]));
	}
	result.concat(boundString[1]);
	return result;
}
var latexifyExpr = function(exprString){

}

"""
replace slashes with \frac
"""
var cleanInput = function(expr){
	var lowerIndex = 0;
	var index = str.indexOf("\/");
	while (index !== -1) {
		var reversed = reverseString(expr.substring(lowerIndex, index + 1));\
		var numerator = reverseString(parseFirstNumber(reversed));

		var fractionNumerator = expr.substring(lowerIndex, index).split("/")[0];
	}

}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function reverseString(str) {
    return str.split('').reverse().join('');
}
function parseFirstNumber(str){
	var i = 0;
	var result = ""
	while (!isNan(parseInt(str[i]))){
		result.append(str[i]);
		i += 1;
	}
	return result;
}

/***
\[
 f(n) =
  \begin{cases}
      \hfill \frac{n}{2}    \hfill & \text{ if $n$ is even} \\
      \hfill -\frac{n-1}{2} \hfill & \text{ if $n$ is odd} \\
  \end{cases}
\]
     ***/

<commit_msg>more work on replacing slashes<commit_after>$(document).ready(function() {
    updateSlider(2);
    $('#submitButton').click(function() {
      var numFunc = $('input[name="numFunc"]').val();
      //console.log(numFunc);
      var funcBoundPairs = [];
      for (i = 1; i <= numFunc; i++) {
      	var funcId = "#inputFunc".concat(i.toString());
      	var boundId = "#bound".concat(i.toString());
      	var func = $(funcId);
      	var bound = $(boundId);
      	var pair = [func, bound];
      	funcBoundPairs.push(pair);
      }
      //console.log(funcBoundPairs);
      input($("#inputFuncLetter"), $("#inputVars"), numFunc, funcBoundPairs);
      return false;
    });
});

var input = function(funcLetter, inputVars, numFunc, funcBoundPairs) {
	var funcLetter = JSON.parse(inputFuncLetter);
	var vars = JSON.parse(inputVars);
	var stringPairs = [];
	for (i = 0; i < numFunc; i++) {
		var func = JSON.parse(funcBoundPairs[i][0]);
		var bound = JSON.parse(funcBoundPairs[i][1]);
		stringPairs.push([func, bound]);
	}
	var latexResult = latexifyFunc(letter, vars, numFunc, stringPairs);
	$("#result").val(latexResult);
}

var latexifyFunc = function(funcLetter, vars, numFunc, stringPairs) {
	var result = "\\[\n   ";
	result.concat(funcLetter);
	result.concat("(".concat(vars.concat(")")));
	result.concat("\n \\begin{cases}");
	for (var i = 0; i < numFunc; i++) {
		var expression = latexifyExpr(stringPairs[i][0]);
		var bounds = latexifyBounds(stringPairs[i][1], vars);
		result.concat("\n \\hfill ");
		result.concat(expression);
		result.concat("\\hfill &");
		result.concat(bounds);
		result.concat("\\\\\n");//Dunno about this
	}
	result = result.concat("\\end{cases}");
	result.concat("\n \\]")
	return result;
	//window.alert(result);
}
var latexifyBounds = function(boundString, vars){
	var inclusiveLower = boundString.charAt(0) === "[";
	var inclusiveUpper = boundString.charAt(boundString.length - 1) === "]";
	var boundArr = boundString.substring(1, boundString.length-1).split(",");
	var boundVar = vars.split(",")[0];
	var result = "".concat(boundArr[0]);
	if (inclusiveLower){
		result.concat(" \\leq ".append(boundVar));
	}
	else {
		result.concat(" < ".append(boundVar));
	}
	if (inclusiveUpper){
		result.concat(" \\leq ".append(boundArr[1]));
	}
	else {
		result.concat(" < ".append(boundArr[1]));
	}
	result.concat(boundString[1]);
	return result;
}
var latexifyExpr = function(exprString){

}

"""
replace slashes with \frac
"""
var replaceSlashes = function(expr){
	var lowerIndex = 0;
	var index = str.indexOf("\/");
	while (index !== -1) {
		var reversed = reverseString(expr.substring(lowerIndex, index));\
		var numerator = reverseString(parseFirstNumber(reversed));
		var denominator = parseFirstNumber(expr.substring(index + 1, expr.length);
		expr.replace(numerator, "\\frac{".append(numerator).concat("}{"));
		expr.replace(denominator, denominator.concat("}"));
	}

}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function reverseString(str) {
    return str.split('').reverse().join('');
}
function parseFirstNumber(str){
	str = str.trim();
	var result = "";
	var i = 0;
	while (!isNan(parseInt(str[i]))){
		result.append(str[i]);
		i += 1;
	}
	return result;
}

/***
\[
 f(n) =
  \begin{cases}
      \hfill \frac{n}{2}    \hfill & \text{ if $n$ is even} \\
      \hfill -\frac{n-1}{2} \hfill & \text{ if $n$ is odd} \\
  \end{cases}
\]
     ***/

<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { get, filter } from 'lodash';
import _ from 'lodash';
import { RequiredText } from '../RequiredText/RequiredText';

import Icons from '../icons';
import { colors, typography, darkScrollbar } from '../styles';
import SelectOptions from '../SelectInput/SelectOptions';
import {
  checkDocumentEvent,
  openOptionsList,
  closeOptionsList,
  toggleOptionsList
} from '../SelectInput';

export const TextInputWrapper = styled.div`
  width: 100%;
  position: relative;
`;

const Caret = styled.div`
  position: absolute;
  right: 0;
  top: 62.5%;
  transform: translateY(-50%);
  width: 32px;
  cursor: pointer;
  height: 32px;

  &::after {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    border-left: 5px transparent solid;
    border-right: 5px transparent solid;
    border-${props => props.open ? 'bottom' : 'top'}: 5px ${colors.black40} solid;
  }
`;

export const TextBox = styled.div`
  border: ${(props) => {
    return props.outlinedSearch ? "1px solid rgba(0,0,0,0.4)" : 'none'
  }};
  border-radius: 3px;
  background-color: ${colors.white};
  border-bottom: thin solid ${colors.black40};
  border-color: ${(props) => {
    if (props.error) {
      return colors.red;
    } else if (props.isFocused) {
        return colors.green;
    } else if (props.disabled) {
      return colors.black20;
    } else if (props.lineColor) {
      return props.lineColor;
    }
    return colors.black40;
  }};
  border-width: ${(props) => {
    if (props.isFocused || props.error) {
      return '2px';
    }
    return '1px';
  }};
  box-sizing: border-box;
  cursor: ${(props) => {
        if (props.disabled) {
          return 'default';
        }
        return 'text';
      }};
  padding-top: 24px;
  padding-bottom: ${(props) => {
    if (props.error || props.isFocused) {
      return '7px';
    }

    return '8px';
  }};
  position: relative;
  transition: border-color 0.14s ease-in-out;
  width: 100%;

  &:hover {
    border-width: ${(props) => {
      if (props.disabled) {
        return '1px';
      }
      return '2px';
    }};
    padding-bottom: ${(props) => {
      if (props.disabled) {
        return '8px';
      }
      return '7px';
    }};
  }

  ${(props) => {
    if (props.disabled) {
      return `
        background-color: ${colors.black05};
        label {
          color: ${colors.black40};
        }
      `;
    }
  }}
`;

export const InputItem = styled.input`
  background-color: transparent;
  border: none;
  box-sizing: border-box;
  height: 100%;
  max-height: 19px;
  padding: ${props => props.search ? '0 0 0 32px' : '0 1px'};
  resize: none;
  text-align: left;
  width: 100%;

  &:focus {
    outline: 0;
  }
  ${typography.subhead1}
  ${darkScrollbar}
  &::placeholder {
    color: ${colors.black30};
  }
`;

export const TextLabel = styled.label`
  color: ${(props) => {
      if (props.error) {
        return colors.red;
      } else if (props.isFocused) {
        return props.theme.focusedColor || colors.green;
      } else if (props.labelColor) {
        return props.labelColor;
      } else {
        return colors.black60;
      }
    }};
  top: 0;
  left: 1px;
  position: absolute;
  transform: ${(props) => {
    if (props.open || props.isFocused) {
      return 'translateY(4px)';
    } else {
      return 'translateY(24px)';
    }
  }};
  transition: font-size 0.14s ease-in-out, transform 0.14s ease-in-out, color 0.14s ease-in-out;
  ${(props) => {
    if (props.open || props.isFocused) {
      return typography.caption
    } else {
      return typography.subhead1
    }
  }}
  line-height: 16px;
`;

export const TextInputHelper = styled.div`
   color: ${(props) => {
     return props.theme.helperColor || colors.black40;
  }};
  padding-top: 4px;
  ${typography.caption}
`;

export const TextInputError = styled(TextInputHelper)`
  color: ${colors.red};
`;

const SearchIcon = styled(Icons.SearchMaterialIcon)`
  position: absolute;
  top: 22px;
  left: 0;
`;

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

    this.state = {
      focused: false,
      optionsListVisible: false,
      value: this.props.value || ''
    };
  }

  checkDocumentEvent = (e) => { checkDocumentEvent.call(this, e) }

  openOptionsList = () => { openOptionsList.call(this) }

  closeOptionsList = () => { closeOptionsList.call(this) }

  toggleOptionsList = () => { toggleOptionsList.call(this) }

  componentDidMount() {
    const {value} = this.props;

    if (value) {
      this.setState({
        value
      });
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.visible !== nextProps.visible) {
      this.setState({
        value: ''
      });
    }
  }

  handleCursorPositionChange = () =>  {
    if(this.props.onSelectionStartChange) {
      this.props.onSelectionStartChange(this.textInputEl.selectionStart);
    }
  }

  focused = () => {
    document.addEventListener('keyup', this.handleCursorPositionChange)
    this.setState({
      focused: true
    }, this.handleFocusChange())
  }

  blurred = () => {
    document.removeEventListener('keyup', this.handleCursorPositionChange)
    if(!this.state.cancelBlur) {
      this.setState({
        focused: false
      });
    }
  }

  componentWillUnmount() {
    document.removeEventListener('keyup', this.handleCursorPositionChange)
  }

  renderHelperText = () => {
    const { error, helper, collapsed } = this.props;

    if((!error || _.isBoolean(error)) && !helper) {
      return null;
    }

    if (collapsed && !this.getValue() && !this.state.focused && !error) {
      return null;
    }

    if (error) {
      return (<TextInputError>{error}</TextInputError>);
    }

    return (<TextInputHelper>{helper}</TextInputHelper>);
  }

  renderRequiredText = () => {
    const { required, collapsed } = this.props;
    const message = "Required";

    if (!this.state.focused && !this.getValue() && !collapsed && required) {
      return (<RequiredText>{message}{required}</RequiredText>);
    }
  }

  focusOnTextInput = () => {
    if (this.textInput !== document.activeElement) {
      this.textInputEl.focus();
    }
  }

  cancelBlur = (e) => {
    this.setState({
      cancelBlur: true
    });
  }

  removeCancelBlur = () => {
    this.setState({
      cancelBlur: false
    });
  }

  handleValueChange = (value) => {
    if (this.props.onChange) {
      this.props.onChange(value);
    }
  }

  handleFocusChange = () => {
    if (this.props.onFocus) {
      this.props.onFocus(this.getValue());
    }
  }

  scrollToTop() {
    if(get(ReactDOM.findDOMNode(this.optionsRef), 'scrollTop', false)) {
      ReactDOM.findDOMNode(this.optionsRef).scrollTop = 0;
    }
  }

  onChange = (e) => {
    if (e) {
      e.preventDefault();
    }

    if(!this.state.optionsListVisible) {
      this.toggleOptionsList();
    }

    const value =  get(e, 'target.value', this.textInputEl.value)

    this.setState({
      value,
    }, () => {
      this.handleValueChange(value)
    });

    this.scrollToTop();
  }

  onDropDownSelect = (value) => {
    this.setState({
      value
    }, () => {
      this.handleValueChange(value)
    });
    this.closeOptionsList();
  }

  findBestOptionIndex(opt = '', value) {
    const valIndex = opt.value.toLowerCase().indexOf(value);
    const labelIndex = opt.label.toLowerCase().indexOf(value);

    if(valIndex === -1 && labelIndex !== -1) {
      return labelIndex;
    }

    if(labelIndex === -1 && valIndex !== -1) {
      return valIndex;
    }

    return labelIndex > valIndex ? valIndex : labelIndex
  }

  getValue = () => this.props.stateless ? this.props.value : this.state.value;

  getPromotedOptions = () => {
    const lowerValue = this.getValue().toLowerCase();
    return this.getValue()
      ? filter(this.props.options, o =>
          o.value.toLowerCase().indexOf(lowerValue) > -1 ||
          o.label.toLowerCase().indexOf(lowerValue) > -1)
        .sort((a, b) => this.findBestOptionIndex(a, lowerValue) - this.findBestOptionIndex(b, lowerValue))
      : [];
  }

  getInputType = (inputType) => ['text', 'password', 'number'].indexOf(inputType) > -1 ? inputType : 'text'

  usePlaceholder = () => {
    if (_.isEmpty(this.props.label) || this.props.label === DEFAULT_LABEL) {
      return this.props.placeholder;
    };
    return '';
  }

  render() {
    const {
      label,
      name,
      inputType,
      error,
      disabled,
      collapsed,
      className,
      options,
      promotedOptions,
      lowPadding,
      labelColor,
      lineColor,
    } = this.props;

    return (
      <TextInputWrapper
        className={className}
        ref={(el) => { this.clickEventElement = el }}>
        <TextBox
          onMouseUp={this.removeCancelBlur}
          onMouseDown={this.cancelBlur}
          onMouseLeave={this.removeCancelBlur}
          onClick={this.focusOnTextInput}
          isFocused={this.state.focused}
          error={error}
          open={this.getValue()}
          disabled={disabled}
          lineColor={lineColor}
          collapsed={collapsed}>
          <InputItem
            type={this.getInputType(inputType)}
            onFocus={this.focused}
            onBlur={this.blurred}
            onClick={this.handleCursorPositionChange}
            id={name}
            name={name}
            disabled={disabled}
            error={error}
            value={this.getValue()}
            ref={(input) => { this.textInputEl = ReactDOM.findDOMNode(input); }}
            onChange={this.onChange}
            search={this.props.search}
            placeholder={this.usePlaceholder()} />
          {this.props.search &&
            <SearchIcon fill={colors.dustyGray} size={{ width: 22, height: 22 }} />
          }
          { !this.props.search &&
            <TextLabel isFocused={this.state.focused} labelColor={labelColor} open={this.getValue()} htmlFor={name} error={error}>{label}</TextLabel>
          }
        </TextBox>
        { options && <Caret onClick={this.toggleOptionsList} open={this.state.optionsListVisible} className={'pb-caret'} />}
        {this.renderHelperText()}
        {this.renderRequiredText()}
        { options && <SelectOptions
          onOptionUpdate={this.onDropDownSelect}
          promotedOptions={promotedOptions || this.getPromotedOptions() }
          options={options}
          optionsCount={options.length}
          visible={this.state.optionsListVisible}
          lowPadding={lowPadding}
          width={this.props.selectOptionsWidth}
          optionsRef={(ref) => {
            this.optionsRef = ref;
          }}
        />}
      </TextInputWrapper>
    );
  }
}

const DEFAULT_LABEL = 'Label';

TextInput.defaultProps = {
  name: 'Name',
  label: DEFAULT_LABEL,
  onSelectionStartChange: _.noop,
  stateless: false,
};

TextInput.propTypes = {
  name: PropTypes.string.isRequired,
  label: PropTypes.string.isRequired,
  inputType: PropTypes.string,
  helper: PropTypes.string,
  required: PropTypes.bool,
  error: PropTypes.any,
  disabled: PropTypes.bool,
  value: PropTypes.string,
  onChange: PropTypes.func,
  collapsed: PropTypes.bool,
  lowPadding: PropTypes.bool,
  stateless: PropTypes.bool,
  selectOptionsWidth: PropTypes.number,
  onSelectionStartChange: PropTypes.func,
  options: PropTypes.arrayOf(PropTypes.shape({
    value: PropTypes.any,
    label: PropTypes.string,
    disabled: PropTypes.bool
  })),
  promotedOptions: PropTypes.arrayOf(PropTypes.shape({
    value: PropTypes.any,
    label: PropTypes.string,
    disabled: PropTypes.bool
  }))
};

export default TextInput;
<commit_msg>fix(TextInput): allowing textlabel to hold 0 value (#200)<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import styled from 'styled-components';
import PropTypes from 'prop-types';
import { get, filter } from 'lodash';
import _ from 'lodash';
import { RequiredText } from '../RequiredText/RequiredText';

import Icons from '../icons';
import { colors, typography, darkScrollbar } from '../styles';
import SelectOptions from '../SelectInput/SelectOptions';
import {
  checkDocumentEvent,
  openOptionsList,
  closeOptionsList,
  toggleOptionsList
} from '../SelectInput';

export const TextInputWrapper = styled.div`
  width: 100%;
  position: relative;
`;

const Caret = styled.div`
  position: absolute;
  right: 0;
  top: 62.5%;
  transform: translateY(-50%);
  width: 32px;
  cursor: pointer;
  height: 32px;

  &::after {
    content: '';
    position: absolute;
    width: 0;
    height: 0;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    margin: auto;
    border-left: 5px transparent solid;
    border-right: 5px transparent solid;
    border-${props => props.open ? 'bottom' : 'top'}: 5px ${colors.black40} solid;
  }
`;

export const TextBox = styled.div`
  border: ${(props) => {
    return props.outlinedSearch ? "1px solid rgba(0,0,0,0.4)" : 'none'
  }};
  border-radius: 3px;
  background-color: ${colors.white};
  border-bottom: thin solid ${colors.black40};
  border-color: ${(props) => {
    if (props.error) {
      return colors.red;
    } else if (props.isFocused) {
        return colors.green;
    } else if (props.disabled) {
      return colors.black20;
    } else if (props.lineColor) {
      return props.lineColor;
    }
    return colors.black40;
  }};
  border-width: ${(props) => {
    if (props.isFocused || props.error) {
      return '2px';
    }
    return '1px';
  }};
  box-sizing: border-box;
  cursor: ${(props) => {
        if (props.disabled) {
          return 'default';
        }
        return 'text';
      }};
  padding-top: 24px;
  padding-bottom: ${(props) => {
    if (props.error || props.isFocused) {
      return '7px';
    }

    return '8px';
  }};
  position: relative;
  transition: border-color 0.14s ease-in-out;
  width: 100%;

  &:hover {
    border-width: ${(props) => {
      if (props.disabled) {
        return '1px';
      }
      return '2px';
    }};
    padding-bottom: ${(props) => {
      if (props.disabled) {
        return '8px';
      }
      return '7px';
    }};
  }

  ${(props) => {
    if (props.disabled) {
      return `
        background-color: ${colors.black05};
        label {
          color: ${colors.black40};
        }
      `;
    }
  }}
`;

export const InputItem = styled.input`
  background-color: transparent;
  border: none;
  box-sizing: border-box;
  height: 100%;
  max-height: 19px;
  padding: ${props => props.search ? '0 0 0 32px' : '0 1px'};
  resize: none;
  text-align: left;
  width: 100%;

  &:focus {
    outline: 0;
  }
  ${typography.subhead1}
  ${darkScrollbar}
  &::placeholder {
    color: ${colors.black30};
  }
`;

export const TextLabel = styled.label`
  color: ${(props) => {
      if (props.error) {
        return colors.red;
      } else if (props.isFocused) {
        return props.theme.focusedColor || colors.green;
      } else if (props.labelColor) {
        return props.labelColor;
      } else {
        return colors.black60;
      }
    }};
  top: 0;
  left: 1px;
  position: absolute;
  transform: ${(props) => {
    if (props.open || props.isFocused) {
      return 'translateY(4px)';
    } else {
      return 'translateY(24px)';
    }
  }};
  transition: font-size 0.14s ease-in-out, transform 0.14s ease-in-out, color 0.14s ease-in-out;
  ${(props) => {
    if (props.open || props.isFocused) {
      return typography.caption
    } else {
      return typography.subhead1
    }
  }}
  line-height: 16px;
`;

export const TextInputHelper = styled.div`
   color: ${(props) => {
     return props.theme.helperColor || colors.black40;
  }};
  padding-top: 4px;
  ${typography.caption}
`;

export const TextInputError = styled(TextInputHelper)`
  color: ${colors.red};
`;

const SearchIcon = styled(Icons.SearchMaterialIcon)`
  position: absolute;
  top: 22px;
  left: 0;
`;

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

    this.state = {
      focused: false,
      optionsListVisible: false,
      value: this.props.value || ''
    };
  }

  checkDocumentEvent = (e) => { checkDocumentEvent.call(this, e) }

  openOptionsList = () => { openOptionsList.call(this) }

  closeOptionsList = () => { closeOptionsList.call(this) }

  toggleOptionsList = () => { toggleOptionsList.call(this) }

  componentDidMount() {
    const {value} = this.props;

    if (value !== undefined && value !== '') {
      this.setState({
        value
      });
    }
  }

  componentWillReceiveProps(nextProps) {
    if (this.props.visible !== nextProps.visible) {
      this.setState({
        value: ''
      });
    }
  }

  handleCursorPositionChange = () =>  {
    if(this.props.onSelectionStartChange) {
      this.props.onSelectionStartChange(this.textInputEl.selectionStart);
    }
  }

  focused = () => {
    document.addEventListener('keyup', this.handleCursorPositionChange)
    this.setState({
      focused: true
    }, this.handleFocusChange())
  }

  blurred = () => {
    document.removeEventListener('keyup', this.handleCursorPositionChange)
    if(!this.state.cancelBlur) {
      this.setState({
        focused: false
      });
    }
  }

  componentWillUnmount() {
    document.removeEventListener('keyup', this.handleCursorPositionChange)
  }

  renderHelperText = () => {
    const { error, helper, collapsed } = this.props;

    if((!error || _.isBoolean(error)) && !helper) {
      return null;
    }

    if (collapsed && !this.getValue() && !this.state.focused && !error) {
      return null;
    }

    if (error) {
      return (<TextInputError>{error}</TextInputError>);
    }

    return (<TextInputHelper>{helper}</TextInputHelper>);
  }

  renderRequiredText = () => {
    const { required, collapsed } = this.props;
    const message = "Required";

    if (!this.state.focused && !this.getValue() && !collapsed && required) {
      return (<RequiredText>{message}{required}</RequiredText>);
    }
  }

  focusOnTextInput = () => {
    if (this.textInput !== document.activeElement) {
      this.textInputEl.focus();
    }
  }

  cancelBlur = (e) => {
    this.setState({
      cancelBlur: true
    });
  }

  removeCancelBlur = () => {
    this.setState({
      cancelBlur: false
    });
  }

  handleValueChange = (value) => {
    if (this.props.onChange) {
      this.props.onChange(value);
    }
  }

  handleFocusChange = () => {
    if (this.props.onFocus) {
      this.props.onFocus(this.getValue());
    }
  }

  scrollToTop() {
    if(get(ReactDOM.findDOMNode(this.optionsRef), 'scrollTop', false)) {
      ReactDOM.findDOMNode(this.optionsRef).scrollTop = 0;
    }
  }

  onChange = (e) => {
    if (e) {
      e.preventDefault();
    }

    if(!this.state.optionsListVisible) {
      this.toggleOptionsList();
    }

    const value =  get(e, 'target.value', this.textInputEl.value)

    this.setState({
      value,
    }, () => {
      this.handleValueChange(value)
    });

    this.scrollToTop();
  }

  onDropDownSelect = (value) => {
    this.setState({
      value
    }, () => {
      this.handleValueChange(value)
    });
    this.closeOptionsList();
  }

  findBestOptionIndex(opt = '', value) {
    const valIndex = opt.value.toLowerCase().indexOf(value);
    const labelIndex = opt.label.toLowerCase().indexOf(value);

    if(valIndex === -1 && labelIndex !== -1) {
      return labelIndex;
    }

    if(labelIndex === -1 && valIndex !== -1) {
      return valIndex;
    }

    return labelIndex > valIndex ? valIndex : labelIndex
  }

  getValue = () => this.props.stateless ? this.props.value : this.state.value;

  getPromotedOptions = () => {
    const lowerValue = this.getValue().toLowerCase();
    return this.getValue()
      ? filter(this.props.options, o =>
          o.value.toLowerCase().indexOf(lowerValue) > -1 ||
          o.label.toLowerCase().indexOf(lowerValue) > -1)
        .sort((a, b) => this.findBestOptionIndex(a, lowerValue) - this.findBestOptionIndex(b, lowerValue))
      : [];
  }

  getInputType = (inputType) => ['text', 'password', 'number'].indexOf(inputType) > -1 ? inputType : 'text'

  usePlaceholder = () => {
    if (_.isEmpty(this.props.label) || this.props.label === DEFAULT_LABEL) {
      return this.props.placeholder;
    };
    return '';
  }

  render() {
    const {
      label,
      name,
      inputType,
      error,
      disabled,
      collapsed,
      className,
      options,
      promotedOptions,
      lowPadding,
      labelColor,
      lineColor,
    } = this.props;

    return (
      <TextInputWrapper
        className={className}
        ref={(el) => { this.clickEventElement = el }}>
        <TextBox
          onMouseUp={this.removeCancelBlur}
          onMouseDown={this.cancelBlur}
          onMouseLeave={this.removeCancelBlur}
          onClick={this.focusOnTextInput}
          isFocused={this.state.focused}
          error={error}
          disabled={disabled}
          lineColor={lineColor}
          collapsed={collapsed}>
          <InputItem
            type={this.getInputType(inputType)}
            onFocus={this.focused}
            onBlur={this.blurred}
            onClick={this.handleCursorPositionChange}
            id={name}
            name={name}
            disabled={disabled}
            error={error}
            value={this.getValue()}
            ref={(input) => { this.textInputEl = ReactDOM.findDOMNode(input); }}
            onChange={this.onChange}
            search={this.props.search}
            placeholder={this.usePlaceholder()} />
          {this.props.search &&
            <SearchIcon fill={colors.dustyGray} size={{ width: 22, height: 22 }} />
          }
          { !this.props.search &&
            <TextLabel isFocused={this.state.focused} labelColor={labelColor} open={this.getValue() !== '' && this.getValue() !== undefined} htmlFor={name} error={error}>{label}</TextLabel>
          }
        </TextBox>
        { options && <Caret onClick={this.toggleOptionsList} open={this.state.optionsListVisible} className={'pb-caret'} />}
        {this.renderHelperText()}
        {this.renderRequiredText()}
        { options && <SelectOptions
          onOptionUpdate={this.onDropDownSelect}
          promotedOptions={promotedOptions || this.getPromotedOptions() }
          options={options}
          optionsCount={options.length}
          visible={this.state.optionsListVisible}
          lowPadding={lowPadding}
          width={this.props.selectOptionsWidth}
          optionsRef={(ref) => {
            this.optionsRef = ref;
          }}
        />}
      </TextInputWrapper>
    );
  }
}

const DEFAULT_LABEL = 'Label';

TextInput.defaultProps = {
  name: 'Name',
  label: DEFAULT_LABEL,
  onSelectionStartChange: _.noop,
  stateless: false,
};

TextInput.propTypes = {
  name: PropTypes.string.isRequired,
  label: PropTypes.string.isRequired,
  inputType: PropTypes.string,
  helper: PropTypes.string,
  required: PropTypes.bool,
  error: PropTypes.any,
  disabled: PropTypes.bool,
  value: PropTypes.string,
  onChange: PropTypes.func,
  collapsed: PropTypes.bool,
  lowPadding: PropTypes.bool,
  stateless: PropTypes.bool,
  selectOptionsWidth: PropTypes.number,
  onSelectionStartChange: PropTypes.func,
  options: PropTypes.arrayOf(PropTypes.shape({
    value: PropTypes.any,
    label: PropTypes.string,
    disabled: PropTypes.bool
  })),
  promotedOptions: PropTypes.arrayOf(PropTypes.shape({
    value: PropTypes.any,
    label: PropTypes.string,
    disabled: PropTypes.bool
  }))
};

export default TextInput;
<|endoftext|>


<commit_before>var endsWith = require("ends-with")
var StackTraceGPS = require("./stacktrace-gps")
var ErrorStackParser = require("./error-stack-parser")

var gps = null;

function resFrame(frame, callback){
    gps._get(frame.fileName).then(function(src){
        var lines = src.split("\n")
        frame.prevLine = lines[frame.lineNumber - 1 - 1]// adjust for lines being one-indexed
        frame.nextLine = lines[frame.lineNumber + 1 - 1]
        frame.line = lines[frame.lineNumber - 1];

        callback(null, JSON.parse(JSON.stringify(frame)))
    })

}

function initGPSIfNecessary(){
    if (gps !== null) return;

    var sourceCache = {};
    var fnEls = document.getElementsByClassName("string-trace-fn")
    fnEls = Array.prototype.slice.call(fnEls)
    fnEls.forEach(function(el){
        var key = el.getAttribute("fn") + ".js"
        sourceCache[key] = el.innerHTML
        sourceCache[key + "?dontprocess=yes"] = decodeURIComponent(el.getAttribute("original-source"))
        sourceCache[el.getAttribute("sm-filename")] = decodeURIComponent(el.getAttribute("sm"))
    })

    gps = new StackTraceGPS({sourceCache: sourceCache});
}

export default function(frame, callback){
    initGPSIfNecessary()

    var frameObject = ErrorStackParser.parse({stack: frame})[0];

    if (endsWith(frameObject.fileName, ".html")){
        // don't bother looking for source map file
        callback(null, frame)
    } else {
        gps.pinpoint(frameObject).then(function(newFrame){
            resFrame(newFrame, callback)
        }, function(){
            resFrame(frameObject, callback)
            console.log("error", arguments)
        });
    }
}
<commit_msg>Avoid React setState on unmounted component message.<commit_after>var endsWith = require("ends-with")
var StackTraceGPS = require("./stacktrace-gps")
var ErrorStackParser = require("./error-stack-parser")

var gps = null;

function resFrame(frame, callback){
    gps._get(frame.fileName).then(function(src){
        var lines = src.split("\n")
        frame.prevLine = lines[frame.lineNumber - 1 - 1]// adjust for lines being one-indexed
        frame.nextLine = lines[frame.lineNumber + 1 - 1]
        frame.line = lines[frame.lineNumber - 1];

        callback(null, JSON.parse(JSON.stringify(frame)))
    })

}

function initGPSIfNecessary(){
    if (gps !== null) return;

    var sourceCache = {};
    var fnEls = document.getElementsByClassName("string-trace-fn")
    fnEls = Array.prototype.slice.call(fnEls)
    fnEls.forEach(function(el){
        var key = el.getAttribute("fn") + ".js"
        sourceCache[key] = el.innerHTML
        sourceCache[key + "?dontprocess=yes"] = decodeURIComponent(el.getAttribute("original-source"))
        sourceCache[el.getAttribute("sm-filename")] = decodeURIComponent(el.getAttribute("sm"))
    })

    gps = new StackTraceGPS({sourceCache: sourceCache});
}

export default function(frame, callback){
    initGPSIfNecessary()

    var frameObject = ErrorStackParser.parse({stack: frame})[0];

    // Force asynchronous callback call, to avoid calling setState on
    // uninitialized compnent in React when using resolveFrame in constructor
    setTimeout(function(){
        if (endsWith(frameObject.fileName, ".html")){
            // don't bother looking for source map file
            callback(null, frame)
        } else {
            gps.pinpoint(frameObject).then(function(newFrame){
                resFrame(newFrame, callback)
            }, function(){
                resFrame(frameObject, callback)
                console.log("error", arguments)
            });
        }
    })
}
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import { connect } from 'react-redux'

import ContainerFluid from '../ContainerFluid'
import VmUserMessages from '../VmUserMessages'
import UserMenu from './UserMenu'

import { getAllVms } from '../../actions/vm'

/**
 * Main application header on top of the page
 */
const VmsPageHeader = ({ title, onRefresh }) => {
  const titleStyle = { padding: '0px 0 5px' }

  return (

      <ContainerFluid>

          {title}

               Refresh

          <UserMenu />
          <VmUserMessages />

      </ContainerFluid>

  )
}
VmsPageHeader.propTypes = {
  title: PropTypes.string.isRequired,
  onRefresh: PropTypes.func.isRequired,
}

export default connect(
  (state) => ({ }),
  (dispatch) => ({
    onRefresh: () => dispatch(getAllVms({ shallowFetch: false })),
  })
)(VmsPageHeader)
<commit_msg>Fix refresh button highlighted after click<commit_after>import React, { PropTypes } from 'react'
import { connect } from 'react-redux'

import ContainerFluid from '../ContainerFluid'
import VmUserMessages from '../VmUserMessages'
import UserMenu from './UserMenu'

import { getAllVms } from '../../actions/vm'

/**
 * Main application header on top of the page
 */
const VmsPageHeader = ({ title, onRefresh }) => {
  const titleStyle = { padding: '0px 0 5px' }

  return (

      <ContainerFluid>

          {title}

               Refresh

          <UserMenu />
          <VmUserMessages />

      </ContainerFluid>

  )
}
VmsPageHeader.propTypes = {
  title: PropTypes.string.isRequired,
  onRefresh: PropTypes.func.isRequired,
}

export default connect(
  (state) => ({ }),
  (dispatch) => ({
    onRefresh: () => dispatch(getAllVms({ shallowFetch: false })),
  })
)(VmsPageHeader)
<|endoftext|>


<commit_before>import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
import BaseTheme from '../../style/themes/base';
import buttonTypes from './button-types.style';
import buttonSizes from './button-sizes.style';
import buttonClasicStyle from './button-classic.style';
import OptionsHelper from '../../utils/helpers/options-helper';
import { StyledIcon } from '../icon/icon.style';
import { isClassic } from '../../utils/helpers/style-helper';

const StyledButton = styled.button`
  align-items: center;
  cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
  display: inline-flex;
  flex-direction: column;
  flex-flow: wrap;
  justify-content: center;
  vertical-align: middle;
  ${addButtonStyle}

  ${({ iconPosition }) => css`
    ${StyledIcon} {
      margin-left: ${iconPosition === 'before' ? '0px' : '8px'};
      margin-right: ${iconPosition === 'before' ? '8px' : '0px'};
      height: ${applyIconHeight}
    }
  `}
`;

export const StyledButtonSubtext = styled.span`
  font-size: 14px;
  font-weight: 400;
  display: block;
`;

function applyIconHeight({ theme, size, iconType }) {
  if (isClassic(theme)) {
    if (iconType === 'services') return '22px;';
    return `${size === 'large' ? '20px' : '18px'};`;
  }
  if (iconType === 'services') return `${size === 'large' ? '28px' : '24px'}`;

  return `${size === 'large' ? '22px' : '18px'};`;
}

function addButtonStyle(props) {
  if (isClassicButton(props)) return buttonClasicStyle(props);

  return stylingForType(props);
}

function stylingForType({
  disabled,
  buttonType,
  theme,
  size
}) {
  return css`
    border: 2px solid transparent;
    box-sizing: border-box;
    font-weight: 600;
    padding-top: 1px;
    padding-bottom: 1px;
    text-decoration: none;
    &:focus {
      outline: solid 3px ${theme.colors.focus};
    }
    & + & {
      margin-left: 16px;
    }

    ${buttonTypes(theme, disabled)[buttonType]};
    ${buttonSizes(theme)[size]}
  `;
}

function isClassicButton({ theme, buttonType }) {
  const isClassicButtonType = OptionsHelper.themesBinary.includes(buttonType);

  return isClassic(theme) && isClassicButtonType;
}

StyledButton.defaultProps = {
  theme: BaseTheme,
  medium: true,
  buttonType: 'secondary',
  legacyColorVariant: 'blue'
};

StyledButton.propTypes = {
  /** Button types for new business themes */
  buttonType: PropTypes.oneOf(OptionsHelper.buttonTypes),
  /** The text the button displays */
  children: PropTypes.node.isRequired,
  /** Apply disabled state to the button */
  disabled: PropTypes.bool,
  /** Used to transfrom button into anchor */
  href: PropTypes.string,
  /** Defines an Icon position within the button */
  iconPosition: PropTypes.oneOf([...OptionsHelper.buttonIconPositions, '']),
  /** Defines an Icon type within the button (see Icon for options) */
  iconType: PropTypes.oneOf([...OptionsHelper.icons, '']),
  /** Assigns a size to the button */
  size: PropTypes.oneOf(OptionsHelper.sizesRestricted),
  /** Second text child, renders under main text, only when size is "large" */
  subtext: PropTypes.string,
  /** Set this prop to pass in legacy theme color variants */
  legacyColorVariant: PropTypes.oneOf(OptionsHelper.buttonColors),
  /** Used to transfrom button into anchor */
  to: PropTypes.string
};

export default StyledButton;
<commit_msg>fixes missing semi-colon in button icon<commit_after>import styled, { css } from 'styled-components';
import PropTypes from 'prop-types';
import BaseTheme from '../../style/themes/base';
import buttonTypes from './button-types.style';
import buttonSizes from './button-sizes.style';
import buttonClasicStyle from './button-classic.style';
import OptionsHelper from '../../utils/helpers/options-helper';
import { StyledIcon } from '../icon/icon.style';
import { isClassic } from '../../utils/helpers/style-helper';

const StyledButton = styled.button`
  align-items: center;
  cursor: ${({ disabled }) => (disabled ? 'not-allowed' : 'pointer')};
  display: inline-flex;
  flex-direction: column;
  flex-flow: wrap;
  justify-content: center;
  vertical-align: middle;
  ${addButtonStyle}

  ${({ iconPosition }) => css`
    ${StyledIcon} {
      margin-left: ${iconPosition === 'before' ? '0px' : '8px'};
      margin-right: ${iconPosition === 'before' ? '8px' : '0px'};
      height: ${applyIconHeight};
    }
  `}
`;

export const StyledButtonSubtext = styled.span`
  font-size: 14px;
  font-weight: 400;
  display: block;
`;

function applyIconHeight({ theme, size, iconType }) {
  if (isClassic(theme)) {
    if (iconType === 'services') return '22px';
    return `${size === 'large' ? '20px' : '18px'}`;
  }
  if (iconType === 'services') return `${size === 'large' ? '28px' : '24px'}`;

  return `${size === 'large' ? '22px' : '18px'}`;
}

function addButtonStyle(props) {
  if (isClassicButton(props)) return buttonClasicStyle(props);

  return stylingForType(props);
}

function stylingForType({
  disabled,
  buttonType,
  theme,
  size
}) {
  return css`
    border: 2px solid transparent;
    box-sizing: border-box;
    font-weight: 600;
    padding-top: 1px;
    padding-bottom: 1px;
    text-decoration: none;
    &:focus {
      outline: solid 3px ${theme.colors.focus};
    }
    & + & {
      margin-left: 16px;
    }

    ${buttonTypes(theme, disabled)[buttonType]};
    ${buttonSizes(theme)[size]}
  `;
}

function isClassicButton({ theme, buttonType }) {
  const isClassicButtonType = OptionsHelper.themesBinary.includes(buttonType);

  return isClassic(theme) && isClassicButtonType;
}

StyledButton.defaultProps = {
  theme: BaseTheme,
  medium: true,
  buttonType: 'secondary',
  legacyColorVariant: 'blue'
};

StyledButton.propTypes = {
  /** Button types for new business themes */
  buttonType: PropTypes.oneOf(OptionsHelper.buttonTypes),
  /** The text the button displays */
  children: PropTypes.node.isRequired,
  /** Apply disabled state to the button */
  disabled: PropTypes.bool,
  /** Used to transfrom button into anchor */
  href: PropTypes.string,
  /** Defines an Icon position within the button */
  iconPosition: PropTypes.oneOf([...OptionsHelper.buttonIconPositions, '']),
  /** Defines an Icon type within the button (see Icon for options) */
  iconType: PropTypes.oneOf([...OptionsHelper.icons, '']),
  /** Assigns a size to the button */
  size: PropTypes.oneOf(OptionsHelper.sizesRestricted),
  /** Second text child, renders under main text, only when size is "large" */
  subtext: PropTypes.string,
  /** Set this prop to pass in legacy theme color variants */
  legacyColorVariant: PropTypes.oneOf(OptionsHelper.buttonColors),
  /** Used to transfrom button into anchor */
  to: PropTypes.string
};

export default StyledButton;
<|endoftext|>


<commit_before><commit_msg>FIO-2645 Made clicking on the error of Container component redirect to it (#4563)<commit_after><|endoftext|>


<commit_before>import Vue from '../../utils/vue'
import { mergeData } from 'vue-functional-data-merge'
import { getComponentConfig } from '../../utils/config'
import { stripTags } from '../../utils/html'
import { hasNormalizedSlot, normalizeSlot } from '../../utils/normalize-slot'
import { BContainer } from '../layout/container'

const NAME = 'BJumbotron'

export const props = {
  fluid: {
    type: Boolean,
    default: false
  },
  containerFluid: {
    type: Boolean,
    default: false
  },
  header: {
    type: String,
    default: null
  },
  headerHtml: {
    type: String,
    default: null
  },
  headerTag: {
    type: String,
    default: 'h1'
  },
  headerLevel: {
    type: [Number, String],
    default: '3'
  },
  lead: {
    type: String,
    default: null
  },
  leadHtml: {
    type: String,
    default: null
  },
  leadTag: {
    type: String,
    default: 'p'
  },
  tag: {
    type: String,
    default: 'div'
  },
  bgVariant: {
    type: String,
    default: () => getComponentConfig(NAME, 'bgVariant')
  },
  borderVariant: {
    type: String,
    default: () => getComponentConfig(NAME, 'borderVariant')
  },
  textVariant: {
    type: String,
    default: () => getComponentConfig(NAME, 'textVariant')
  }
}

// @vue/component
export const BJumbotron = /*#__PURE__*/ Vue.extend({
  name: NAME,
  functional: true,
  props,
  render(h, { props, data, slots, scopedSlots }) {
    // The order of the conditionals matter.
    // We are building the component markup in order.
    let childNodes = []
    const $slots = slots()
    const $scopedSlots = scopedSlots || {}

    // Header
    if (props.header || hasNormalizedSlot('header', $scopedSlots, $slots) || props.headerHtml) {
      childNodes.push(
        h(
          props.headerTag,
          {
            class: {
              [`display-${props.headerLevel}`]: Boolean(props.headerLevel)
            }
          },
          normalizeSlot('header', {}, $scopedSlots, $slots) ||
            props.headerHtml ||
            stripTags(props.header)
        )
      )
    }

    // Lead
    if (props.lead || hasNormalizedSlot('lead', $scopedSlots, $slots) || props.leadHtml) {
      childNodes.push(
        h(
          props.leadTag,
          { staticClass: 'lead' },
          normalizeSlot('lead', {}, $scopedSlots, $slots) || props.leadHtml || stripTags(props.lead)
        )
      )
    }

    // Default slot
    if (hasNormalizedSlot('default', $scopedSlots, $slots)) {
      childNodes.push(normalizeSlot('default', {}, $scopedSlots, $slots))
    }

    // If fluid, wrap content in a container/container-fluid
    if (props.fluid) {
      // Children become a child of a container
      childNodes = [h(BContainer, { props: { fluid: props.containerFluid } }, childNodes)]
    }
    // Return the jumbotron
    return h(
      props.tag,
      mergeData(data, {
        staticClass: 'jumbotron',
        class: {
          'jumbotron-fluid': props.fluid,
          [`text-${props.textVariant}`]: Boolean(props.textVariant),
          [`bg-${props.bgVariant}`]: Boolean(props.bgVariant),
          [`border-${props.borderVariant}`]: Boolean(props.borderVariant),
          border: Boolean(props.borderVariant)
        }
      }),
      childNodes
    )
  }
})

export default BJumbotron
<commit_msg>Update jumbotron.js<commit_after>import Vue from '../../utils/vue'
import { mergeData } from 'vue-functional-data-merge'
import { getComponentConfig } from '../../utils/config'
import { stripTags } from '../../utils/html'
import { hasNormalizedSlot, normalizeSlot } from '../../utils/normalize-slot'
import { BContainer } from '../layout/container'

const NAME = 'BJumbotron'

export const props = {
  fluid: {
    type: Boolean,
    default: false
  },
  containerFluid: {
    type: [Boolean, String],
    default: false
  },
  header: {
    type: String,
    default: null
  },
  headerHtml: {
    type: String,
    default: null
  },
  headerTag: {
    type: String,
    default: 'h1'
  },
  headerLevel: {
    type: [Number, String],
    default: '3'
  },
  lead: {
    type: String,
    default: null
  },
  leadHtml: {
    type: String,
    default: null
  },
  leadTag: {
    type: String,
    default: 'p'
  },
  tag: {
    type: String,
    default: 'div'
  },
  bgVariant: {
    type: String,
    default: () => getComponentConfig(NAME, 'bgVariant')
  },
  borderVariant: {
    type: String,
    default: () => getComponentConfig(NAME, 'borderVariant')
  },
  textVariant: {
    type: String,
    default: () => getComponentConfig(NAME, 'textVariant')
  }
}

// @vue/component
export const BJumbotron = /*#__PURE__*/ Vue.extend({
  name: NAME,
  functional: true,
  props,
  render(h, { props, data, slots, scopedSlots }) {
    // The order of the conditionals matter.
    // We are building the component markup in order.
    let childNodes = []
    const $slots = slots()
    const $scopedSlots = scopedSlots || {}

    // Header
    if (props.header || hasNormalizedSlot('header', $scopedSlots, $slots) || props.headerHtml) {
      childNodes.push(
        h(
          props.headerTag,
          {
            class: {
              [`display-${props.headerLevel}`]: Boolean(props.headerLevel)
            }
          },
          normalizeSlot('header', {}, $scopedSlots, $slots) ||
            props.headerHtml ||
            stripTags(props.header)
        )
      )
    }

    // Lead
    if (props.lead || hasNormalizedSlot('lead', $scopedSlots, $slots) || props.leadHtml) {
      childNodes.push(
        h(
          props.leadTag,
          { staticClass: 'lead' },
          normalizeSlot('lead', {}, $scopedSlots, $slots) || props.leadHtml || stripTags(props.lead)
        )
      )
    }

    // Default slot
    if (hasNormalizedSlot('default', $scopedSlots, $slots)) {
      childNodes.push(normalizeSlot('default', {}, $scopedSlots, $slots))
    }

    // If fluid, wrap content in a container/container-fluid
    if (props.fluid) {
      // Children become a child of a container
      childNodes = [h(BContainer, { props: { fluid: props.containerFluid } }, childNodes)]
    }
    // Return the jumbotron
    return h(
      props.tag,
      mergeData(data, {
        staticClass: 'jumbotron',
        class: {
          'jumbotron-fluid': props.fluid,
          [`text-${props.textVariant}`]: Boolean(props.textVariant),
          [`bg-${props.bgVariant}`]: Boolean(props.bgVariant),
          [`border-${props.borderVariant}`]: Boolean(props.borderVariant),
          border: Boolean(props.borderVariant)
        }
      }),
      childNodes
    )
  }
})

export default BJumbotron
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import * as React from 'react';
import { timeCode } from '../../../utils/time-code';
import classNames from 'classnames';
import Tooltip from '../Tooltip';

import type { CssPixels, DevicePixels } from '../../../types/units';

type Props<HoveredItem> = {
  containerWidth: CssPixels,
  containerHeight: CssPixels,
  className: string,
  onSelectItem?: (HoveredItem | null) => void,
  onDoubleClickItem: (HoveredItem | null) => void,
  getHoveredItemInfo: HoveredItem => React.Node,
  drawCanvas: (CanvasRenderingContext2D, HoveredItem | null) => void,
  isDragging: boolean,
  hitTest: (x: CssPixels, y: CssPixels) => HoveredItem | null,
};

// The naming of the X and Y coordinates here correspond to the ones
// found on the MouseEvent interface.
type State<HoveredItem> = {
  hoveredItem: HoveredItem | null,
  pageX: CssPixels,
  pageY: CssPixels,
};

require('./Canvas.css');

/**
 * The maximum amount of movement in either direction between the
 * mouse down and mouse up event for it to be interpreted as a
 * item-selecting click. We cannot use a real click event as a trigger
 * for selecting items because then a long dragging movement of the
 * viewport would still select items when the mouse button is
 * released. On the other hand, for accessibility reasons we want a
 * small amount of movement between mouse down and up to be okay.
 */
const MOUSE_CLICK_MAX_MOVEMENT_DELTA = 5;

// This isn't a PureComponent on purpose: we always want to update if the parent updates
// But we still conditionally update the canvas itself, see componentDidUpdate.
export default class ChartCanvas<HoveredItem> extends React.Component<
  Props<HoveredItem>,
  State<HoveredItem>
> {
  _devicePixelRatio: number = 1;
  _offsetX: CssPixels = 0;
  _offsetY: CssPixels = 0;
  _mouseDownOffsetX: CssPixels = 0;
  _mouseDownOffsetY: CssPixels = 0;
  _mouseMoved: boolean = false;
  _ctx: CanvasRenderingContext2D;
  _canvas: HTMLCanvasElement | null = null;
  _isDrawScheduled: boolean = false;

  state: State<HoveredItem> = {
    hoveredItem: null,
    pageX: 0,
    pageY: 0,
  };

  _scheduleDraw() {
    const { className, drawCanvas } = this.props;
    if (this._isDrawScheduled) {
      return;
    }
    this._isDrawScheduled = true;
    window.requestAnimationFrame(() => {
      this._isDrawScheduled = false;
      if (this._canvas) {
        timeCode(`${className} render`, () => {
          this._prepCanvas();
          drawCanvas(this._ctx, this.state.hoveredItem);
        });
      }
    });
  }

  _prepCanvas() {
    const canvas = this._canvas;
    const { containerWidth, containerHeight } = this.props;
    const { devicePixelRatio } = window;
    const pixelWidth: DevicePixels = containerWidth * devicePixelRatio;
    const pixelHeight: DevicePixels = containerHeight * devicePixelRatio;
    if (!canvas) {
      return;
    }
    // Satisfy the null check for Flow.
    const ctx = this._ctx || canvas.getContext('2d', { alpha: false });
    if (!this._ctx) {
      this._ctx = ctx;
    }
    if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) {
      canvas.width = pixelWidth;
      canvas.height = pixelHeight;
      canvas.style.width = containerWidth + 'px';
      canvas.style.height = containerHeight + 'px';
      ctx.scale(this._devicePixelRatio, this._devicePixelRatio);
    }
    if (this._devicePixelRatio !== devicePixelRatio) {
      // Make sure and multiply by the inverse of the previous ratio, as the scaling
      // operates off of the previous set scale.
      const scale = 1 / this._devicePixelRatio * devicePixelRatio;
      ctx.scale(scale, scale);
      this._devicePixelRatio = devicePixelRatio;
    }
  }

  _onMouseDown = (
    event: { nativeEvent: MouseEvent } & SyntheticMouseEvent<>
  ) => {
    this._mouseDownOffsetX = event.nativeEvent.offsetX;
    this._mouseDownOffsetY = event.nativeEvent.offsetY;
    this._mouseMoved = false;
  };

  _onMouseUp = () => {
    if (!this._mouseMoved && this.props.onSelectItem) {
      this.props.onSelectItem(this.state.hoveredItem);
    }
  };

  _onMouseMove = (
    event: { nativeEvent: MouseEvent } & SyntheticMouseEvent<>
  ) => {
    if (!this._canvas) {
      return;
    }

    this._offsetX = event.nativeEvent.offsetX;
    this._offsetY = event.nativeEvent.offsetY;
    const maybeHoveredItem = this.props.hitTest(this._offsetX, this._offsetY);

    if (
      Math.abs(this._offsetX - this._mouseDownOffsetX) >
        MOUSE_CLICK_MAX_MOVEMENT_DELTA ||
      Math.abs(this._offsetY - this._mouseDownOffsetY) >
        MOUSE_CLICK_MAX_MOVEMENT_DELTA
    ) {
      this._mouseMoved = true;
    }

    if (maybeHoveredItem !== null) {
      this.setState({
        hoveredItem: maybeHoveredItem,
        pageX: event.pageX,
        pageY: event.pageY,
      });
    } else if (this.state.hoveredItem !== null) {
      this.setState({
        hoveredItem: null,
      });
    }
  };

  _onMouseOut = () => {
    if (this.state.hoveredItem !== null) {
      this.setState({ hoveredItem: null });
    }
  };

  _onDoubleClick = () => {
    this.props.onDoubleClickItem(this.state.hoveredItem);
  };

  _getHoveredItemInfo = (): React.Node => {
    const { hoveredItem } = this.state;
    if (hoveredItem === null) {
      return null;
    }
    return this.props.getHoveredItemInfo(hoveredItem);
  };

  _takeCanvasRef = (canvas: HTMLCanvasElement | null) => {
    this._canvas = canvas;
  };

  componentWillReceiveProps() {
    // It is possible that the data backing the chart has been
    // changed, for instance after symbolication. Clear the
    // hoveredItem if the mouse no longer hovers over it.
    const { hoveredItem } = this.state;
    if (
      hoveredItem !== null &&
      !hoveredItemsAreEqual(
        this.props.hitTest(this._offsetX, this._offsetY),
        hoveredItem
      )
    ) {
      this.setState({ hoveredItem: null });
    }
  }

  componentDidUpdate(
    prevProps: Props<HoveredItem>,
    prevState: State<HoveredItem>
  ) {
    if (
      prevProps !== this.props ||
      !hoveredItemsAreEqual(prevState.hoveredItem, this.state.hoveredItem)
    ) {
      this._scheduleDraw();
    }
  }

  render() {
    const { isDragging } = this.props;
    const { hoveredItem, pageX, pageY } = this.state;

    const className = classNames({
      chartCanvas: true,
      [this.props.className]: true,
      hover: hoveredItem !== null,
    });

    const tooltipContents = this._getHoveredItemInfo();

    return (

        <canvas
          className={className}
          ref={this._takeCanvasRef}
          onMouseDown={this._onMouseDown}
          onMouseUp={this._onMouseUp}
          onMouseMove={this._onMouseMove}
          onMouseOut={this._onMouseOut}
          onDoubleClick={this._onDoubleClick}
        />
        {!isDragging && tooltipContents ? (
          <Tooltip mouseX={pageX} mouseY={pageY}>
            {tooltipContents}
          </Tooltip>
        ) : null}

    );
  }
}

/**
 * Check for shallow equality for objects, and strict equality for everything else.
 */
function hoveredItemsAreEqual(a: any, b: any) {
  if (a && b && typeof a === 'object' && typeof b === 'object') {
    if (a.length !== b.length) {
      return false;
    }
    let hasAllKeys = true;
    for (const aKey in a) {
      let hasKey = false;
      for (const bKey in b) {
        if (aKey === bKey) {
          if (a[aKey] !== b[bKey]) {
            return false;
          }
          hasKey = true;
          break;
        }
      }
      hasAllKeys = hasAllKeys && hasKey;
      if (!hasAllKeys) {
        return false;
      }
    }
    return true;
  }
  return a === b;
}
<commit_msg>Add comments after code review<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

// @flow
import * as React from 'react';
import { timeCode } from '../../../utils/time-code';
import classNames from 'classnames';
import Tooltip from '../Tooltip';

import type { CssPixels, DevicePixels } from '../../../types/units';

type Props<HoveredItem> = {
  containerWidth: CssPixels,
  containerHeight: CssPixels,
  className: string,
  onSelectItem?: (HoveredItem | null) => void,
  onDoubleClickItem: (HoveredItem | null) => void,
  getHoveredItemInfo: HoveredItem => React.Node,
  drawCanvas: (CanvasRenderingContext2D, HoveredItem | null) => void,
  isDragging: boolean,
  hitTest: (x: CssPixels, y: CssPixels) => HoveredItem | null,
};

// The naming of the X and Y coordinates here correspond to the ones
// found on the MouseEvent interface.
type State<HoveredItem> = {
  hoveredItem: HoveredItem | null,
  pageX: CssPixels,
  pageY: CssPixels,
};

require('./Canvas.css');

/**
 * The maximum amount of movement in either direction between the
 * mouse down and mouse up event for it to be interpreted as a
 * item-selecting click. We cannot use a real click event as a trigger
 * for selecting items because then a long dragging movement of the
 * viewport would still select items when the mouse button is
 * released. On the other hand, for accessibility reasons we want a
 * small amount of movement between mouse down and up to be okay.
 */
const MOUSE_CLICK_MAX_MOVEMENT_DELTA: CssPixels = 5;

// This isn't a PureComponent on purpose: we always want to update if the parent updates
// But we still conditionally update the canvas itself, see componentDidUpdate.
export default class ChartCanvas<HoveredItem> extends React.Component<
  Props<HoveredItem>,
  State<HoveredItem>
> {
  _devicePixelRatio: number = 1;
  // The current mouse position. Needs to be stored for tooltip
  // hit-test if props update.
  _offsetX: CssPixels = 0;
  _offsetY: CssPixels = 0;
  // The position of the most recent mouse down event. Needed for
  // comparison with the current mouse position in order to
  // distinguish between clicks and drags.
  _mouseDownOffsetX: CssPixels = 0;
  _mouseDownOffsetY: CssPixels = 0;
  // Indicates if move threshold breached. Checked at mouse up event
  // to prevent it from being interpreted as a click.
  _mouseMovedWhileClicked: boolean = false;
  _ctx: CanvasRenderingContext2D;
  _canvas: HTMLCanvasElement | null = null;
  _isDrawScheduled: boolean = false;

  state: State<HoveredItem> = {
    hoveredItem: null,
    pageX: 0,
    pageY: 0,
  };

  _scheduleDraw() {
    const { className, drawCanvas } = this.props;
    if (this._isDrawScheduled) {
      return;
    }
    this._isDrawScheduled = true;
    window.requestAnimationFrame(() => {
      this._isDrawScheduled = false;
      if (this._canvas) {
        timeCode(`${className} render`, () => {
          this._prepCanvas();
          drawCanvas(this._ctx, this.state.hoveredItem);
        });
      }
    });
  }

  _prepCanvas() {
    const canvas = this._canvas;
    const { containerWidth, containerHeight } = this.props;
    const { devicePixelRatio } = window;
    const pixelWidth: DevicePixels = containerWidth * devicePixelRatio;
    const pixelHeight: DevicePixels = containerHeight * devicePixelRatio;
    if (!canvas) {
      return;
    }
    // Satisfy the null check for Flow.
    const ctx = this._ctx || canvas.getContext('2d', { alpha: false });
    if (!this._ctx) {
      this._ctx = ctx;
    }
    if (canvas.width !== pixelWidth || canvas.height !== pixelHeight) {
      canvas.width = pixelWidth;
      canvas.height = pixelHeight;
      canvas.style.width = containerWidth + 'px';
      canvas.style.height = containerHeight + 'px';
      ctx.scale(this._devicePixelRatio, this._devicePixelRatio);
    }
    if (this._devicePixelRatio !== devicePixelRatio) {
      // Make sure and multiply by the inverse of the previous ratio, as the scaling
      // operates off of the previous set scale.
      const scale = 1 / this._devicePixelRatio * devicePixelRatio;
      ctx.scale(scale, scale);
      this._devicePixelRatio = devicePixelRatio;
    }
  }

  _onMouseDown = (
    event: { nativeEvent: MouseEvent } & SyntheticMouseEvent<>
  ) => {
    // Remember where the mouse was positioned. Move too far and it
    // won't be registered as a selecting click on mouse up.
    this._mouseDownOffsetX = event.nativeEvent.offsetX;
    this._mouseDownOffsetY = event.nativeEvent.offsetY;
    this._mouseMovedWhileClicked = false;
  };

  _onMouseUp = () => {
    if (!this._mouseMovedWhileClicked && this.props.onSelectItem) {
      this.props.onSelectItem(this.state.hoveredItem);
    }
  };

  _onMouseMove = (
    event: { nativeEvent: MouseEvent } & SyntheticMouseEvent<>
  ) => {
    if (!this._canvas) {
      return;
    }

    this._offsetX = event.nativeEvent.offsetX;
    this._offsetY = event.nativeEvent.offsetY;
    const maybeHoveredItem = this.props.hitTest(this._offsetX, this._offsetY);

    // If the mouse moves too far while a button down, flag this as
    // drag event only. Then it won't select anything when the button
    // is released.
    if (
      !this._mouseMovedWhileClicked &&
      event.buttons !== 0 &&
      (Math.abs(this._offsetX - this._mouseDownOffsetX) >
        MOUSE_CLICK_MAX_MOVEMENT_DELTA ||
        Math.abs(this._offsetY - this._mouseDownOffsetY) >
          MOUSE_CLICK_MAX_MOVEMENT_DELTA)
    ) {
      this._mouseMovedWhileClicked = true;
    }

    if (maybeHoveredItem !== null) {
      this.setState({
        hoveredItem: maybeHoveredItem,
        pageX: event.pageX,
        pageY: event.pageY,
      });
    } else if (this.state.hoveredItem !== null) {
      this.setState({
        hoveredItem: null,
      });
    }
  };

  _onMouseOut = () => {
    if (this.state.hoveredItem !== null) {
      this.setState({ hoveredItem: null });
    }
  };

  _onDoubleClick = () => {
    this.props.onDoubleClickItem(this.state.hoveredItem);
  };

  _getHoveredItemInfo = (): React.Node => {
    const { hoveredItem } = this.state;
    if (hoveredItem === null) {
      return null;
    }
    return this.props.getHoveredItemInfo(hoveredItem);
  };

  _takeCanvasRef = (canvas: HTMLCanvasElement | null) => {
    this._canvas = canvas;
  };

  componentWillReceiveProps() {
    // It is possible that the data backing the chart has been
    // changed, for instance after symbolication. Clear the
    // hoveredItem if the mouse no longer hovers over it.
    const { hoveredItem } = this.state;
    if (
      hoveredItem !== null &&
      !hoveredItemsAreEqual(
        this.props.hitTest(this._offsetX, this._offsetY),
        hoveredItem
      )
    ) {
      this.setState({ hoveredItem: null });
    }
  }

  componentDidUpdate(
    prevProps: Props<HoveredItem>,
    prevState: State<HoveredItem>
  ) {
    if (
      prevProps !== this.props ||
      !hoveredItemsAreEqual(prevState.hoveredItem, this.state.hoveredItem)
    ) {
      this._scheduleDraw();
    }
  }

  render() {
    const { isDragging } = this.props;
    const { hoveredItem, pageX, pageY } = this.state;

    const className = classNames({
      chartCanvas: true,
      [this.props.className]: true,
      hover: hoveredItem !== null,
    });

    const tooltipContents = this._getHoveredItemInfo();

    return (

        <canvas
          className={className}
          ref={this._takeCanvasRef}
          onMouseDown={this._onMouseDown}
          onMouseUp={this._onMouseUp}
          onMouseMove={this._onMouseMove}
          onMouseOut={this._onMouseOut}
          onDoubleClick={this._onDoubleClick}
        />
        {!isDragging && tooltipContents ? (
          <Tooltip mouseX={pageX} mouseY={pageY}>
            {tooltipContents}
          </Tooltip>
        ) : null}

    );
  }
}

/**
 * Check for shallow equality for objects, and strict equality for everything else.
 */
function hoveredItemsAreEqual(a: any, b: any) {
  if (a && b && typeof a === 'object' && typeof b === 'object') {
    if (a.length !== b.length) {
      return false;
    }
    let hasAllKeys = true;
    for (const aKey in a) {
      let hasKey = false;
      for (const bKey in b) {
        if (aKey === bKey) {
          if (a[aKey] !== b[bKey]) {
            return false;
          }
          hasKey = true;
          break;
        }
      }
      hasAllKeys = hasAllKeys && hasKey;
      if (!hasAllKeys) {
        return false;
      }
    }
    return true;
  }
  return a === b;
}
<|endoftext|>


<commit_before>{% import modulePath + "example-module/example-module.njs" as example %}

{% extends templatePath + "default.njs" %}

{% block pageTitle %}Example page{% endblock %}

{% block content %}

This is a simple example of a nunjucks template

        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorum repudiandae esse dolores quos minus perspiciatis laboriosam magni ipsum, optio sed quae aliquid sequi consectetur eaque vel, est ducimus similique illum. Debitis ea dolorum temporibus doloremque ratione, nesciunt aspernatur. Velit saepe dicta ipsa minus iusto odit ex, obcaecati temporibus, sint deserunt.

    {{ example.macro() }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
{% endblock %}
<commit_msg>Fixes example page<commit_after>{% import modulesPath + "example-module/example-module.njs" as example %}

{% extends templatePath + "default.njs" %}

{% block pageTitle %}Example page{% endblock %}

{% block content %}

This is a simple example of a nunjucks template

        Lorem ipsum dolor sit amet, consectetur adipisicing elit. Dolorum repudiandae esse dolores quos minus perspiciatis laboriosam magni ipsum, optio sed quae aliquid sequi consectetur eaque vel, est ducimus similique illum. Debitis ea dolorum temporibus doloremque ratione, nesciunt aspernatur. Velit saepe dicta ipsa minus iusto odit ex, obcaecati temporibus, sint deserunt.

    {{ example.macro() }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
    {{ example.macro(true) }}
{% endblock %}
<|endoftext|>