<commit_before>import {DivOverlay} from './DivOverlay';
import {toPoint} from '../geometry/Point';
import {Map} from '../map/Map';
import {Layer} from './Layer';
import * as Util from '../core/Util';
import * as DomUtil from '../dom/DomUtil';

/*
 * @class Tooltip
 * @inherits DivOverlay
 * @aka L.Tooltip
 * Used to display small texts on top of map layers.
 *
 * @example
 *
 * ```js
 * marker.bindTooltip("my tooltip text").openTooltip();
 * ```
 * Note about tooltip offset. Leaflet takes two options in consideration
 * for computing tooltip offsetting:
 * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
 *   Add a positive x offset to move the tooltip to the right, and a positive y offset to
 *   move it to the bottom. Negatives will move to the left and top.
 * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
 *   should adapt this value if you use a custom icon.
 */

// @namespace Tooltip
export var Tooltip = DivOverlay.extend({

	// @section
	// @aka Tooltip options
	options: {
		// @option pane: String = 'tooltipPane'
		// `Map pane` where the tooltip will be added.
		pane: 'tooltipPane',

		// @option offset: Point = Point(0, 0)
		// Optional offset of the tooltip position.
		offset: [0, 0],

		// @option direction: String = 'auto'
		// Direction where to open the tooltip. Possible values are: `right`, `left`,
		// `top`, `bottom`, `center`, `auto`.
		// `auto` will dynamically switch between `right` and `left` according to the tooltip
		// position on the map.
		direction: 'auto',

		// @option permanent: Boolean = false
		// Whether to open the tooltip permanently or only on mouseover.
		permanent: false,

		// @option sticky: Boolean = false
		// If true, the tooltip will follow the mouse instead of being fixed at the feature center.
		sticky: false,

		// @option interactive: Boolean = false
		// If true, the tooltip will listen to the feature events.
		interactive: false,

		// @option opacity: Number = 0.9
		// Tooltip container opacity.
		opacity: 0.9
	},

	onAdd: function (map) {
		DivOverlay.prototype.onAdd.call(this, map);
		this.setOpacity(this.options.opacity);

		if (this.options.interactive) {
			DomUtil.addClass(this._container, 'leaflet-clickable');
			if (this._source) {
				this._source.addInteractiveTarget(this._container);
			}
		}

		// @namespace Map
		// @section Tooltip events
		// @event tooltipopen: TooltipEvent
		// Fired when a tooltip is opened in the map.
		map.fire('tooltipopen', {tooltip: this});

		if (this._source) {
			// @namespace Layer
			// @section Tooltip events
			// @event tooltipopen: TooltipEvent
			// Fired when a tooltip bound to this layer is opened.
			this._source.fire('tooltipopen', {tooltip: this}, true);
		}
	},

	onRemove: function (map) {
		DivOverlay.prototype.onRemove.call(this, map);

		if (this.options.interactive) {
			DomUtil.removeClass(this._container, 'leaflet-clickable');
			if (this._source) {
				this._source.removeInteractiveTarget(this._container);
			}
		}

		// @namespace Map
		// @section Tooltip events
		// @event tooltipclose: TooltipEvent
		// Fired when a tooltip in the map is closed.
		map.fire('tooltipclose', {tooltip: this});

		if (this._source) {
			// @namespace Layer
			// @section Tooltip events
			// @event tooltipclose: TooltipEvent
			// Fired when a tooltip bound to this layer is closed.
			this._source.fire('tooltipclose', {tooltip: this}, true);
		}
	},

	getEvents: function () {
		var events = DivOverlay.prototype.getEvents.call(this);

		if (!this.options.permanent) {
			events.preclick = this._close;
		}

		return events;
	},

	_close: function () {
		if (this._map) {
			this._map.closeTooltip(this);
		}
	},

	_initLayout: function () {
		var prefix = 'leaflet-tooltip',
		    className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');

		this._contentNode = this._container = DomUtil.create('div', className);
	},

	_updateLayout: function () {},

	_adjustPan: function () {},

	_setPosition: function (pos) {
		var subX, subY,
		    map = this._map,
		    container = this._container,
		    centerPoint = map.latLngToContainerPoint(map.getCenter()),
		    tooltipPoint = map.layerPointToContainerPoint(pos),
		    direction = this.options.direction,
		    tooltipWidth = container.offsetWidth,
		    tooltipHeight = container.offsetHeight,
		    offset = toPoint(this.options.offset),
		    anchor = this._getAnchor();

		if (direction === 'top') {
			subX = tooltipWidth / 2;
			subY = tooltipHeight;
		} else if (direction === 'bottom') {
			subX = tooltipWidth / 2;
			subY = 0;
		} else if (direction === 'center') {
			subX = tooltipWidth / 2;
			subY = tooltipHeight / 2;
		} else if (direction === 'right') {
			subX = 0;
			subY = tooltipHeight / 2;
		} else if (direction === 'left') {
			subX = tooltipWidth;
			subY = tooltipHeight / 2;
		} else if (tooltipPoint.x < centerPoint.x) {
			direction = 'right';
			subX = 0;
			subY = tooltipHeight / 2;
		} else {
			direction = 'left';
			subX = tooltipWidth + (offset.x + anchor.x) * 2;
			subY = tooltipHeight / 2;
		}

		pos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);

		DomUtil.removeClass(container, 'leaflet-tooltip-right');
		DomUtil.removeClass(container, 'leaflet-tooltip-left');
		DomUtil.removeClass(container, 'leaflet-tooltip-top');
		DomUtil.removeClass(container, 'leaflet-tooltip-bottom');
		DomUtil.addClass(container, 'leaflet-tooltip-' + direction);
		DomUtil.setPosition(container, pos);
	},

	_updatePosition: function () {
		var pos = this._map.latLngToLayerPoint(this._latlng);
		this._setPosition(pos);
	},

	setOpacity: function (opacity) {
		this.options.opacity = opacity;

		if (this._container) {
			DomUtil.setOpacity(this._container, opacity);
		}
	},

	_animateZoom: function (e) {
		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
		this._setPosition(pos);
	},

	_getAnchor: function () {
		// Where should we anchor the tooltip on the source layer?
		return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
	}

});

// @namespace Tooltip
// @factory L.tooltip(options?: Tooltip options, source?: Layer)
// Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
export var tooltip = function (options, source) {
	return new Tooltip(options, source);
};

// @namespace Map
// @section Methods for Layers and Controls
Map.include({

	// @method openTooltip(tooltip: Tooltip): this
	// Opens the specified tooltip.
	// @alternative
	// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
	// Creates a tooltip with the specified content and options and open it.
	openTooltip: function (tooltip, latlng, options) {
		if (!(tooltip instanceof Tooltip)) {
			tooltip = new Tooltip(options).setContent(tooltip);
		}

		if (latlng) {
			tooltip.setLatLng(latlng);
		}

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

		return this.addLayer(tooltip);
	},

	// @method closeTooltip(tooltip?: Tooltip): this
	// Closes the tooltip given as parameter.
	closeTooltip: function (tooltip) {
		if (tooltip) {
			this.removeLayer(tooltip);
		}
		return this;
	}

});

/*
 * @namespace Layer
 * @section Tooltip methods example
 *
 * All layers share a set of methods convenient for binding tooltips to it.
 *
 * ```js
 * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
 * layer.openTooltip();
 * layer.closeTooltip();
 * ```
 */

// @section Tooltip methods
Layer.include({

	// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
	// Binds a tooltip to the layer with the passed `content` and sets up the
	// necessary event listeners. If a `Function` is passed it will receive
	// the layer as the first argument and should return a `String` or `HTMLElement`.
	bindTooltip: function (content, options) {

		if (content instanceof Tooltip) {
			Util.setOptions(content, options);
			this._tooltip = content;
			content._source = this;
		} else {
			if (!this._tooltip || options) {
				this._tooltip = new Tooltip(options, this);
			}
			this._tooltip.setContent(content);

		}

		this._initTooltipInteractions();

		if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
			this.openTooltip();
		}

		return this;
	},

	// @method unbindTooltip(): this
	// Removes the tooltip previously bound with `bindTooltip`.
	unbindTooltip: function () {
		if (this._tooltip) {
			this._initTooltipInteractions(true);
			this.closeTooltip();
			this._tooltip = null;
		}
		return this;
	},

	_initTooltipInteractions: function (remove) {
		if (!remove && this._tooltipHandlersAdded) { return; }
		var onOff = remove ? 'off' : 'on',
		    events = {
			remove: this.closeTooltip,
			move: this._moveTooltip
		    };
		if (!this._tooltip.options.permanent) {
			events.mouseover = this._openTooltip;
			events.mouseout = this.closeTooltip;
			if (this._tooltip.options.sticky) {
				events.mousemove = this._moveTooltip;
			}
			events.click = this._openTooltip;
		} else {
			events.add = this._openTooltip;
		}
		this[onOff](events);
		this._tooltipHandlersAdded = !remove;
	},

	// @method openTooltip(latlng?: LatLng): this
	// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
	openTooltip: function (layer, latlng) {
		if (this._tooltip && this._map) {
			latlng = this._tooltip._prepareOpen(this, layer, latlng);

			// open the tooltip on the map
			this._map.openTooltip(this._tooltip, latlng);
		}

		return this;
	},

	// @method closeTooltip(): this
	// Closes the tooltip bound to this layer if it is open.
	closeTooltip: function () {
		if (this._tooltip) {
			this._tooltip._close();
		}
		return this;
	},

	// @method toggleTooltip(): this
	// Opens or closes the tooltip bound to this layer depending on its current state.
	toggleTooltip: function (target) {
		if (this._tooltip) {
			if (this._tooltip._map) {
				this.closeTooltip();
			} else {
				this.openTooltip(target);
			}
		}
		return this;
	},

	// @method isTooltipOpen(): boolean
	// Returns `true` if the tooltip bound to this layer is currently open.
	isTooltipOpen: function () {
		return this._tooltip.isOpen();
	},

	// @method setTooltipContent(content: String|HTMLElement|Tooltip): this
	// Sets the content of the tooltip bound to this layer.
	setTooltipContent: function (content) {
		if (this._tooltip) {
			this._tooltip.setContent(content);
		}
		return this;
	},

	// @method getTooltip(): Tooltip
	// Returns the tooltip bound to this layer.
	getTooltip: function () {
		return this._tooltip;
	},

	_openTooltip: function (e) {
		var layer = e.layer || e.target;

		if (!this._tooltip || !this._map) {
			return;
		}
		this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
	},

	_moveTooltip: function (e) {
		var latlng = e.latlng, containerPoint, layerPoint;
		if (this._tooltip.options.sticky && e.originalEvent) {
			containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
			layerPoint = this._map.containerPointToLayerPoint(containerPoint);
			latlng = this._map.layerPointToLatLng(layerPoint);
		}
		this._tooltip.setLatLng(latlng);
	}
});
<commit_msg>Map/closeTooltip: make argument not optional (#7533)<commit_after>import {DivOverlay} from './DivOverlay';
import {toPoint} from '../geometry/Point';
import {Map} from '../map/Map';
import {Layer} from './Layer';
import * as Util from '../core/Util';
import * as DomUtil from '../dom/DomUtil';

/*
 * @class Tooltip
 * @inherits DivOverlay
 * @aka L.Tooltip
 * Used to display small texts on top of map layers.
 *
 * @example
 *
 * ```js
 * marker.bindTooltip("my tooltip text").openTooltip();
 * ```
 * Note about tooltip offset. Leaflet takes two options in consideration
 * for computing tooltip offsetting:
 * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
 *   Add a positive x offset to move the tooltip to the right, and a positive y offset to
 *   move it to the bottom. Negatives will move to the left and top.
 * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
 *   should adapt this value if you use a custom icon.
 */

// @namespace Tooltip
export var Tooltip = DivOverlay.extend({

	// @section
	// @aka Tooltip options
	options: {
		// @option pane: String = 'tooltipPane'
		// `Map pane` where the tooltip will be added.
		pane: 'tooltipPane',

		// @option offset: Point = Point(0, 0)
		// Optional offset of the tooltip position.
		offset: [0, 0],

		// @option direction: String = 'auto'
		// Direction where to open the tooltip. Possible values are: `right`, `left`,
		// `top`, `bottom`, `center`, `auto`.
		// `auto` will dynamically switch between `right` and `left` according to the tooltip
		// position on the map.
		direction: 'auto',

		// @option permanent: Boolean = false
		// Whether to open the tooltip permanently or only on mouseover.
		permanent: false,

		// @option sticky: Boolean = false
		// If true, the tooltip will follow the mouse instead of being fixed at the feature center.
		sticky: false,

		// @option interactive: Boolean = false
		// If true, the tooltip will listen to the feature events.
		interactive: false,

		// @option opacity: Number = 0.9
		// Tooltip container opacity.
		opacity: 0.9
	},

	onAdd: function (map) {
		DivOverlay.prototype.onAdd.call(this, map);
		this.setOpacity(this.options.opacity);

		if (this.options.interactive) {
			DomUtil.addClass(this._container, 'leaflet-clickable');
			if (this._source) {
				this._source.addInteractiveTarget(this._container);
			}
		}

		// @namespace Map
		// @section Tooltip events
		// @event tooltipopen: TooltipEvent
		// Fired when a tooltip is opened in the map.
		map.fire('tooltipopen', {tooltip: this});

		if (this._source) {
			// @namespace Layer
			// @section Tooltip events
			// @event tooltipopen: TooltipEvent
			// Fired when a tooltip bound to this layer is opened.
			this._source.fire('tooltipopen', {tooltip: this}, true);
		}
	},

	onRemove: function (map) {
		DivOverlay.prototype.onRemove.call(this, map);

		if (this.options.interactive) {
			DomUtil.removeClass(this._container, 'leaflet-clickable');
			if (this._source) {
				this._source.removeInteractiveTarget(this._container);
			}
		}

		// @namespace Map
		// @section Tooltip events
		// @event tooltipclose: TooltipEvent
		// Fired when a tooltip in the map is closed.
		map.fire('tooltipclose', {tooltip: this});

		if (this._source) {
			// @namespace Layer
			// @section Tooltip events
			// @event tooltipclose: TooltipEvent
			// Fired when a tooltip bound to this layer is closed.
			this._source.fire('tooltipclose', {tooltip: this}, true);
		}
	},

	getEvents: function () {
		var events = DivOverlay.prototype.getEvents.call(this);

		if (!this.options.permanent) {
			events.preclick = this._close;
		}

		return events;
	},

	_close: function () {
		if (this._map) {
			this._map.closeTooltip(this);
		}
	},

	_initLayout: function () {
		var prefix = 'leaflet-tooltip',
		    className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');

		this._contentNode = this._container = DomUtil.create('div', className);
	},

	_updateLayout: function () {},

	_adjustPan: function () {},

	_setPosition: function (pos) {
		var subX, subY,
		    map = this._map,
		    container = this._container,
		    centerPoint = map.latLngToContainerPoint(map.getCenter()),
		    tooltipPoint = map.layerPointToContainerPoint(pos),
		    direction = this.options.direction,
		    tooltipWidth = container.offsetWidth,
		    tooltipHeight = container.offsetHeight,
		    offset = toPoint(this.options.offset),
		    anchor = this._getAnchor();

		if (direction === 'top') {
			subX = tooltipWidth / 2;
			subY = tooltipHeight;
		} else if (direction === 'bottom') {
			subX = tooltipWidth / 2;
			subY = 0;
		} else if (direction === 'center') {
			subX = tooltipWidth / 2;
			subY = tooltipHeight / 2;
		} else if (direction === 'right') {
			subX = 0;
			subY = tooltipHeight / 2;
		} else if (direction === 'left') {
			subX = tooltipWidth;
			subY = tooltipHeight / 2;
		} else if (tooltipPoint.x < centerPoint.x) {
			direction = 'right';
			subX = 0;
			subY = tooltipHeight / 2;
		} else {
			direction = 'left';
			subX = tooltipWidth + (offset.x + anchor.x) * 2;
			subY = tooltipHeight / 2;
		}

		pos = pos.subtract(toPoint(subX, subY, true)).add(offset).add(anchor);

		DomUtil.removeClass(container, 'leaflet-tooltip-right');
		DomUtil.removeClass(container, 'leaflet-tooltip-left');
		DomUtil.removeClass(container, 'leaflet-tooltip-top');
		DomUtil.removeClass(container, 'leaflet-tooltip-bottom');
		DomUtil.addClass(container, 'leaflet-tooltip-' + direction);
		DomUtil.setPosition(container, pos);
	},

	_updatePosition: function () {
		var pos = this._map.latLngToLayerPoint(this._latlng);
		this._setPosition(pos);
	},

	setOpacity: function (opacity) {
		this.options.opacity = opacity;

		if (this._container) {
			DomUtil.setOpacity(this._container, opacity);
		}
	},

	_animateZoom: function (e) {
		var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
		this._setPosition(pos);
	},

	_getAnchor: function () {
		// Where should we anchor the tooltip on the source layer?
		return toPoint(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
	}

});

// @namespace Tooltip
// @factory L.tooltip(options?: Tooltip options, source?: Layer)
// Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
export var tooltip = function (options, source) {
	return new Tooltip(options, source);
};

// @namespace Map
// @section Methods for Layers and Controls
Map.include({

	// @method openTooltip(tooltip: Tooltip): this
	// Opens the specified tooltip.
	// @alternative
	// @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
	// Creates a tooltip with the specified content and options and open it.
	openTooltip: function (tooltip, latlng, options) {
		if (!(tooltip instanceof Tooltip)) {
			tooltip = new Tooltip(options).setContent(tooltip);
		}

		if (latlng) {
			tooltip.setLatLng(latlng);
		}

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

		return this.addLayer(tooltip);
	},

	// @method closeTooltip(tooltip: Tooltip): this
	// Closes the tooltip given as parameter.
	closeTooltip: function (tooltip) {
		return this.removeLayer(tooltip);
	}

});

/*
 * @namespace Layer
 * @section Tooltip methods example
 *
 * All layers share a set of methods convenient for binding tooltips to it.
 *
 * ```js
 * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
 * layer.openTooltip();
 * layer.closeTooltip();
 * ```
 */

// @section Tooltip methods
Layer.include({

	// @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
	// Binds a tooltip to the layer with the passed `content` and sets up the
	// necessary event listeners. If a `Function` is passed it will receive
	// the layer as the first argument and should return a `String` or `HTMLElement`.
	bindTooltip: function (content, options) {

		if (content instanceof Tooltip) {
			Util.setOptions(content, options);
			this._tooltip = content;
			content._source = this;
		} else {
			if (!this._tooltip || options) {
				this._tooltip = new Tooltip(options, this);
			}
			this._tooltip.setContent(content);

		}

		this._initTooltipInteractions();

		if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
			this.openTooltip();
		}

		return this;
	},

	// @method unbindTooltip(): this
	// Removes the tooltip previously bound with `bindTooltip`.
	unbindTooltip: function () {
		if (this._tooltip) {
			this._initTooltipInteractions(true);
			this.closeTooltip();
			this._tooltip = null;
		}
		return this;
	},

	_initTooltipInteractions: function (remove) {
		if (!remove && this._tooltipHandlersAdded) { return; }
		var onOff = remove ? 'off' : 'on',
		    events = {
			remove: this.closeTooltip,
			move: this._moveTooltip
		    };
		if (!this._tooltip.options.permanent) {
			events.mouseover = this._openTooltip;
			events.mouseout = this.closeTooltip;
			if (this._tooltip.options.sticky) {
				events.mousemove = this._moveTooltip;
			}
			events.click = this._openTooltip;
		} else {
			events.add = this._openTooltip;
		}
		this[onOff](events);
		this._tooltipHandlersAdded = !remove;
	},

	// @method openTooltip(latlng?: LatLng): this
	// Opens the bound tooltip at the specified `latlng` or at the default tooltip anchor if no `latlng` is passed.
	openTooltip: function (layer, latlng) {
		if (this._tooltip && this._map) {
			latlng = this._tooltip._prepareOpen(this, layer, latlng);

			// open the tooltip on the map
			this._map.openTooltip(this._tooltip, latlng);
		}

		return this;
	},

	// @method closeTooltip(): this
	// Closes the tooltip bound to this layer if it is open.
	closeTooltip: function () {
		if (this._tooltip) {
			this._tooltip._close();
		}
		return this;
	},

	// @method toggleTooltip(): this
	// Opens or closes the tooltip bound to this layer depending on its current state.
	toggleTooltip: function (target) {
		if (this._tooltip) {
			if (this._tooltip._map) {
				this.closeTooltip();
			} else {
				this.openTooltip(target);
			}
		}
		return this;
	},

	// @method isTooltipOpen(): boolean
	// Returns `true` if the tooltip bound to this layer is currently open.
	isTooltipOpen: function () {
		return this._tooltip.isOpen();
	},

	// @method setTooltipContent(content: String|HTMLElement|Tooltip): this
	// Sets the content of the tooltip bound to this layer.
	setTooltipContent: function (content) {
		if (this._tooltip) {
			this._tooltip.setContent(content);
		}
		return this;
	},

	// @method getTooltip(): Tooltip
	// Returns the tooltip bound to this layer.
	getTooltip: function () {
		return this._tooltip;
	},

	_openTooltip: function (e) {
		var layer = e.layer || e.target;

		if (!this._tooltip || !this._map) {
			return;
		}
		this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
	},

	_moveTooltip: function (e) {
		var latlng = e.latlng, containerPoint, layerPoint;
		if (this._tooltip.options.sticky && e.originalEvent) {
			containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
			layerPoint = this._map.containerPointToLayerPoint(containerPoint);
			latlng = this._map.layerPointToLatLng(layerPoint);
		}
		this._tooltip.setLatLng(latlng);
	}
});
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react';
import classNames from 'classnames';
import HeaderRow from './HeaderRow';
import HeaderTabs from './HeaderTabs';

class Header extends React.Component {
    static propTypes = {
        className: PropTypes.string,
        scroll: PropTypes.bool,
        title: PropTypes.string,
        transparent: PropTypes.bool,
        waterfall: PropTypes.bool
    }

    render() {
        var { className, scroll, title, transparent, waterfall, ...otherProps } = this.props;

        var classes = classNames('mdl-layout__header', {
            'mdl-layout__header--scroll': scroll,
            'mdl-layout__header--transparent': transparent,
            'mdl-layout__header--waterfall': waterfall
        }, className);

        var isRowOrTab = false;
        React.Children.forEach(this.props.children, child => {
            if(child.type === HeaderRow || child.type === HeaderTabs) {
                isRowOrTab = true;
            }
        });

        return (
            <header className={classes} {...otherProps}>
                {isRowOrTab ? this.props.children : (
                    <HeaderRow title={title}>{this.props.children}</HeaderRow>
                )}
            </header>
        );
    }
}

export default Header;
<commit_msg>Fixed error if there are no children in the header<commit_after>import React, { PropTypes } from 'react';
import classNames from 'classnames';
import HeaderRow from './HeaderRow';
import HeaderTabs from './HeaderTabs';

class Header extends React.Component {
    static propTypes = {
        className: PropTypes.string,
        scroll: PropTypes.bool,
        title: PropTypes.string,
        transparent: PropTypes.bool,
        waterfall: PropTypes.bool
    }

    render() {
        var { className, scroll, title, transparent, waterfall, ...otherProps } = this.props;

        var classes = classNames('mdl-layout__header', {
            'mdl-layout__header--scroll': scroll,
            'mdl-layout__header--transparent': transparent,
            'mdl-layout__header--waterfall': waterfall
        }, className);

        var isRowOrTab = false;
        React.Children.forEach(this.props.children, child => {
            if(child && (child.type === HeaderRow || child.type === HeaderTabs)) {
                isRowOrTab = true;
            }
        });

        return (
            <header className={classes} {...otherProps}>
                {isRowOrTab ? this.props.children : (
                    <HeaderRow title={title}>{this.props.children}</HeaderRow>
                )}
            </header>
        );
    }
}

export default Header;
<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import SideBar from '../component/SideBar'
import Navigation from '../component/Navigation'
import styled from 'styled-components'
import { media } from '../utils/style'
import './reset.css'
import './spoqa-han-sans.css'
import './index.css'

const NavigationWrapper = styled.div`
  display: none;
  ${media.mobile`
  display: block;
  `}
`

const Body = styled.div`
  position: relative;
`

const ContentBlock = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: black;
  z-index: ${props => props.mobileSideNavVisible ? 2 : -1};
  opacity: ${props => props.mobileSideNavVisible ? '0.7' : '0'};
  transition: all 0.5s ease;
`

const Content = styled.div`
  position: relative;
  margin-left: 300px;
  padding: 50px;
  z-index: 0;
  ${media.mobile`
  margin-left: 0;
  margin-top: 50px;
  min-height: calc( 100vh - 50px );
  padding: 20px;
  `}
  transition: all 0.3s ease;
`

class TemplateWrapper extends React.Component {

  state = {
    mobileSideNavVisible: false,
  }

  toggleMobileSideNavVisible = (e) => {
    e.stopPropagation();
    const { mobileSideNavVisible  } = this.state;
    this.setState({mobileSideNavVisible : !mobileSideNavVisible})
  }

  onClickSideBarItem = (e) => {
    e.stopPropagation();
    this.hideWhenMobileSideNav();
  }

  componentDidMount() {
    window.addEventListener('click', this.hideWhenMobileSideNav )
  }
  componentWillUnmound() {
    window.removeEventListner('click', this.hideWhenMobileSideNav )
  }

  hideWhenMobileSideNav = () => {
    if (this.state.mobileSideNavVisible ) {
      this.setState({ mobileSideNavVisible: false })
    }
  }

  render() {
    const { mobileSideNavVisible } = this.state;
    const { title, image } = this.props.data.site.siteMetadata;
    return (

        <Helmet
          title={title}
          meta={[
            { name: 'description', content: 'holdonnn\'s blog' },
            { name: 'og:description', content: 'holdonnn\'s blog' },
            { name: 'keywords', content: 'blog' },
            { name: 'image', content: image },
            { name: 'og:image', content: image },
          ]}
        />
        <NavigationWrapper>
          <Navigation
            onClickMenu={this.toggleMobileSideNavVisible}
          />
        </NavigationWrapper>

          <SideBar
            onClickSideBarItem={this.onClickSideBarItem}
            mobileSideNavVisible={mobileSideNavVisible}
          />
          <Content mobileSideNavVisible={mobileSideNavVisible}>
            <ContentBlock mobileSideNavVisible={mobileSideNavVisible} />
            {this.props.children()}
          </Content>

    )
  }
}

TemplateWrapper.propTypes = {
  children: PropTypes.func,
}

export default TemplateWrapper

export const query = graphql`
  query LayoutQuery {
    site {
      siteMetadata {
        title
        image
      }
    }
  }
`
<commit_msg>remove animation<commit_after>import React from 'react'
import PropTypes from 'prop-types'
import Helmet from 'react-helmet'
import SideBar from '../component/SideBar'
import Navigation from '../component/Navigation'
import styled from 'styled-components'
import { media } from '../utils/style'
import './reset.css'
import './spoqa-han-sans.css'
import './index.css'

const NavigationWrapper = styled.div`
  display: none;
  ${media.mobile`
  display: block;
  `}
`

const Body = styled.div`
  position: relative;
`

const ContentBlock = styled.div`
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: black;
  z-index: 2;
  opacity: 0.7;
  display: ${props => props.mobileSideNavVisible ? 'block' : 'none'};
`

const Content = styled.div`
  position: relative;
  margin-left: 300px;
  padding: 50px;
  z-index: 0;
  ${media.mobile`
  margin-left: 0;
  margin-top: 50px;
  min-height: calc( 100vh - 50px );
  padding: 20px;
  `}
  transition: all 0.3s ease;
`

class TemplateWrapper extends React.Component {

  state = {
    mobileSideNavVisible: false,
  }

  toggleMobileSideNavVisible = (e) => {
    e.stopPropagation();
    const { mobileSideNavVisible  } = this.state;
    this.setState({mobileSideNavVisible : !mobileSideNavVisible})
  }

  onClickSideBarItem = (e) => {
    e.stopPropagation();
    this.hideWhenMobileSideNav();
  }

  componentDidMount() {
    window.addEventListener('click', this.hideWhenMobileSideNav )
  }
  componentWillUnmound() {
    window.removeEventListner('click', this.hideWhenMobileSideNav )
  }

  hideWhenMobileSideNav = () => {
    if (this.state.mobileSideNavVisible ) {
      this.setState({ mobileSideNavVisible: false })
    }
  }

  render() {
    const { mobileSideNavVisible } = this.state;
    const { title, image } = this.props.data.site.siteMetadata;
    return (

        <Helmet
          title={title}
          meta={[
            { name: 'description', content: 'holdonnn\'s blog' },
            { name: 'og:description', content: 'holdonnn\'s blog' },
            { name: 'keywords', content: 'blog' },
            { name: 'image', content: image },
            { name: 'og:image', content: image },
          ]}
        />
        <NavigationWrapper>
          <Navigation
            onClickMenu={this.toggleMobileSideNavVisible}
          />
        </NavigationWrapper>

          <SideBar
            onClickSideBarItem={this.onClickSideBarItem}
            mobileSideNavVisible={mobileSideNavVisible}
          />
          <Content mobileSideNavVisible={mobileSideNavVisible}>
            <ContentBlock mobileSideNavVisible={mobileSideNavVisible} />
            {this.props.children()}
          </Content>

    )
  }
}

TemplateWrapper.propTypes = {
  children: PropTypes.func,
}

export default TemplateWrapper

export const query = graphql`
  query LayoutQuery {
    site {
      siteMetadata {
        title
        image
      }
    }
  }
`
<|endoftext|>


<commit_before>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

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

import {baseUrl} from "./matrix-to";

function matrixLinkify(linkify) {
    // Text tokens
    const TT = linkify.scanner.TOKENS;
    // Multi tokens
    const MT = linkify.parser.TOKENS;
    const MultiToken = MT.Base;
    const S_START = linkify.parser.start;

    if (TT.UNDERSCORE === undefined) {
        throw new Error("linkify-matrix requires linkifyjs 2.1.1: this version is too old.");
    }

    const ROOMALIAS = function(value) {
        MultiToken.call(this, value);
        this.type = 'roomalias';
        this.isLink = true;
    };
    ROOMALIAS.prototype = new MultiToken();

    const S_HASH = new linkify.parser.State();
    const S_HASH_NAME = new linkify.parser.State();
    const S_HASH_NAME_COLON = new linkify.parser.State();
    const S_HASH_NAME_COLON_DOMAIN = new linkify.parser.State();
    const S_HASH_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_ROOMALIAS = new linkify.parser.State(ROOMALIAS);

    const roomname_tokens = [
        TT.DOT,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,
        TT.UNDERSCORE,
        TT.POUND,

        // because 'localhost' is tokenised to the localhost token,
        // usernames @localhost:foo.com are otherwise not matched!
        TT.LOCALHOST,
    ];

    S_START.on(TT.POUND, S_HASH);

    S_HASH.on(roomname_tokens, S_HASH_NAME);
    S_HASH_NAME.on(roomname_tokens, S_HASH_NAME);
    S_HASH_NAME.on(TT.DOMAIN, S_HASH_NAME);

    S_HASH_NAME.on(TT.COLON, S_HASH_NAME_COLON);

    S_HASH_NAME_COLON.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
    S_HASH_NAME_COLON.on(TT.LOCALHOST, S_ROOMALIAS); // accept #foo:localhost
    S_HASH_NAME_COLON_DOMAIN.on(TT.DOT, S_HASH_NAME_COLON_DOMAIN_DOT);
    S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
    S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_ROOMALIAS);

    const USERID = function(value) {
        MultiToken.call(this, value);
        this.type = 'userid';
        this.isLink = true;
    };
    USERID.prototype = new MultiToken();

    const S_AT = new linkify.parser.State();
    const S_AT_NAME = new linkify.parser.State();
    const S_AT_NAME_COLON = new linkify.parser.State();
    const S_AT_NAME_COLON_DOMAIN = new linkify.parser.State();
    const S_AT_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_USERID = new linkify.parser.State(USERID);

    const username_tokens = [
        TT.DOT,
        TT.UNDERSCORE,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,

        // as in roomname_tokens
        TT.LOCALHOST,
    ];

    S_START.on(TT.AT, S_AT);

    S_AT.on(username_tokens, S_AT_NAME);
    S_AT_NAME.on(username_tokens, S_AT_NAME);
    S_AT_NAME.on(TT.DOMAIN, S_AT_NAME);

    S_AT_NAME.on(TT.COLON, S_AT_NAME_COLON);

    S_AT_NAME_COLON.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
    S_AT_NAME_COLON.on(TT.LOCALHOST, S_USERID); // accept @foo:localhost
    S_AT_NAME_COLON_DOMAIN.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT);
    S_AT_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
    S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID);

    const GROUPID = function(value) {
        MultiToken.call(this, value);
        this.type = 'groupid';
        this.isLink = true;
    };
    GROUPID.prototype = new MultiToken();

    const S_PLUS = new linkify.parser.State();
    const S_PLUS_NAME = new linkify.parser.State();
    const S_PLUS_NAME_COLON = new linkify.parser.State();
    const S_PLUS_NAME_COLON_DOMAIN = new linkify.parser.State();
    const S_PLUS_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_GROUPID = new linkify.parser.State(GROUPID);

    const groupid_tokens = [
        TT.DOT,
        TT.UNDERSCORE,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,

        // as in roomname_tokens
        TT.LOCALHOST,
    ];

    S_START.on(TT.PLUS, S_PLUS);

    S_PLUS.on(groupid_tokens, S_PLUS_NAME);
    S_PLUS_NAME.on(groupid_tokens, S_PLUS_NAME);
    S_PLUS_NAME.on(TT.DOMAIN, S_PLUS_NAME);

    S_PLUS_NAME.on(TT.COLON, S_PLUS_NAME_COLON);

    S_PLUS_NAME_COLON.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
    S_PLUS_NAME_COLON.on(TT.LOCALHOST, S_GROUPID); // accept +foo:localhost
    S_PLUS_NAME_COLON_DOMAIN.on(TT.DOT, S_PLUS_NAME_COLON_DOMAIN_DOT);
    S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
    S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_GROUPID);
}

// stubs, overwritten in MatrixChat's componentDidMount
matrixLinkify.onUserClick = function(e, userId) { e.preventDefault(); };
matrixLinkify.onAliasClick = function(e, roomAlias) { e.preventDefault(); };
matrixLinkify.onGroupClick = function(e, groupId) { e.preventDefault(); };

const escapeRegExp = function(string) {
    return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};

// Recognise URLs from both our local vector and official vector as vector.
// anyone else really should be using matrix.to.
matrixLinkify.VECTOR_URL_PATTERN = "^(?:https?:\/\/)?(?:"
    + escapeRegExp(window.location.host + window.location.pathname) + "|"
    + "(?:www\\.)?(?:riot|vector)\\.im/(?:app|beta|staging|develop)/"
    + ")(#.*)";

matrixLinkify.MATRIXTO_URL_PATTERN = "^(?:https?:\/\/)?(?:www\\.)?matrix\\.to/#/([#@!+].*)";
matrixLinkify.MATRIXTO_MD_LINK_PATTERN =
    '\\[([^\\]]*)\\]\\((?:https?:\/\/)?(?:www\\.)?matrix\\.to/#/([#@!+][^\\)]*)\\)';
matrixLinkify.MATRIXTO_BASE_URL= baseUrl;

const matrixToEntityMap = {
    '@': '#/user/',
    '#': '#/room/',
    '!': '#/room/',
    '+': '#/group/',
};

matrixLinkify.options = {
    events: function(href, type) {
        switch (type) {
            case "userid":
                return {
                    click: function(e) {
                        matrixLinkify.onUserClick(e, href);
                    },
                };
            case "roomalias":
                return {
                    click: function(e) {
                        matrixLinkify.onAliasClick(e, href);
                    },
                };
            case "groupid":
                return {
                    click: function(e) {
                        matrixLinkify.onGroupClick(e, href);
                    },
                };
        }
    },

    formatHref: function(href, type) {
        switch (type) {
            case 'roomalias':
            case 'userid':
            case 'groupid':
                return matrixLinkify.MATRIXTO_BASE_URL + '/#/' + href;
            default: {
                // FIXME: horrible duplication with HtmlUtils' transform tags
                let m = href.match(matrixLinkify.VECTOR_URL_PATTERN);
                if (m) {
                    return m[1];
                }
                m = href.match(matrixLinkify.MATRIXTO_URL_PATTERN);
                if (m) {
                    const entity = m[1];
                    if (matrixToEntityMap[entity[0]]) return matrixToEntityMap[entity[0]] + entity;
                }

                return href;
            }
        }
    },

    linkAttributes: {
        rel: 'noopener',
    },

    target: function(href, type) {
        if (type === 'url') {
            if (href.match(matrixLinkify.VECTOR_URL_PATTERN) ||
                href.match(matrixLinkify.MATRIXTO_URL_PATTERN)) {
                return null;
            } else {
                return '_blank';
            }
        }
        return null;
    },
};

module.exports = matrixLinkify;
<commit_msg>Fix MATRIXTO_URL_PATTERN RegExp groups<commit_after>/*
Copyright 2015, 2016 OpenMarket Ltd

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

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

import {baseUrl} from "./matrix-to";

function matrixLinkify(linkify) {
    // Text tokens
    const TT = linkify.scanner.TOKENS;
    // Multi tokens
    const MT = linkify.parser.TOKENS;
    const MultiToken = MT.Base;
    const S_START = linkify.parser.start;

    if (TT.UNDERSCORE === undefined) {
        throw new Error("linkify-matrix requires linkifyjs 2.1.1: this version is too old.");
    }

    const ROOMALIAS = function(value) {
        MultiToken.call(this, value);
        this.type = 'roomalias';
        this.isLink = true;
    };
    ROOMALIAS.prototype = new MultiToken();

    const S_HASH = new linkify.parser.State();
    const S_HASH_NAME = new linkify.parser.State();
    const S_HASH_NAME_COLON = new linkify.parser.State();
    const S_HASH_NAME_COLON_DOMAIN = new linkify.parser.State();
    const S_HASH_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_ROOMALIAS = new linkify.parser.State(ROOMALIAS);

    const roomname_tokens = [
        TT.DOT,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,
        TT.UNDERSCORE,
        TT.POUND,

        // because 'localhost' is tokenised to the localhost token,
        // usernames @localhost:foo.com are otherwise not matched!
        TT.LOCALHOST,
    ];

    S_START.on(TT.POUND, S_HASH);

    S_HASH.on(roomname_tokens, S_HASH_NAME);
    S_HASH_NAME.on(roomname_tokens, S_HASH_NAME);
    S_HASH_NAME.on(TT.DOMAIN, S_HASH_NAME);

    S_HASH_NAME.on(TT.COLON, S_HASH_NAME_COLON);

    S_HASH_NAME_COLON.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
    S_HASH_NAME_COLON.on(TT.LOCALHOST, S_ROOMALIAS); // accept #foo:localhost
    S_HASH_NAME_COLON_DOMAIN.on(TT.DOT, S_HASH_NAME_COLON_DOMAIN_DOT);
    S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_HASH_NAME_COLON_DOMAIN);
    S_HASH_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_ROOMALIAS);

    const USERID = function(value) {
        MultiToken.call(this, value);
        this.type = 'userid';
        this.isLink = true;
    };
    USERID.prototype = new MultiToken();

    const S_AT = new linkify.parser.State();
    const S_AT_NAME = new linkify.parser.State();
    const S_AT_NAME_COLON = new linkify.parser.State();
    const S_AT_NAME_COLON_DOMAIN = new linkify.parser.State();
    const S_AT_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_USERID = new linkify.parser.State(USERID);

    const username_tokens = [
        TT.DOT,
        TT.UNDERSCORE,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,

        // as in roomname_tokens
        TT.LOCALHOST,
    ];

    S_START.on(TT.AT, S_AT);

    S_AT.on(username_tokens, S_AT_NAME);
    S_AT_NAME.on(username_tokens, S_AT_NAME);
    S_AT_NAME.on(TT.DOMAIN, S_AT_NAME);

    S_AT_NAME.on(TT.COLON, S_AT_NAME_COLON);

    S_AT_NAME_COLON.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
    S_AT_NAME_COLON.on(TT.LOCALHOST, S_USERID); // accept @foo:localhost
    S_AT_NAME_COLON_DOMAIN.on(TT.DOT, S_AT_NAME_COLON_DOMAIN_DOT);
    S_AT_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_AT_NAME_COLON_DOMAIN);
    S_AT_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_USERID);

    const GROUPID = function(value) {
        MultiToken.call(this, value);
        this.type = 'groupid';
        this.isLink = true;
    };
    GROUPID.prototype = new MultiToken();

    const S_PLUS = new linkify.parser.State();
    const S_PLUS_NAME = new linkify.parser.State();
    const S_PLUS_NAME_COLON = new linkify.parser.State();
    const S_PLUS_NAME_COLON_DOMAIN = new linkify.parser.State();
    const S_PLUS_NAME_COLON_DOMAIN_DOT = new linkify.parser.State();
    const S_GROUPID = new linkify.parser.State(GROUPID);

    const groupid_tokens = [
        TT.DOT,
        TT.UNDERSCORE,
        TT.PLUS,
        TT.NUM,
        TT.DOMAIN,
        TT.TLD,

        // as in roomname_tokens
        TT.LOCALHOST,
    ];

    S_START.on(TT.PLUS, S_PLUS);

    S_PLUS.on(groupid_tokens, S_PLUS_NAME);
    S_PLUS_NAME.on(groupid_tokens, S_PLUS_NAME);
    S_PLUS_NAME.on(TT.DOMAIN, S_PLUS_NAME);

    S_PLUS_NAME.on(TT.COLON, S_PLUS_NAME_COLON);

    S_PLUS_NAME_COLON.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
    S_PLUS_NAME_COLON.on(TT.LOCALHOST, S_GROUPID); // accept +foo:localhost
    S_PLUS_NAME_COLON_DOMAIN.on(TT.DOT, S_PLUS_NAME_COLON_DOMAIN_DOT);
    S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.DOMAIN, S_PLUS_NAME_COLON_DOMAIN);
    S_PLUS_NAME_COLON_DOMAIN_DOT.on(TT.TLD, S_GROUPID);
}

// stubs, overwritten in MatrixChat's componentDidMount
matrixLinkify.onUserClick = function(e, userId) { e.preventDefault(); };
matrixLinkify.onAliasClick = function(e, roomAlias) { e.preventDefault(); };
matrixLinkify.onGroupClick = function(e, groupId) { e.preventDefault(); };

const escapeRegExp = function(string) {
    return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
};

// Recognise URLs from both our local vector and official vector as vector.
// anyone else really should be using matrix.to.
matrixLinkify.VECTOR_URL_PATTERN = "^(?:https?:\/\/)?(?:"
    + escapeRegExp(window.location.host + window.location.pathname) + "|"
    + "(?:www\\.)?(?:riot|vector)\\.im/(?:app|beta|staging|develop)/"
    + ")(#.*)";

matrixLinkify.MATRIXTO_URL_PATTERN = "^(?:https?:\/\/)?(?:www\\.)?matrix\\.to/#/(([#@!+]).*)";
matrixLinkify.MATRIXTO_MD_LINK_PATTERN =
    '\\[([^\\]]*)\\]\\((?:https?:\/\/)?(?:www\\.)?matrix\\.to/#/([#@!+][^\\)]*)\\)';
matrixLinkify.MATRIXTO_BASE_URL= baseUrl;

const matrixToEntityMap = {
    '@': '#/user/',
    '#': '#/room/',
    '!': '#/room/',
    '+': '#/group/',
};

matrixLinkify.options = {
    events: function(href, type) {
        switch (type) {
            case "userid":
                return {
                    click: function(e) {
                        matrixLinkify.onUserClick(e, href);
                    },
                };
            case "roomalias":
                return {
                    click: function(e) {
                        matrixLinkify.onAliasClick(e, href);
                    },
                };
            case "groupid":
                return {
                    click: function(e) {
                        matrixLinkify.onGroupClick(e, href);
                    },
                };
        }
    },

    formatHref: function(href, type) {
        switch (type) {
            case 'roomalias':
            case 'userid':
            case 'groupid':
                return matrixLinkify.MATRIXTO_BASE_URL + '/#/' + href;
            default: {
                // FIXME: horrible duplication with HtmlUtils' transform tags
                let m = href.match(matrixLinkify.VECTOR_URL_PATTERN);
                if (m) {
                    return m[1];
                }
                m = href.match(matrixLinkify.MATRIXTO_URL_PATTERN);
                if (m) {
                    const entity = m[1];
                    if (matrixToEntityMap[entity[0]]) return matrixToEntityMap[entity[0]] + entity;
                }

                return href;
            }
        }
    },

    linkAttributes: {
        rel: 'noopener',
    },

    target: function(href, type) {
        if (type === 'url') {
            if (href.match(matrixLinkify.VECTOR_URL_PATTERN) ||
                href.match(matrixLinkify.MATRIXTO_URL_PATTERN)) {
                return null;
            } else {
                return '_blank';
            }
        }
        return null;
    },
};

module.exports = matrixLinkify;
<|endoftext|>


<commit_before>(function() {
    'use strict';

    angular
        .module('mutant-ng-translate')
        .factory('$translateLoaderSvc', ['$timeout', '$translateLoader', '$translateEvents', translateLoaderSvc]);

    function translateLoaderSvc($timeout, $translateLoader, $translateEvents) {
        var self = this;

        self.config = config;
        self.options = undefined;
        self.storageCallback = undefined;

        self.parts = [];

        self.addParts = addParts;
        self.addPart = addPart;

        self.loadParts = loadParts;
        self.loadPart = loadPart;

        self.sync = {
            counter: {},
            loading: {},
            loaded: {},

            loadingOn: loadingOn,
            loadingOff: loadingOff,
            isLoading: isLoading,
            isLoaded: isLoaded,
            needLoad: needLoad,

            increaseCounter: increaseCounter,
            resetCounter: resetCounter,
            checkCounter: checkCounter
        };

        self.preload = preload;

        return self;

        /* CONFIG */
        function config(options, storageCallback) {
            self.options = options;
            self.storageCallback = storageCallback;

            if (self.options.preload.enabled) {
                $translateEvents.allPartsLoaded.subscribe(self.preload, true);
            }
        }

        /* PARTS */
        function addParts(names, lang) {
            for (var i = 0; i < names.length; i++) {
                self.addPart(names[i], lang);
            }
        }

        function addPart(name, lang) {
            // TODO: check if part with this name already added
            var part = { name: name };
            self.parts.push(part);

            self.loadPart(part, lang);
        }

        function loadParts(lang, force) {
            if (force) {
                self.sync.resetCounter(lang);
            }

            for (var i = 0; i < self.parts.length; i++) {
                if (!force && !self.sync.needLoad(self.parts[i], lang)) continue;

                self.loadPart(self.parts[i], lang);
            }
        }

        function loadPart(part, lang) {
            self.sync.loadingOn(part, lang);

            var partOptions = {
                part: part,
                lang: lang,
                urlTemplate: self.options.urlTemplate,
                dataTransformation: self.options.dataTransformation
            };

            $translateLoader
                .loadPart(partOptions)
                .then(function(values) {
                    self.sync.loadingOff(part, lang);
                    self.sync.increaseCounter(lang);
                    self.sync.checkCounter(lang);

                    self.storageCallback(lang, values);

                    $translateEvents.partLoaded.publish(partOptions);
                });
        }

        /* SYNCHRONIZATION */
        function loadingOn(part, lang) {
            self.sync.loading[lang + '.' + part.name] = true;
        }

        function loadingOff(part, lang) {
            self.sync.loading[lang + '.' + part.name] = false;
            self.sync.loaded[lang + '.' + part.name] = true;
        }

        function isLoading(part, lang) {
            return self.sync.loading[lang + '.' + part.name];
        }

        function isLoaded(part, lang) {
            return self.sync.loaded[lang + '.' + part.name];
        }

        function increaseCounter(lang) {
            if (!self.sync.counter[lang]) self.sync.counter[lang] = 1;
            else self.sync.counter[lang]++;
        }

        function resetCounter(lang) {
            self.sync.counter[lang] = 0;
        }

        function checkCounter(lang) {
            if (self.sync.counter[lang] !== self.parts.length) return;

            $translateEvents.allPartsLoaded.publish({ lang: lang });
        }

        function needLoad(part, lang) {
            return !isLoading(part, lang) && !isLoaded(part, lang);
        }

        /* PRELOAD */
        function preload() {
            if (!self.options.preload.langs) return;

            $timeout(function () {
                for (var i = 0; i < self.options.preload.langs.length; i++) {
                    var lang = self.options.preload.langs[i];

                    self.loadParts(lang);
                }
            }, self.options.preload.delay);
        }
    }
})();<commit_msg>change data format for part loaded event<commit_after>(function() {
    'use strict';

    angular
        .module('mutant-ng-translate')
        .factory('$translateLoaderSvc', ['$timeout', '$translateLoader', '$translateEvents', translateLoaderSvc]);

    function translateLoaderSvc($timeout, $translateLoader, $translateEvents) {
        var self = this;

        self.config = config;
        self.options = undefined;
        self.storageCallback = undefined;

        self.parts = [];

        self.addParts = addParts;
        self.addPart = addPart;

        self.loadParts = loadParts;
        self.loadPart = loadPart;

        self.sync = {
            counter: {},
            loading: {},
            loaded: {},

            loadingOn: loadingOn,
            loadingOff: loadingOff,
            isLoading: isLoading,
            isLoaded: isLoaded,
            needLoad: needLoad,

            increaseCounter: increaseCounter,
            resetCounter: resetCounter,
            checkCounter: checkCounter
        };

        self.preload = preload;

        return self;

        /* CONFIG */
        function config(options, storageCallback) {
            self.options = options;
            self.storageCallback = storageCallback;

            if (self.options.preload.enabled) {
                $translateEvents.allPartsLoaded.subscribe(self.preload, true);
            }
        }

        /* PARTS */
        function addParts(names, lang) {
            for (var i = 0; i < names.length; i++) {
                self.addPart(names[i], lang);
            }
        }

        function addPart(name, lang) {
            // TODO: check if part with this name already added
            var part = { name: name };
            self.parts.push(part);

            self.loadPart(part, lang);
        }

        function loadParts(lang, force) {
            if (force) {
                self.sync.resetCounter(lang);
            }

            for (var i = 0; i < self.parts.length; i++) {
                if (!force && !self.sync.needLoad(self.parts[i], lang)) continue;

                self.loadPart(self.parts[i], lang);
            }
        }

        function loadPart(part, lang) {
            self.sync.loadingOn(part, lang);

            var partOptions = {
                part: part,
                lang: lang,
                urlTemplate: self.options.urlTemplate,
                dataTransformation: self.options.dataTransformation
            };

            $translateLoader
                .loadPart(partOptions)
                .then(function(values) {
                    self.sync.loadingOff(part, lang);
                    self.sync.increaseCounter(lang);
                    self.sync.checkCounter(lang);

                    self.storageCallback(lang, values);

                    $translateEvents.partLoaded.publish({ part: part.name, lang: lang});
                });
        }

        /* SYNCHRONIZATION */
        function loadingOn(part, lang) {
            self.sync.loading[lang + '.' + part.name] = true;
        }

        function loadingOff(part, lang) {
            self.sync.loading[lang + '.' + part.name] = false;
            self.sync.loaded[lang + '.' + part.name] = true;
        }

        function isLoading(part, lang) {
            return self.sync.loading[lang + '.' + part.name];
        }

        function isLoaded(part, lang) {
            return self.sync.loaded[lang + '.' + part.name];
        }

        function increaseCounter(lang) {
            if (!self.sync.counter[lang]) self.sync.counter[lang] = 1;
            else self.sync.counter[lang]++;
        }

        function resetCounter(lang) {
            self.sync.counter[lang] = 0;
        }

        function checkCounter(lang) {
            if (self.sync.counter[lang] !== self.parts.length) return;

            $translateEvents.allPartsLoaded.publish({ lang: lang });
        }

        function needLoad(part, lang) {
            return !isLoading(part, lang) && !isLoaded(part, lang);
        }

        /* PRELOAD */
        function preload() {
            if (!self.options.preload.langs) return;

            $timeout(function () {
                for (var i = 0; i < self.options.preload.langs.length; i++) {
                    var lang = self.options.preload.langs[i];

                    self.loadParts(lang);
                }
            }, self.options.preload.delay);
        }
    }
})();<|endoftext|>


<commit_before>export default {
  el: {
    datepicker: {
      now: 'ตอนนี้',
      today: 'วันนี้',
      cancel: 'ยกเลิก',
      clear: 'ล้างข้อมูล',
      confirm: 'ตกลง',
      selectDate: 'เลือกวันที่',
      selectTime: 'เลือกเวลา',
      startDate: 'วันที่เริ่มต้น',
      startTime: 'เวลาเริ่มต้น',
      endDate: 'วันที่สิ้นสุด',
      endTime: 'เวลาสิ้นสุด',
      year: 'ปี',
      month1: 'มกราคม',
      month2: 'กุมภาพันธ์',
      month3: 'มีนาคม',
      month4: 'เมษายน',
      month5: 'พฤษภาคม',
      month6: 'มิถุนายน',
      month7: 'กรกฎาคม',
      month8: 'สิงหาคม',
      month9: 'กันยายน',
      month10: 'ตุลาคม',
      month11: 'พฤศจิกายน',
      month12: 'ธันวาคม',
      // week: 'week',
      weeks: {
        sun: 'อาทิตย์',
        mon: 'จันทร์',
        tue: 'อังคาร',
        wed: 'พุธ',
        thu: 'พฤหัสบดี',
        fri: 'ศุกร์',
        sat: 'เสาร์'
      },
      months: {
        jan: 'มกรา',
        feb: 'กุมภา',
        mar: 'มีนา',
        apr: 'เมษา',
        may: 'พฤษภา',
        jun: 'มิถุนา',
        jul: 'กรกฎา',
        aug: 'สิงหา',
        sep: 'กันยา',
        oct: 'ตุลา',
        nov: 'พฤศจิกา',
        dec: 'ธันวา'
      }
    },
    select: {
      loading: 'กำลังโหลด',
      noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
      noData: 'ไม่พบข้อมูล',
      placeholder: 'เลือก'
    },
    cascader: {
      noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
      placeholder: 'เลือก'
    },
    pagination: {
      goto: 'ไปที่',
      pagesize: '/หน้า',
      total: 'ทั้งหมด {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'ข้อความ',
      confirm: 'ตกลง',
      cancel: 'ยกเลิก',
      error: 'คุณป้อนข้อมูลไม่ถูกต้อง'
    },
    upload: {
      delete: 'ลบ',
      preview: 'ตัวอย่าง',
      continue: 'ทำต่อ'
    },
    table: {
      emptyText: 'ไม่พบข้อมูล',
      confirmFilter: 'ยืนยัน',
      resetFilter: 'รีเซ็ต',
      clearFilter: 'ทั้งหมด'
    },
    tree: {
      emptyText: 'ไม่พบข้อมูล'
    }
  }
};
<commit_msg>change short date in thai locale<commit_after>export default {
  el: {
    datepicker: {
      now: 'ตอนนี้',
      today: 'วันนี้',
      cancel: 'ยกเลิก',
      clear: 'ล้างข้อมูล',
      confirm: 'ตกลง',
      selectDate: 'เลือกวันที่',
      selectTime: 'เลือกเวลา',
      startDate: 'วันที่เริ่มต้น',
      startTime: 'เวลาเริ่มต้น',
      endDate: 'วันที่สิ้นสุด',
      endTime: 'เวลาสิ้นสุด',
      year: 'ปี',
      month1: 'มกราคม',
      month2: 'กุมภาพันธ์',
      month3: 'มีนาคม',
      month4: 'เมษายน',
      month5: 'พฤษภาคม',
      month6: 'มิถุนายน',
      month7: 'กรกฎาคม',
      month8: 'สิงหาคม',
      month9: 'กันยายน',
      month10: 'ตุลาคม',
      month11: 'พฤศจิกายน',
      month12: 'ธันวาคม',
      // week: 'week',
      weeks: {
        sun: 'อ',
        mon: 'จ',
        tue: 'อ',
        wed: 'พ',
        thu: 'พฤ',
        fri: 'ศ',
        sat: 'ส'
      },
      months: {
        jan: 'มกรา',
        feb: 'กุมภา',
        mar: 'มีนา',
        apr: 'เมษา',
        may: 'พฤษภา',
        jun: 'มิถุนา',
        jul: 'กรกฎา',
        aug: 'สิงหา',
        sep: 'กันยา',
        oct: 'ตุลา',
        nov: 'พฤศจิกา',
        dec: 'ธันวา'
      }
    },
    select: {
      loading: 'กำลังโหลด',
      noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
      noData: 'ไม่พบข้อมูล',
      placeholder: 'เลือก'
    },
    cascader: {
      noMatch: 'ไม่พบข้อมูลที่ตรงกัน',
      placeholder: 'เลือก'
    },
    pagination: {
      goto: 'ไปที่',
      pagesize: '/หน้า',
      total: 'ทั้งหมด {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'ข้อความ',
      confirm: 'ตกลง',
      cancel: 'ยกเลิก',
      error: 'คุณป้อนข้อมูลไม่ถูกต้อง'
    },
    upload: {
      delete: 'ลบ',
      preview: 'ตัวอย่าง',
      continue: 'ทำต่อ'
    },
    table: {
      emptyText: 'ไม่พบข้อมูล',
      confirmFilter: 'ยืนยัน',
      resetFilter: 'รีเซ็ต',
      clearFilter: 'ทั้งหมด'
    },
    tree: {
      emptyText: 'ไม่พบข้อมูล'
    }
  }
};
<|endoftext|>


<commit_before>export default {
  el: {
    colorpicker: {
      confirm: 'OK',
      clear: 'Arassala'
    },
    datepicker: {
      now: 'Ýaňy',
      today: 'Şügün',
      cancel: 'Bes et',
      clear: 'Arassala',
      confirm: 'OK',
      selectDate: 'Güni saýlaň',
      selectTime: 'Wagty saýlaň',
      startDate: 'Başlaýan Güni',
      startTime: 'Başlaýan Wagty',
      endDate: 'Sonky Güni',
      endTime: 'Sonky Wagty',
      year: '',
      month1: 'Ýan',
      month2: 'Few',
      month3: 'Mar',
      month4: 'Apr',
      month5: 'Maý',
      month6: 'Iýn',
      month7: 'Iýl',
      month8: 'Awg',
      month9: 'Sep',
      month10: 'Okt',
      month11: 'Noý',
      month12: 'Dek',
      // week: 'week',
      weeks: {
        sun: 'Ýek',
        mon: 'Duş',
        tue: 'Siş',
        wed: 'Çar',
        thu: 'Pen',
        fri: 'Ann',
        sat: 'Şen'
      },
      months: {
        jan: 'Ýan',
        feb: 'Few',
        mar: 'Mar',
        apr: 'Apr',
        may: 'Maý',
        jun: 'Iýn',
        jul: 'Iýl',
        aug: 'Awg',
        sep: 'Sep',
        oct: 'Okt',
        nov: 'Noý',
        dec: 'Dek'
      }
    },
    select: {
      loading: 'Indirilýär',
      noMatch: 'Hiçzat tapylmady',
      noData: 'Hiçzat ýok',
      placeholder: 'Saýla'
    },
    cascader: {
      noMatch: 'Hiçzat tapylmady',
      loading: 'Indirilýär',
      placeholder: 'saýlaň'
    },
    pagination: {
      goto: 'Git',
      pagesize: '/sahypa',
      total: 'Umumy {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Hat',
      confirm: 'OK',
      cancel: 'Bes et',
      error: 'Ýalňyş girizme'
    },
    upload: {
      delete: 'Poz',
      preview: 'Gör',
      continue: 'Dowam et'
    },
    table: {
      emptyText: 'Maglumat ýok',
      confirmFilter: 'Tassykla',
      resetFilter: 'Arassala',
      clearFilter: 'Hemmesi',
      sumText: 'Sum' // to be translated
    },
    tree: {
      emptyText: 'Maglumat ýok'
    },
    transfer: {
      noMatch: 'Hiçzat tapylmady',
      noData: 'Hiçzat ýok',
      titles: ['List 1', 'List 2'], // to be translated
      filterPlaceholder: 'Enter keyword', // to be translated
      noCheckedFormat: '{total} items', // to be translated
      hasCheckedFormat: '{checked}/{total} checked' // to be translated
    }
  }
};
<commit_msg>Locale: [tk] translated new strings (#5295)<commit_after>export default {
  el: {
    colorpicker: {
      confirm: 'OK',
      clear: 'Arassala'
    },
    datepicker: {
      now: 'Ýaňy',
      today: 'Şügün',
      cancel: 'Bes et',
      clear: 'Arassala',
      confirm: 'OK',
      selectDate: 'Güni saýlaň',
      selectTime: 'Wagty saýlaň',
      startDate: 'Başlaýan Güni',
      startTime: 'Başlaýan Wagty',
      endDate: 'Sonky Güni',
      endTime: 'Sonky Wagty',
      year: '',
      month1: 'Ýan',
      month2: 'Few',
      month3: 'Mar',
      month4: 'Apr',
      month5: 'Maý',
      month6: 'Iýn',
      month7: 'Iýl',
      month8: 'Awg',
      month9: 'Sep',
      month10: 'Okt',
      month11: 'Noý',
      month12: 'Dek',
      // week: 'week',
      weeks: {
        sun: 'Ýek',
        mon: 'Duş',
        tue: 'Siş',
        wed: 'Çar',
        thu: 'Pen',
        fri: 'Ann',
        sat: 'Şen'
      },
      months: {
        jan: 'Ýan',
        feb: 'Few',
        mar: 'Mar',
        apr: 'Apr',
        may: 'Maý',
        jun: 'Iýn',
        jul: 'Iýl',
        aug: 'Awg',
        sep: 'Sep',
        oct: 'Okt',
        nov: 'Noý',
        dec: 'Dek'
      }
    },
    select: {
      loading: 'Indirilýär',
      noMatch: 'Hiçzat tapylmady',
      noData: 'Hiçzat ýok',
      placeholder: 'Saýla'
    },
    cascader: {
      noMatch: 'Hiçzat tapylmady',
      loading: 'Indirilýär',
      placeholder: 'saýlaň'
    },
    pagination: {
      goto: 'Git',
      pagesize: '/sahypa',
      total: 'Umumy {total}',
      pageClassifier: ''
    },
    messagebox: {
      title: 'Hat',
      confirm: 'OK',
      cancel: 'Bes et',
      error: 'Ýalňyş girizme'
    },
    upload: {
      delete: 'Poz',
      preview: 'Gör',
      continue: 'Dowam et'
    },
    table: {
      emptyText: 'Maglumat ýok',
      confirmFilter: 'Tassykla',
      resetFilter: 'Arassala',
      clearFilter: 'Hemmesi',
      sumText: 'Jemi'
    },
    tree: {
      emptyText: 'Maglumat ýok'
    },
    transfer: {
      noMatch: 'Hiçzat tapylmady',
      noData: 'Hiçzat ýok',
      titles: ['Sanaw 1', 'Sanaw 2'],
      filterPlaceholder: 'Gözleg sözlerini giriziň',
      noCheckedFormat: '{total} element',
      hasCheckedFormat: '{checked}/{total} saýlanan'
    }
  }
};
<|endoftext|>


<commit_before>/*
 * Leaflet.locationfilter - leaflet location filter plugin
 * Copyright (C) 2012, Tripbirds.com
 * http://tripbirds.com
 *
 * Licensed under the MIT License.
 *
 * Date: 2012-09-24
 * Version: 0.1
 */
L.LatLngBounds.prototype.modify = function(map, amount) {
    var sw = this.getSouthWest(),
        ne = this.getNorthEast(),
        swPoint = map.latLngToLayerPoint(sw),
        nePoint = map.latLngToLayerPoint(ne);

    sw = map.layerPointToLatLng(new L.Point(swPoint.x-amount, swPoint.y+amount));
    ne = map.layerPointToLatLng(new L.Point(nePoint.x+amount, nePoint.y-amount));

    return new L.LatLngBounds(sw, ne);
};

L.Control.Button = L.Class.extend({
    initialize: function(options) {
        L.Util.setOptions(this, options);
    },

    addTo: function(container) {
        container.addButton(this);
        return this;
    },

    onAdd: function (buttonContainer) {
        this._buttonContainer = buttonContainer;
        this._button = L.DomUtil.create('a', this.options.className, this._buttonContainer.getContainer());
        this._button.href = '#';
        this.setText(this.options.text);

        var that = this;
        this._onClick = function(event) {
            that.options.onClick.call(that, event);
        };

        L.DomEvent
            .on(this._button, 'click', L.DomEvent.stopPropagation)
            .on(this._button, 'mousedown', L.DomEvent.stopPropagation)
            .on(this._button, 'dblclick', L.DomEvent.stopPropagation)
            .on(this._button, 'click', L.DomEvent.preventDefault)
            .on(this._button, 'click', this._onClick, this);
    },

    remove: function() {
        L.DomEvent.off(this._button, "click", this._onClick);
        this._buttonContainer.getContainer().removeChild(this._button);
    },

    setText: function(text) {
        this._button.title = text;
        this._button.innerHTML = text;
    }
});

L.Control.ButtonContainer = L.Control.extend({
    options: {
        position: 'topleft'
    },

    getContainer: function() {
        if (!this._container) {
            this._container = L.DomUtil.create('div', this.options.className);
        }
        return this._container;
    },

    onAdd: function (map) {
        this._map = map;
        return this.getContainer();
    },

    addButton: function(button) {
        button.onAdd(this);
    },

    addClass: function(className) {
        L.DomUtil.addClass(this.getContainer(), className);
    },

    removeClass: function(className) {
        L.DomUtil.removeClass(this.getContainer(), className);
    }
});

L.LocationFilter = L.Class.extend({
    options: {
        enableButton: {
            enableText: "Select area",
            disableText: "Remove selection"
        },
        adjustButton: {
            text: "Select area within current zoom"
        }
    },

    initialize: function(options) {
        L.Util.setOptions(this, options);
    },

    addTo: function(map) {
        map.addLayer(this);
        return this;
    },

    onAdd: function(map) {
        this._map = map;
        this._layer = new L.LayerGroup();
        this._initializeButtonContainer();

        if (this.options.enable) {
            this._enable();
        }
    },

    onRemove: function(map) {
        this._disable();
        this._buttonContainer.removeFrom(map);
    },

    /* Get the current filter bounds */
    getBounds: function() {
        return new L.LatLngBounds(this._sw, this._ne);
    },

    isEnabled: function() {
        return this._enabled;
    },

    /* Draw a rectangle */
    _drawRectangle: function(bounds, options) {
        options = options || {};
        var defaultOptions = {
            stroke: false,
            fill: true,
            fillColor: "black",
            fillOpacity: 0.3,
            clickable: false
        };
        options = L.Util.extend(defaultOptions, options);
        var rect = new L.Rectangle(bounds, options);
        rect.addTo(this._layer);
        return rect;
    },

    /* Draw a draggable marker */
    _drawImageMarker: function(point, options) {
        var marker = new L.Marker(point, {
            icon: new L.DivIcon({
                iconAnchor: options.anchor,
                iconSize: options.size,
                className: options.className
            }),
            draggable: true
        });
        marker.addTo(this._layer);
        return marker;
    },

    /* Draw a move marker. Sets up drag listener that updates the
       filter corners and redraws the filter when the move marker is
       moved */
    _drawMoveMarker: function(point) {
        var that = this;
        this._moveMarker = this._drawImageMarker(point, {
            "className": "location-filter move-marker",
            "anchor": [-10, -10],
            "size": [13,13]
        });
        this._moveMarker.on('drag', function(e) {
            var markerPos = that._moveMarker.getLatLng(),
                latDelta = markerPos.lat-that._nw.lat,
                lngDelta = markerPos.lng-that._nw.lng;
            that._nw = new L.LatLng(that._nw.lat+latDelta, that._nw.lng+lngDelta);
            that._ne = new L.LatLng(that._ne.lat+latDelta, that._ne.lng+lngDelta);
            that._sw = new L.LatLng(that._sw.lat+latDelta, that._sw.lng+lngDelta);
            that._se = new L.LatLng(that._se.lat+latDelta, that._se.lng+lngDelta);
            that._draw();
        });
        this._setupDragendListener(this._moveMarker);
        return this._moveMarker;
    },

    /* Draw a resize marker */
    _drawResizeMarker: function(point, latFollower, lngFollower, otherPos) {
        return this._drawImageMarker(point, {
            "className": "location-filter resize-marker",
            "anchor": [7, 6],
            "size": [13, 12]
        });
    },

    /* Track moving of the given resize marker and update the markers
       given in options.moveAlong to match the position of the moved
       marker. Update filter corners and redraw the filter */
    _setupResizeMarkerTracking: function(marker, options) {
        var that = this;
        marker.on('drag', function(e) {
            var curPosition = marker.getLatLng(),
                latMarker = options.moveAlong.lat,
                lngMarker = options.moveAlong.lng;
            // Move follower markers when this marker is moved
            latMarker.setLatLng(new L.LatLng(curPosition.lat, latMarker.getLatLng().lng));
            lngMarker.setLatLng(new L.LatLng(lngMarker.getLatLng().lat, curPosition.lng));
            // Sort marker positions in nw, ne, sw, se order
            var corners = [that._nwMarker.getLatLng(),
                           that._neMarker.getLatLng(),
                           that._swMarker.getLatLng(),
                           that._seMarker.getLatLng()];
            corners.sort(function(a, b) {
                if (a.lat != b.lat)
                    return b.lat-a.lat;
                else
                    return a.lng-b.lng;
            });
            // Update corner points and redraw everything except the resize markers
            that._nw = corners[0];
            that._ne = corners[1];
            that._sw = corners[2];
            that._se = corners[3];
            that._draw({repositionResizeMarkers: false});
        });
        this._setupDragendListener(marker);
    },

    /* Call the callback (given by name) if it was supplied in options */
    _callCallback: function(callbackName) {
        if (this.options[callbackName]) {
            this.options[callbackName](this.getBounds());
        }
    },

    /* Call the onChange callback whenever dragend is triggered on the
       given marker */
    _setupDragendListener: function(marker) {
        if (this.options.onChange) {
            var that = this;
            marker.on('dragend', function(e) {
                that._callCallback("onChange");
            });
        }
    },

    /* Create bounds for the mask rectangles and the location
       filter rectangle */
    _calculateBounds: function() {
        var mapBounds = this._map.getBounds(),
            outerBounds = new L.LatLngBounds(
                new L.LatLng(mapBounds.getSouthWest().lat-0.1,
                             mapBounds.getSouthWest().lng-0.1),
                new L.LatLng(mapBounds.getNorthEast().lat+0.1,
                             mapBounds.getNorthEast().lng+0.1)
            );

        // The south west and north east points of the mask */
        this._osw = outerBounds.getSouthWest();
        this._one = outerBounds.getNorthEast();

        // Bounds for the mask rectangles
        this._northBounds = new L.LatLngBounds(new L.LatLng(this._ne.lat, this._osw.lng), this._one),
        this._westBounds = new L.LatLngBounds(new L.LatLng(this._sw.lat, this._osw.lng), this._nw),
        this._eastBounds = new L.LatLngBounds(this._se, new L.LatLng(this._ne.lat, this._one.lng)),
        this._southBounds = new L.LatLngBounds(this._osw, new L.LatLng(this._sw.lat, this._one.lng));
    },

    /* Initializes rectangles and markers */
    _initialDraw: function() {
        if (this._initialDrawCalled) {
            return;
        }

        // Calculate filter bounds
        this._calculateBounds();

        // Create rectangles
        this._northRect = this._drawRectangle(this._northBounds);
        this._westRect = this._drawRectangle(this._westBounds);
        this._eastRect = this._drawRectangle(this._eastBounds);
        this._southRect = this._drawRectangle(this._southBounds);
        this._innerRect = this._drawRectangle(this.getBounds(), {
            fillColor: "transparent",
            stroke: true,
            color: "white",
            weight: 1,
            opacity: 0.9
        });

        // Create resize markers
        this._nwMarker = this._drawResizeMarker(this._nw);
        this._neMarker = this._drawResizeMarker(this._ne);
        this._swMarker = this._drawResizeMarker(this._sw);
        this._seMarker = this._drawResizeMarker(this._se);

        // Setup tracking of resize markers. Each marker has pair of
        // follower markers that must be moved whenever the marker is
        // moved. For example, whenever the north west resize marker
        // moves, the south west marker must move along on the x-axis
        // and the north east marker must move on the y axis
        this._setupResizeMarkerTracking(this._nwMarker, {moveAlong: {lat: this._neMarker, lng: this._swMarker}});
        this._setupResizeMarkerTracking(this._neMarker, {moveAlong: {lat: this._nwMarker, lng: this._seMarker}});
        this._setupResizeMarkerTracking(this._swMarker, {moveAlong: {lat: this._seMarker, lng: this._nwMarker}});
        this._setupResizeMarkerTracking(this._seMarker, {moveAlong: {lat: this._swMarker, lng: this._neMarker}});

        // Create move marker
        this._moveMarker = this._drawMoveMarker(this._nw);

        this._initialDrawCalled = true;
    },

    /* Reposition all rectangles and markers to the current filter bounds. */
    _draw: function(options) {
        options = L.Util.extend({repositionResizeMarkers: true}, options);

        // Calculate filter bounds
        this._calculateBounds();

        // Reposition rectangles
        this._northRect.setBounds(this._northBounds);
        this._westRect.setBounds(this._westBounds);
        this._eastRect.setBounds(this._eastBounds);
        this._southRect.setBounds(this._southBounds);
        this._innerRect.setBounds(this.getBounds());

        // Reposition resize markers
        if (options.repositionResizeMarkers) {
            this._nwMarker.setLatLng(this._nw);
            this._neMarker.setLatLng(this._ne);
            this._swMarker.setLatLng(this._sw);
            this._seMarker.setLatLng(this._se);
        }

        // Reposition the move marker
        this._moveMarker.setLatLng(this._nw);
    },

    /* Adjust the location filter to the current map bounds */
    _adjustToMap: function() {
        var mapBounds = this._map.getBounds();

        this._nw = mapBounds.getNorthWest();
        this._ne = mapBounds.getNorthEast();
        this._sw = mapBounds.getSouthWest();
        this._se = mapBounds.getSouthEast();

        this._draw();
        this._map.zoomOut();

        // Call change callback
        this._callCallback("onChange");
    },

    /* Enable the location filter */
    _enable: function() {
        // Initialize corners
        var bounds;
        if (this._sw && this._ne) {
            bounds = new L.LatLngBounds(this._sw, this._ne);
        } else if (this.options.bounds) {
            bounds = this.options.bounds;
        } else {
            bounds = this._map.getBounds();
        }
        this._map.invalidateSize();
        this._nw = bounds.getNorthWest();
        this._ne = bounds.getNorthEast();
        this._sw = bounds.getSouthWest();
        this._se = bounds.getSouthEast();

        // Update buttons
        this._buttonContainer.addClass("enabled");

        if (this._enableButton) {
            this._enableButton.setText(this.options.enableButton.disableText);
        }

        if (this.options.adjustButton) {
            this._createAdjustButton();
        }

        // Draw filter
        this._initialDraw();
        this._draw();

        // Set up map move event listener
        var that = this;
        this._moveHandler = function() {
            that._draw();
        };
        this._map.on("move", this._moveHandler);

        // Add the filter layer to the map
        this._layer.addTo(this._map);

        // Zoom out the map if necessary
        var mapBounds = this._map.getBounds();
        bounds = new L.LatLngBounds(this._sw, this._ne).modify(this._map, 10);
        if (!mapBounds.contains(bounds.getSouthWest()) || !mapBounds.contains(bounds.getNorthEast())) {
            this._map.fitBounds(bounds);
        }

        this._enabled = true;

        // Call the enabled callback
        this._callCallback("onEnabled");
    },

    /* Disable the location filter */
    _disable: function() {
        // Update buttons
        this._buttonContainer.removeClass("enabled");

        if (this._enableButton) {
            this._enableButton.setText(this.options.enableButton.enableText);
        }

        if (this._adjustButton) {
            this._adjustButton.remove();
        }

        // Remove event listener
        this._map.off("move", this._moveHandler);

        // Remove rectangle layer from map
        this._map.removeLayer(this._layer);

        this._enabled = false;

        // Call the disabled callback
        this._callCallback("onDisabled");
    },

    /* Create a button that allows the user to adjust the location
       filter to the current zoom */
    _createAdjustButton: function() {
        var that = this;
        this._adjustButton = new L.Control.Button({
            className: "adjust-button",
            text: this.options.adjustButton.text,

            onClick: function(event) {
                that._adjustToMap();
                that._callCallback("onAdjustToZoomClick");
            }
        }).addTo(this._buttonContainer);
    },

    /* Create the location filter button container and the button that
       toggles the location filter */
    _initializeButtonContainer: function() {
        var that = this;
        this._buttonContainer = new L.Control.ButtonContainer({className: "location-filter button-container"});

        if (this.options.enableButton) {
            this._enableButton = new L.Control.Button({
                className: "enable-button",
                text: this.options.enableButton.enableText,

                onClick: function(event) {
                    if (!that._enabled) {
                        // Enable the location filter
                        that._enable();
                        that._callCallback("onEnableClick");
                    } else {
                        // Disable the location filter
                        that._disable();
                        that._callCallback("onDisableClick");
                    }
                }
            }).addTo(this._buttonContainer);
        }

        this._buttonContainer.addTo(this._map);
    }
});<commit_msg>Make enable/disable public<commit_after>/*
 * Leaflet.locationfilter - leaflet location filter plugin
 * Copyright (C) 2012, Tripbirds.com
 * http://tripbirds.com
 *
 * Licensed under the MIT License.
 *
 * Date: 2012-09-24
 * Version: 0.1
 */
L.LatLngBounds.prototype.modify = function(map, amount) {
    var sw = this.getSouthWest(),
        ne = this.getNorthEast(),
        swPoint = map.latLngToLayerPoint(sw),
        nePoint = map.latLngToLayerPoint(ne);

    sw = map.layerPointToLatLng(new L.Point(swPoint.x-amount, swPoint.y+amount));
    ne = map.layerPointToLatLng(new L.Point(nePoint.x+amount, nePoint.y-amount));

    return new L.LatLngBounds(sw, ne);
};

L.Control.Button = L.Class.extend({
    initialize: function(options) {
        L.Util.setOptions(this, options);
    },

    addTo: function(container) {
        container.addButton(this);
        return this;
    },

    onAdd: function (buttonContainer) {
        this._buttonContainer = buttonContainer;
        this._button = L.DomUtil.create('a', this.options.className, this._buttonContainer.getContainer());
        this._button.href = '#';
        this.setText(this.options.text);

        var that = this;
        this._onClick = function(event) {
            that.options.onClick.call(that, event);
        };

        L.DomEvent
            .on(this._button, 'click', L.DomEvent.stopPropagation)
            .on(this._button, 'mousedown', L.DomEvent.stopPropagation)
            .on(this._button, 'dblclick', L.DomEvent.stopPropagation)
            .on(this._button, 'click', L.DomEvent.preventDefault)
            .on(this._button, 'click', this._onClick, this);
    },

    remove: function() {
        L.DomEvent.off(this._button, "click", this._onClick);
        this._buttonContainer.getContainer().removeChild(this._button);
    },

    setText: function(text) {
        this._button.title = text;
        this._button.innerHTML = text;
    }
});

L.Control.ButtonContainer = L.Control.extend({
    options: {
        position: 'topleft'
    },

    getContainer: function() {
        if (!this._container) {
            this._container = L.DomUtil.create('div', this.options.className);
        }
        return this._container;
    },

    onAdd: function (map) {
        this._map = map;
        return this.getContainer();
    },

    addButton: function(button) {
        button.onAdd(this);
    },

    addClass: function(className) {
        L.DomUtil.addClass(this.getContainer(), className);
    },

    removeClass: function(className) {
        L.DomUtil.removeClass(this.getContainer(), className);
    }
});

L.LocationFilter = L.Class.extend({
    options: {
        enableButton: {
            enableText: "Select area",
            disableText: "Remove selection"
        },
        adjustButton: {
            text: "Select area within current zoom"
        }
    },

    initialize: function(options) {
        L.Util.setOptions(this, options);
    },

    addTo: function(map) {
        map.addLayer(this);
        return this;
    },

    onAdd: function(map) {
        this._map = map;
        this._layer = new L.LayerGroup();
        this._initializeButtonContainer();

        if (this.options.enable) {
            this.enable();
        }
    },

    onRemove: function(map) {
        this.disable();
        this._buttonContainer.removeFrom(map);
    },

    /* Get the current filter bounds */
    getBounds: function() {
        return new L.LatLngBounds(this._sw, this._ne);
    },

    isEnabled: function() {
        return this._enabled;
    },

    /* Draw a rectangle */
    _drawRectangle: function(bounds, options) {
        options = options || {};
        var defaultOptions = {
            stroke: false,
            fill: true,
            fillColor: "black",
            fillOpacity: 0.3,
            clickable: false
        };
        options = L.Util.extend(defaultOptions, options);
        var rect = new L.Rectangle(bounds, options);
        rect.addTo(this._layer);
        return rect;
    },

    /* Draw a draggable marker */
    _drawImageMarker: function(point, options) {
        var marker = new L.Marker(point, {
            icon: new L.DivIcon({
                iconAnchor: options.anchor,
                iconSize: options.size,
                className: options.className
            }),
            draggable: true
        });
        marker.addTo(this._layer);
        return marker;
    },

    /* Draw a move marker. Sets up drag listener that updates the
       filter corners and redraws the filter when the move marker is
       moved */
    _drawMoveMarker: function(point) {
        var that = this;
        this._moveMarker = this._drawImageMarker(point, {
            "className": "location-filter move-marker",
            "anchor": [-10, -10],
            "size": [13,13]
        });
        this._moveMarker.on('drag', function(e) {
            var markerPos = that._moveMarker.getLatLng(),
                latDelta = markerPos.lat-that._nw.lat,
                lngDelta = markerPos.lng-that._nw.lng;
            that._nw = new L.LatLng(that._nw.lat+latDelta, that._nw.lng+lngDelta);
            that._ne = new L.LatLng(that._ne.lat+latDelta, that._ne.lng+lngDelta);
            that._sw = new L.LatLng(that._sw.lat+latDelta, that._sw.lng+lngDelta);
            that._se = new L.LatLng(that._se.lat+latDelta, that._se.lng+lngDelta);
            that._draw();
        });
        this._setupDragendListener(this._moveMarker);
        return this._moveMarker;
    },

    /* Draw a resize marker */
    _drawResizeMarker: function(point, latFollower, lngFollower, otherPos) {
        return this._drawImageMarker(point, {
            "className": "location-filter resize-marker",
            "anchor": [7, 6],
            "size": [13, 12]
        });
    },

    /* Track moving of the given resize marker and update the markers
       given in options.moveAlong to match the position of the moved
       marker. Update filter corners and redraw the filter */
    _setupResizeMarkerTracking: function(marker, options) {
        var that = this;
        marker.on('drag', function(e) {
            var curPosition = marker.getLatLng(),
                latMarker = options.moveAlong.lat,
                lngMarker = options.moveAlong.lng;
            // Move follower markers when this marker is moved
            latMarker.setLatLng(new L.LatLng(curPosition.lat, latMarker.getLatLng().lng));
            lngMarker.setLatLng(new L.LatLng(lngMarker.getLatLng().lat, curPosition.lng));
            // Sort marker positions in nw, ne, sw, se order
            var corners = [that._nwMarker.getLatLng(),
                           that._neMarker.getLatLng(),
                           that._swMarker.getLatLng(),
                           that._seMarker.getLatLng()];
            corners.sort(function(a, b) {
                if (a.lat != b.lat)
                    return b.lat-a.lat;
                else
                    return a.lng-b.lng;
            });
            // Update corner points and redraw everything except the resize markers
            that._nw = corners[0];
            that._ne = corners[1];
            that._sw = corners[2];
            that._se = corners[3];
            that._draw({repositionResizeMarkers: false});
        });
        this._setupDragendListener(marker);
    },

    /* Call the callback (given by name) if it was supplied in options */
    _callCallback: function(callbackName) {
        if (this.options[callbackName]) {
            this.options[callbackName](this.getBounds());
        }
    },

    /* Call the onChange callback whenever dragend is triggered on the
       given marker */
    _setupDragendListener: function(marker) {
        if (this.options.onChange) {
            var that = this;
            marker.on('dragend', function(e) {
                that._callCallback("onChange");
            });
        }
    },

    /* Create bounds for the mask rectangles and the location
       filter rectangle */
    _calculateBounds: function() {
        var mapBounds = this._map.getBounds(),
            outerBounds = new L.LatLngBounds(
                new L.LatLng(mapBounds.getSouthWest().lat-0.1,
                             mapBounds.getSouthWest().lng-0.1),
                new L.LatLng(mapBounds.getNorthEast().lat+0.1,
                             mapBounds.getNorthEast().lng+0.1)
            );

        // The south west and north east points of the mask */
        this._osw = outerBounds.getSouthWest();
        this._one = outerBounds.getNorthEast();

        // Bounds for the mask rectangles
        this._northBounds = new L.LatLngBounds(new L.LatLng(this._ne.lat, this._osw.lng), this._one),
        this._westBounds = new L.LatLngBounds(new L.LatLng(this._sw.lat, this._osw.lng), this._nw),
        this._eastBounds = new L.LatLngBounds(this._se, new L.LatLng(this._ne.lat, this._one.lng)),
        this._southBounds = new L.LatLngBounds(this._osw, new L.LatLng(this._sw.lat, this._one.lng));
    },

    /* Initializes rectangles and markers */
    _initialDraw: function() {
        if (this._initialDrawCalled) {
            return;
        }

        // Calculate filter bounds
        this._calculateBounds();

        // Create rectangles
        this._northRect = this._drawRectangle(this._northBounds);
        this._westRect = this._drawRectangle(this._westBounds);
        this._eastRect = this._drawRectangle(this._eastBounds);
        this._southRect = this._drawRectangle(this._southBounds);
        this._innerRect = this._drawRectangle(this.getBounds(), {
            fillColor: "transparent",
            stroke: true,
            color: "white",
            weight: 1,
            opacity: 0.9
        });

        // Create resize markers
        this._nwMarker = this._drawResizeMarker(this._nw);
        this._neMarker = this._drawResizeMarker(this._ne);
        this._swMarker = this._drawResizeMarker(this._sw);
        this._seMarker = this._drawResizeMarker(this._se);

        // Setup tracking of resize markers. Each marker has pair of
        // follower markers that must be moved whenever the marker is
        // moved. For example, whenever the north west resize marker
        // moves, the south west marker must move along on the x-axis
        // and the north east marker must move on the y axis
        this._setupResizeMarkerTracking(this._nwMarker, {moveAlong: {lat: this._neMarker, lng: this._swMarker}});
        this._setupResizeMarkerTracking(this._neMarker, {moveAlong: {lat: this._nwMarker, lng: this._seMarker}});
        this._setupResizeMarkerTracking(this._swMarker, {moveAlong: {lat: this._seMarker, lng: this._nwMarker}});
        this._setupResizeMarkerTracking(this._seMarker, {moveAlong: {lat: this._swMarker, lng: this._neMarker}});

        // Create move marker
        this._moveMarker = this._drawMoveMarker(this._nw);

        this._initialDrawCalled = true;
    },

    /* Reposition all rectangles and markers to the current filter bounds. */
    _draw: function(options) {
        options = L.Util.extend({repositionResizeMarkers: true}, options);

        // Calculate filter bounds
        this._calculateBounds();

        // Reposition rectangles
        this._northRect.setBounds(this._northBounds);
        this._westRect.setBounds(this._westBounds);
        this._eastRect.setBounds(this._eastBounds);
        this._southRect.setBounds(this._southBounds);
        this._innerRect.setBounds(this.getBounds());

        // Reposition resize markers
        if (options.repositionResizeMarkers) {
            this._nwMarker.setLatLng(this._nw);
            this._neMarker.setLatLng(this._ne);
            this._swMarker.setLatLng(this._sw);
            this._seMarker.setLatLng(this._se);
        }

        // Reposition the move marker
        this._moveMarker.setLatLng(this._nw);
    },

    /* Adjust the location filter to the current map bounds */
    _adjustToMap: function() {
        var mapBounds = this._map.getBounds();

        this._nw = mapBounds.getNorthWest();
        this._ne = mapBounds.getNorthEast();
        this._sw = mapBounds.getSouthWest();
        this._se = mapBounds.getSouthEast();

        this._draw();
        this._map.zoomOut();

        // Call change callback
        this._callCallback("onChange");
    },

    /* Enable the location filter */
    enable: function() {
        if (this._enabled) {
            return;
        }

        // Initialize corners
        var bounds;
        if (this._sw && this._ne) {
            bounds = new L.LatLngBounds(this._sw, this._ne);
        } else if (this.options.bounds) {
            bounds = this.options.bounds;
        } else {
            bounds = this._map.getBounds();
        }
        this._map.invalidateSize();
        this._nw = bounds.getNorthWest();
        this._ne = bounds.getNorthEast();
        this._sw = bounds.getSouthWest();
        this._se = bounds.getSouthEast();

        // Update buttons
        this._buttonContainer.addClass("enabled");

        if (this._enableButton) {
            this._enableButton.setText(this.options.enableButton.disableText);
        }

        if (this.options.adjustButton) {
            this._createAdjustButton();
        }

        // Draw filter
        this._initialDraw();
        this._draw();

        // Set up map move event listener
        var that = this;
        this._moveHandler = function() {
            that._draw();
        };
        this._map.on("move", this._moveHandler);

        // Add the filter layer to the map
        this._layer.addTo(this._map);

        // Zoom out the map if necessary
        var mapBounds = this._map.getBounds();
        bounds = new L.LatLngBounds(this._sw, this._ne).modify(this._map, 10);
        if (!mapBounds.contains(bounds.getSouthWest()) || !mapBounds.contains(bounds.getNorthEast())) {
            this._map.fitBounds(bounds);
        }

        this._enabled = true;

        // Call the enabled callback
        this._callCallback("onEnabled");
    },

    /* Disable the location filter */
    disable: function() {
        if (!this._enabled) {
            return;
        }

        // Update buttons
        this._buttonContainer.removeClass("enabled");

        if (this._enableButton) {
            this._enableButton.setText(this.options.enableButton.enableText);
        }

        if (this._adjustButton) {
            this._adjustButton.remove();
        }

        // Remove event listener
        this._map.off("move", this._moveHandler);

        // Remove rectangle layer from map
        this._map.removeLayer(this._layer);

        this._enabled = false;

        // Call the disabled callback
        this._callCallback("onDisabled");
    },

    /* Create a button that allows the user to adjust the location
       filter to the current zoom */
    _createAdjustButton: function() {
        var that = this;
        this._adjustButton = new L.Control.Button({
            className: "adjust-button",
            text: this.options.adjustButton.text,

            onClick: function(event) {
                that._adjustToMap();
                that._callCallback("onAdjustToZoomClick");
            }
        }).addTo(this._buttonContainer);
    },

    /* Create the location filter button container and the button that
       toggles the location filter */
    _initializeButtonContainer: function() {
        var that = this;
        this._buttonContainer = new L.Control.ButtonContainer({className: "location-filter button-container"});

        if (this.options.enableButton) {
            this._enableButton = new L.Control.Button({
                className: "enable-button",
                text: this.options.enableButton.enableText,

                onClick: function(event) {
                    if (!that._enabled) {
                        // Enable the location filter
                        that.enable();
                        that._callCallback("onEnableClick");
                    } else {
                        // Disable the location filter
                        that.disable();
                        that._callCallback("onDisableClick");
                    }
                }
            }).addTo(this._buttonContainer);
        }

        this._buttonContainer.addTo(this._map);
    }
});<|endoftext|>


<commit_before><commit_msg>Delete spectsworking.js<commit_after><|endoftext|>