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

'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import { MatrixClient } from 'matrix-js-sdk';

import MFileBody from './MFileBody';
import ImageUtils from '../../../ImageUtils';
import Modal from '../../../Modal';
import sdk from '../../../index';
import dis from '../../../dispatcher';
import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile';
import Promise from 'bluebird';
import { _t } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";

export default class extends React.Component {
    displayName: 'MImageBody'

    static propTypes = {
        /* the MatrixEvent to show */
        mxEvent: PropTypes.object.isRequired,

        /* called when the image has loaded */
        onWidgetLoad: PropTypes.func.isRequired,
    }

    static contextTypes = {
        matrixClient: PropTypes.instanceOf(MatrixClient),
    }

    constructor(props) {
        super(props);

        this.onAction = this.onAction.bind(this);
        this.onImageError = this.onImageError.bind(this);
        this.onImageEnter = this.onImageEnter.bind(this);
        this.onImageLeave = this.onImageLeave.bind(this);
        this.onClientSync = this.onClientSync.bind(this);
        this.onClick = this.onClick.bind(this);
        this.fixupHeight = this.fixupHeight.bind(this);
        this._isGif = this._isGif.bind(this);

        this.state = {
            decryptedUrl: null,
            decryptedThumbnailUrl: null,
            decryptedBlob: null,
            error: null,
            imgError: false,
        };
    }

    componentWillMount() {
        this.unmounted = false;
        this.context.matrixClient.on('sync', this.onClientSync);
    }

    onClientSync(syncState, prevState) {
        if (this.unmounted) return;
        // Consider the client reconnected if there is no error with syncing.
        // This means the state could be RECONNECTING, SYNCING or PREPARED.
        const reconnected = syncState !== "ERROR" && prevState !== syncState;
        if (reconnected && this.state.imgError) {
            // Load the image again
            this.setState({
                imgError: false,
            });
        }
    }

    onClick(ev) {
        if (ev.button == 0 && !ev.metaKey) {
            ev.preventDefault();
            const content = this.props.mxEvent.getContent();
            const httpUrl = this._getContentUrl();
            const ImageView = sdk.getComponent("elements.ImageView");
            const params = {
                src: httpUrl,
                name: content.body && content.body.length > 0 ? content.body : _t('Attachment'),
                mxEvent: this.props.mxEvent,
            };

            if (content.info) {
                params.width = content.info.w;
                params.height = content.info.h;
                params.fileSize = content.info.size;
            }

            Modal.createDialog(ImageView, params, "mx_Dialog_lightbox");
        }
    }

    _isGif() {
        const content = this.props.mxEvent.getContent();
        return (
          content &&
          content.info &&
          content.info.mimetype === "image/gif"
        );
    }

    onImageEnter(e) {
        if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
            return;
        }
        const imgElement = e.target;
        imgElement.src = this._getContentUrl();
    }

    onImageLeave(e) {
        if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
            return;
        }
        const imgElement = e.target;
        imgElement.src = this._getThumbUrl();
    }

    onImageError() {
        this.setState({
            imgError: true,
        });
    }

    _getContentUrl() {
        const content = this.props.mxEvent.getContent();
        if (content.file !== undefined) {
            return this.state.decryptedUrl;
        } else {
            return this.context.matrixClient.mxcUrlToHttp(content.url);
        }
    }

    _getThumbUrl() {
        const content = this.props.mxEvent.getContent();
        if (content.file !== undefined) {
            // Don't use the thumbnail for clients wishing to autoplay gifs.
            if (this.state.decryptedThumbnailUrl) {
                return this.state.decryptedThumbnailUrl;
            }
            return this.state.decryptedUrl;
        }
        else if (content.info.mimetype == "image/svg+xml" && content.info.thumbnail_url) {
            // special case to return client-generated thumbnails for SVGs, if any,
            // given we deliberately don't thumbnail them serverside to prevent
            // billion lol attacks and similar
            return this.context.matrixClient.mxcUrlToHttp(
                content.info.thumbnail_url, 800, 600
            );
        }
        else {
            return this.context.matrixClient.mxcUrlToHttp(content.url, 800, 600);
        }
    }

    componentDidMount() {
        this.dispatcherRef = dis.register(this.onAction);
        this.fixupHeight();
        const content = this.props.mxEvent.getContent();
        if (content.file !== undefined && this.state.decryptedUrl === null) {
            let thumbnailPromise = Promise.resolve(null);
            if (content.info.thumbnail_file) {
                thumbnailPromise = decryptFile(
                    content.info.thumbnail_file,
                ).then(function(blob) {
                    return readBlobAsDataUri(blob);
                });
            }
            let decryptedBlob;
            thumbnailPromise.then((thumbnailUrl) => {
                return decryptFile(content.file).then(function(blob) {
                    decryptedBlob = blob;
                    return readBlobAsDataUri(blob);
                }).then((contentUrl) => {
                    this.setState({
                        decryptedUrl: contentUrl,
                        decryptedThumbnailUrl: thumbnailUrl,
                        decryptedBlob: decryptedBlob,
                    });
                    this.props.onWidgetLoad();
                });
            }).catch((err) => {
                console.warn("Unable to decrypt attachment: ", err);
                // Set a placeholder image when we can't decrypt the image.
                this.setState({
                    error: err,
                });
            }).done();
        }
        this._afterComponentDidMount();
    }

    // To be overridden by subclasses (e.g. MStickerBody) for further
    // initialisation after componentDidMount
    _afterComponentDidMount() {
    }

    componentWillUnmount() {
        this.unmounted = true;
        dis.unregister(this.dispatcherRef);
        this.context.matrixClient.removeListener('sync', this.onClientSync);
        this._afterComponentWillUnmount();
    }

    // To be overridden by subclasses (e.g. MStickerBody) for further
    // cleanup after componentWillUnmount
    _afterComponentWillUnmount() {
    }

    onAction(payload) {
        if (payload.action === "timeline_resize") {
            this.fixupHeight();
        }
    }

    fixupHeight() {
        if (!this.refs.image) {
            console.warn(`Refusing to fix up height on ${this.displayName} with no image element`);
            return;
        }

        const content = this.props.mxEvent.getContent();
        const timelineWidth = this.refs.body.offsetWidth;
        const maxHeight = 600; // let images take up as much width as they can so long as the height doesn't exceed 600px.
        // the alternative here would be 600*timelineWidth/800; to scale them down to fit inside a 4:3 bounding box

        // FIXME: this will break on clientside generated thumbnails (as per e2e rooms)
        // which may well be much smaller than the 800x600 bounding box.

        //console.log("trying to fit image into timelineWidth of " + this.refs.body.offsetWidth + " or " + this.refs.body.clientWidth);
        let thumbHeight = null;
        if (content.info) {
            thumbHeight = ImageUtils.thumbHeight(content.info.w, content.info.h, timelineWidth, maxHeight);
        }
        this.refs.image.style.height = thumbHeight + "px";
        // console.log("Image height now", thumbHeight);
    }

    _messageContent(contentUrl, thumbUrl, content) {
        const thumbnail = (

        );

        return (

                { thumbUrl && !this.state.imgError ? thumbnail : '' }
                <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} />

      );
    }

    render() {
        const content = this.props.mxEvent.getContent();

        if (this.state.error !== null) {
            return (

                    { _t("Error decrypting image") }

            );
        }

        if (content.file !== undefined && this.state.decryptedUrl === null) {
            // Need to decrypt the attachment
            // The attachment is decrypted in componentDidMount.
            // For now add an img tag with a spinner.
            return (

            );
        }

        const contentUrl = this._getContentUrl();
        let thumbUrl;
        if (this._isGif() && SettingsStore.getValue("autoplayGifsAndVideos")) {
          thumbUrl = contentUrl;
        } else {
          thumbUrl = this._getThumbUrl();
        }

        return this._messageContent(contentUrl, thumbUrl, content);
    }
}
<commit_msg>clarify another scrolljump bug<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.
*/

'use strict';

import React from 'react';
import PropTypes from 'prop-types';
import { MatrixClient } from 'matrix-js-sdk';

import MFileBody from './MFileBody';
import ImageUtils from '../../../ImageUtils';
import Modal from '../../../Modal';
import sdk from '../../../index';
import dis from '../../../dispatcher';
import { decryptFile, readBlobAsDataUri } from '../../../utils/DecryptFile';
import Promise from 'bluebird';
import { _t } from '../../../languageHandler';
import SettingsStore from "../../../settings/SettingsStore";

export default class extends React.Component {
    displayName: 'MImageBody'

    static propTypes = {
        /* the MatrixEvent to show */
        mxEvent: PropTypes.object.isRequired,

        /* called when the image has loaded */
        onWidgetLoad: PropTypes.func.isRequired,
    }

    static contextTypes = {
        matrixClient: PropTypes.instanceOf(MatrixClient),
    }

    constructor(props) {
        super(props);

        this.onAction = this.onAction.bind(this);
        this.onImageError = this.onImageError.bind(this);
        this.onImageEnter = this.onImageEnter.bind(this);
        this.onImageLeave = this.onImageLeave.bind(this);
        this.onClientSync = this.onClientSync.bind(this);
        this.onClick = this.onClick.bind(this);
        this.fixupHeight = this.fixupHeight.bind(this);
        this._isGif = this._isGif.bind(this);

        this.state = {
            decryptedUrl: null,
            decryptedThumbnailUrl: null,
            decryptedBlob: null,
            error: null,
            imgError: false,
        };
    }

    componentWillMount() {
        this.unmounted = false;
        this.context.matrixClient.on('sync', this.onClientSync);
    }

    onClientSync(syncState, prevState) {
        if (this.unmounted) return;
        // Consider the client reconnected if there is no error with syncing.
        // This means the state could be RECONNECTING, SYNCING or PREPARED.
        const reconnected = syncState !== "ERROR" && prevState !== syncState;
        if (reconnected && this.state.imgError) {
            // Load the image again
            this.setState({
                imgError: false,
            });
        }
    }

    onClick(ev) {
        if (ev.button == 0 && !ev.metaKey) {
            ev.preventDefault();
            const content = this.props.mxEvent.getContent();
            const httpUrl = this._getContentUrl();
            const ImageView = sdk.getComponent("elements.ImageView");
            const params = {
                src: httpUrl,
                name: content.body && content.body.length > 0 ? content.body : _t('Attachment'),
                mxEvent: this.props.mxEvent,
            };

            if (content.info) {
                params.width = content.info.w;
                params.height = content.info.h;
                params.fileSize = content.info.size;
            }

            Modal.createDialog(ImageView, params, "mx_Dialog_lightbox");
        }
    }

    _isGif() {
        const content = this.props.mxEvent.getContent();
        return (
          content &&
          content.info &&
          content.info.mimetype === "image/gif"
        );
    }

    onImageEnter(e) {
        if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
            return;
        }
        const imgElement = e.target;
        imgElement.src = this._getContentUrl();
    }

    onImageLeave(e) {
        if (!this._isGif() || SettingsStore.getValue("autoplayGifsAndVideos")) {
            return;
        }
        const imgElement = e.target;
        imgElement.src = this._getThumbUrl();
    }

    onImageError() {
        this.setState({
            imgError: true,
        });
    }

    _getContentUrl() {
        const content = this.props.mxEvent.getContent();
        if (content.file !== undefined) {
            return this.state.decryptedUrl;
        } else {
            return this.context.matrixClient.mxcUrlToHttp(content.url);
        }
    }

    _getThumbUrl() {
        const content = this.props.mxEvent.getContent();
        if (content.file !== undefined) {
            // Don't use the thumbnail for clients wishing to autoplay gifs.
            if (this.state.decryptedThumbnailUrl) {
                return this.state.decryptedThumbnailUrl;
            }
            return this.state.decryptedUrl;
        }
        else if (content.info.mimetype == "image/svg+xml" && content.info.thumbnail_url) {
            // special case to return client-generated thumbnails for SVGs, if any,
            // given we deliberately don't thumbnail them serverside to prevent
            // billion lol attacks and similar
            return this.context.matrixClient.mxcUrlToHttp(
                content.info.thumbnail_url, 800, 600
            );
        }
        else {
            return this.context.matrixClient.mxcUrlToHttp(content.url, 800, 600);
        }
    }

    componentDidMount() {
        this.dispatcherRef = dis.register(this.onAction);
        this.fixupHeight();
        const content = this.props.mxEvent.getContent();
        if (content.file !== undefined && this.state.decryptedUrl === null) {
            let thumbnailPromise = Promise.resolve(null);
            if (content.info.thumbnail_file) {
                thumbnailPromise = decryptFile(
                    content.info.thumbnail_file,
                ).then(function(blob) {
                    return readBlobAsDataUri(blob);
                });
            }
            let decryptedBlob;
            thumbnailPromise.then((thumbnailUrl) => {
                return decryptFile(content.file).then(function(blob) {
                    decryptedBlob = blob;
                    return readBlobAsDataUri(blob);
                }).then((contentUrl) => {
                    this.setState({
                        decryptedUrl: contentUrl,
                        decryptedThumbnailUrl: thumbnailUrl,
                        decryptedBlob: decryptedBlob,
                    });
                    this.props.onWidgetLoad();
                });
            }).catch((err) => {
                console.warn("Unable to decrypt attachment: ", err);
                // Set a placeholder image when we can't decrypt the image.
                this.setState({
                    error: err,
                });
            }).done();
        }
        this._afterComponentDidMount();
    }

    // To be overridden by subclasses (e.g. MStickerBody) for further
    // initialisation after componentDidMount
    _afterComponentDidMount() {
    }

    componentWillUnmount() {
        this.unmounted = true;
        dis.unregister(this.dispatcherRef);
        this.context.matrixClient.removeListener('sync', this.onClientSync);
        this._afterComponentWillUnmount();
    }

    // To be overridden by subclasses (e.g. MStickerBody) for further
    // cleanup after componentWillUnmount
    _afterComponentWillUnmount() {
    }

    onAction(payload) {
        if (payload.action === "timeline_resize") {
            this.fixupHeight();
        }
    }

    fixupHeight() {
        if (!this.refs.image) {
            console.warn(`Refusing to fix up height on ${this.displayName} with no image element`);
            return;
        }

        const content = this.props.mxEvent.getContent();
        const timelineWidth = this.refs.body.offsetWidth;
        const maxHeight = 600; // let images take up as much width as they can so long as the height doesn't exceed 600px.
        // the alternative here would be 600*timelineWidth/800; to scale them down to fit inside a 4:3 bounding box

        // FIXME: this will break on clientside generated thumbnails (as per e2e rooms)
        // which may well be much smaller than the 800x600 bounding box.

        // FIXME: It will also break really badly for images with broken or missing thumbnails

        //console.log("trying to fit image into timelineWidth of " + this.refs.body.offsetWidth + " or " + this.refs.body.clientWidth);
        let thumbHeight = null;
        if (content.info) {
            thumbHeight = ImageUtils.thumbHeight(content.info.w, content.info.h, timelineWidth, maxHeight);
        }
        this.refs.image.style.height = thumbHeight + "px";
        // console.log("Image height now", thumbHeight);
    }

    _messageContent(contentUrl, thumbUrl, content) {
        const thumbnail = (

        );

        return (

                { thumbUrl && !this.state.imgError ? thumbnail : '' }
                <MFileBody {...this.props} decryptedBlob={this.state.decryptedBlob} />

      );
    }

    render() {
        const content = this.props.mxEvent.getContent();

        if (this.state.error !== null) {
            return (

                    { _t("Error decrypting image") }

            );
        }

        if (content.file !== undefined && this.state.decryptedUrl === null) {
            // Need to decrypt the attachment
            // The attachment is decrypted in componentDidMount.
            // For now add an img tag with a spinner.
            return (

            );
        }

        const contentUrl = this._getContentUrl();
        let thumbUrl;
        if (this._isGif() && SettingsStore.getValue("autoplayGifsAndVideos")) {
          thumbUrl = contentUrl;
        } else {
          thumbUrl = this._getThumbUrl();
        }

        return this._messageContent(contentUrl, thumbUrl, content);
    }
}
<|endoftext|>


<commit_before>import {
  checkRendering,
  getRefinements,
  clearRefinementsFromState,
  clearRefinementsAndSearch,
} from '../../lib/utils.js';

const usage = `Usage:
var customClearAll = connectClearAll(function render(params, isFirstRendering) {
  // params = {
  //   refine,
  //   hasRefinements,
  //   createURL,
  //   instantSearchInstance,
  //   widgetParams,
  // }
});
search.addWidget(
  customClearAll({
    [ excludeAttributes = [] ],
    [ clearsQuery = false ]
  })
);
Full documentation available at https://community.algolia.com/instantsearch.js/connectors/connectClearAll.html
`;

const refine = ({helper, clearAttributes, hasRefinements, clearsQuery}) => () => {
  if (hasRefinements) {
    clearRefinementsAndSearch(helper, clearAttributes, clearsQuery);
  }
};

/**
 * @typedef {Object} CustomClearAllWidgetOptions
 * @property {string[]} excludeAttributes Every attributes that should not be removed when calling `refine()`.
 * @property {boolean} clearsQuery Should calling `refine()` also clears the active search query.
 */

/**
 * @typedef {Object} ClearAllRenderingOptions
 * @property {function} refine Trigger the clear of all the currently refined values.
 * @property {boolean} hasRefinements Indicate if search state is refined.
 * @property {function} createURL Create a url for the next state when refinements are cleared.
 * @property {InstantSearch} instantSearchInstance Instance of instantsearch on which the widget is attached.
 * @property {Object} widgetParams All original `CustomClearAllWidgetOptions` forwarded to the `renderFn`.
 */

/**
 * **ClearAll** connector provides the logic to build a custom widget that will give the user the ability to reset the search state.
 * This connector provides a `ClearAllRenderingOptions.refine()` function to remove the current refined facets.
 * @type {Connector}
 * @param {function(ClearAllRenderingOptions, boolean)} renderFn Rendering function for the custom **ClearAll** widget.
 * @return {function(CustomClearAllWidgetOptions)} Re-usable widget factory for a custom **ClearAll** widget.
 * @example
 * var $ = window.$;
 * var instantsearch = window.instantsearch;
 *
 * // custom `renderFn` to render the custom ClearAll widget
 * function renderFn(ClearAllRenderingOptions) {
 *   if (ClearAllRenderingOptions.isFirstRendering === true) {
 *     var markup = $('<button id="custom-clear-all">Clear All</button>');
 *     containerNode.append(markup);
 *
 *     markup.on('click', function(event) {
 *       event.preventDefault();
 *       ClearAllRenderingOptions.refine();
 *     })
 *   }
 *
 *   var clearAllCTA = containerNode.find('#custom-clear-all');
 *   clearAllCTA.attr('disabled', !ClearAllRenderingOptions.hasRefinements)
 * };
 *
 * // connect `renderFn` to ClearAll logic
 * var customClearAllWidget = instantsearch.connectors.connectClearAll(renderFn);
 *
 * // mount widget on the page
 * search.addWidget(
 *   customClearAllWidget({
 *     containerNode: $('#custom-clear-all-container'),
 *   })
 * );
 */
export default function connectClearAll(renderFn) {
  checkRendering(renderFn, usage);

  return (widgetParams = {}) => {
    const {excludeAttributes = [], clearsQuery = false} = widgetParams;

    return {
      // Provide the same function to the `renderFn` so that way the user
      // has to only bind it once when `isFirstRendering` for instance
      _refine() {},
      _cachedRefine() { this._refine(); },

      init({helper, instantSearchInstance, createURL}) {
        this._cachedRefine = this._cachedRefine.bind(this);

        const clearAttributes = getRefinements({}, helper.state)
          .map(one => one.attributeName)
          .filter(one => excludeAttributes.indexOf(one) === -1);

        const hasRefinements = clearAttributes.length !== 0;
        const preparedCreateURL = () => createURL(clearRefinementsFromState(helper.state, [], clearsQuery));

        this._refine = refine({helper, clearAttributes, hasRefinements, clearsQuery});

        renderFn({
          refine: this._cachedRefine,
          hasRefinements,
          createURL: preparedCreateURL,
          instantSearchInstance,
          widgetParams,
        }, true);
      },

      render({results, state, createURL, helper, instantSearchInstance}) {
        const clearAttributes = getRefinements(results, state)
          .map(one => one.attributeName)
          .filter(one => excludeAttributes.indexOf(one) === -1);

        const hasRefinements = clearAttributes.length !== 0;
        const preparedCreateURL = () => createURL(clearRefinementsFromState(state, [], clearsQuery));

        this._refine = refine({helper, clearAttributes, hasRefinements, clearsQuery});

        renderFn({
          refine: this._cachedRefine,
          hasRefinements,
          createURL: preparedCreateURL,
          instantSearchInstance,
          widgetParams,
        }, false);
      },
    };
  };
}
<commit_msg>doc(connectClearAll): fix example<commit_after>import {
  checkRendering,
  getRefinements,
  clearRefinementsFromState,
  clearRefinementsAndSearch,
} from '../../lib/utils.js';

const usage = `Usage:
var customClearAll = connectClearAll(function render(params, isFirstRendering) {
  // params = {
  //   refine,
  //   hasRefinements,
  //   createURL,
  //   instantSearchInstance,
  //   widgetParams,
  // }
});
search.addWidget(
  customClearAll({
    [ excludeAttributes = [] ],
    [ clearsQuery = false ]
  })
);
Full documentation available at https://community.algolia.com/instantsearch.js/connectors/connectClearAll.html
`;

const refine = ({helper, clearAttributes, hasRefinements, clearsQuery}) => () => {
  if (hasRefinements) {
    clearRefinementsAndSearch(helper, clearAttributes, clearsQuery);
  }
};

/**
 * @typedef {Object} CustomClearAllWidgetOptions
 * @property {string[]} excludeAttributes Every attributes that should not be removed when calling `refine()`.
 * @property {boolean} clearsQuery Should calling `refine()` also clears the active search query.
 */

/**
 * @typedef {Object} ClearAllRenderingOptions
 * @property {function} refine Trigger the clear of all the currently refined values.
 * @property {boolean} hasRefinements Indicate if search state is refined.
 * @property {function} createURL Create a url for the next state when refinements are cleared.
 * @property {InstantSearch} instantSearchInstance Instance of instantsearch on which the widget is attached.
 * @property {Object} widgetParams All original `CustomClearAllWidgetOptions` forwarded to the `renderFn`.
 */

/**
 * **ClearAll** connector provides the logic to build a custom widget that will give the user the ability to reset the search state.
 * This connector provides a `ClearAllRenderingOptions.refine()` function to remove the current refined facets.
 * @type {Connector}
 * @param {function(ClearAllRenderingOptions, boolean)} renderFn Rendering function for the custom **ClearAll** widget.
 * @return {function(CustomClearAllWidgetOptions)} Re-usable widget factory for a custom **ClearAll** widget.
 * @example
 * var $ = window.$;
 * var instantsearch = window.instantsearch;
 *
 * // custom `renderFn` to render the custom ClearAll widget
 * function renderFn(ClearAllRenderingOptions, isFirstRendering) {
 *   if (isFirstRendering === true) {
 *     var markup = $('<button id="custom-clear-all">Clear All</button>');
 *     ClearAllRenderingOptions.widgetParams.containerNode.append(markup);
 *
 *     markup.on('click', function(event) {
 *       event.preventDefault();
 *       ClearAllRenderingOptions.refine();
 *     })
 *   }
 *
 *   var clearAllCTA = ClearAllRenderingOptions.widgetParams.containerNode.find('#custom-clear-all');
 *   clearAllCTA.attr('disabled', !ClearAllRenderingOptions.hasRefinements)
 * };
 *
 * // connect `renderFn` to ClearAll logic
 * var customClearAllWidget = instantsearch.connectors.connectClearAll(renderFn);
 *
 * // mount widget on the page
 * search.addWidget(
 *   customClearAllWidget({
 *     containerNode: $('#custom-clear-all-container'),
 *   })
 * );
 */
export default function connectClearAll(renderFn) {
  checkRendering(renderFn, usage);

  return (widgetParams = {}) => {
    const {excludeAttributes = [], clearsQuery = false} = widgetParams;

    return {
      // Provide the same function to the `renderFn` so that way the user
      // has to only bind it once when `isFirstRendering` for instance
      _refine() {},
      _cachedRefine() { this._refine(); },

      init({helper, instantSearchInstance, createURL}) {
        this._cachedRefine = this._cachedRefine.bind(this);

        const clearAttributes = getRefinements({}, helper.state)
          .map(one => one.attributeName)
          .filter(one => excludeAttributes.indexOf(one) === -1);

        const hasRefinements = clearAttributes.length !== 0;
        const preparedCreateURL = () => createURL(clearRefinementsFromState(helper.state, [], clearsQuery));

        this._refine = refine({helper, clearAttributes, hasRefinements, clearsQuery});

        renderFn({
          refine: this._cachedRefine,
          hasRefinements,
          createURL: preparedCreateURL,
          instantSearchInstance,
          widgetParams,
        }, true);
      },

      render({results, state, createURL, helper, instantSearchInstance}) {
        const clearAttributes = getRefinements(results, state)
          .map(one => one.attributeName)
          .filter(one => excludeAttributes.indexOf(one) === -1);

        const hasRefinements = clearAttributes.length !== 0;
        const preparedCreateURL = () => createURL(clearRefinementsFromState(state, [], clearsQuery));

        this._refine = refine({helper, clearAttributes, hasRefinements, clearsQuery});

        renderFn({
          refine: this._cachedRefine,
          hasRefinements,
          createURL: preparedCreateURL,
          instantSearchInstance,
          widgetParams,
        }, false);
      },
    };
  };
}
<|endoftext|>


<commit_before>import React from 'react';
import LayoutWrapper from '../../../../components/utility/layoutWrapper';
import Box from '../../../../components/utility/box';
import { Select, DatePicker } from 'antd';
import InputBox from './input-box';
import IntlMessages from '../../../../components/utility/intlMessages';
import campaignActions from '../../../../redux/campaign/actions';
import { connect } from 'react-redux';

const {
  createCampaign
} = campaignActions;

const Option = Select.Option;

const missing_people = [
  { id: 1, name: "Melisa", dni: "35.675.123" },
  { id: 2, name: "María", dni: "28.425.029" },
  { id: 3, name: "Juana", dni: "28.321.456" }
]

class NewCampaign extends React.Component {

  constructor(props) {
    super(props);
    this.state = { missing_people: missing_people };
  }

  renderMissingPersonOptions = () => {
    return (
      this.state.missing_people.map(m => <Option key={m.id} value={`${m.name} (${m.dni})`}>{`${m.name} (${m.dni})`}</Option>)
    )
  }

  render() {
    return (
      <LayoutWrapper className="isoCheckoutPage">
        <Box>

Alta de campaña

                  <InputBox
                    label={<IntlMessages id="admin.campaign.new.title" />}
                    placeholder="Título de campaña"
                    important
                  />

                  <InputBox
                    label={<IntlMessages id="admin.campaign.new.description" />}
                    placeholder="Descripción de campaña"
                    important
                  />

Fecha de expiración

                  <DatePicker placeholder="Fecha de expiración" />

Persona perdida

                <Select
                  mode="combobox"
                  placeholder="DNI de persona perdida"
                  notFoundContent="No hay resultados"
                  defaultActiveFirstOption={false}
                  showArrow={false}
                  filterOption={false}
                >
                  { this.renderMissingPersonOptions() }
                </Select>

        </Box>
      </LayoutWrapper>
    );
  }
}

function mapStateToProps(state) {
  const { campaigns } = state.Campaign;
  return {
    campaigns: campaigns
  };
}

export default connect(mapStateToProps, { createCampaign })(NewCampaign);<commit_msg>A few improvements in new campaigns view<commit_after>import React from 'react';
import LayoutWrapper from '../../../../components/utility/layoutWrapper';
import Box from '../../../../components/utility/box';
import { Button, Select, DatePicker } from 'antd';
import InputBox from './input-box';
import IntlMessages from '../../../../components/utility/intlMessages';
import campaignActions from '../../../../redux/campaign/actions';
import { connect } from 'react-redux';

const {
  createCampaign
} = campaignActions;

const Option = Select.Option;

const missing_people = [
  { id: 1, name: "Melisa", dni: "35.675.123" },
  { id: 2, name: "María", dni: "28.425.029" },
  { id: 3, name: "Juana", dni: "28.321.456" }
]

class NewCampaign extends React.Component {

  constructor(props) {
    super(props);
    this.state = { missing_people: missing_people };
  }

  renderMissingPersonOptions = () => {
    return (
      this.state.missing_people.map(m => <Option key={m.id} value={`${m.name} (${m.dni})`}>{`${m.name} (${m.dni})`}</Option>)
    )
  }

  render() {
    return (
      <LayoutWrapper className="isoCheckoutPage">
        <Box>

Alta de campaña

                  <InputBox
                    label={<IntlMessages id="admin.campaign.new.title" />}
                    placeholder="Título de campaña"
                  />

                  <InputBox
                    label={<IntlMessages id="admin.campaign.new.description" />}
                    placeholder="Descripción de campaña"
                  />

Fecha de expiración

                  <DatePicker placeholder="Fecha de expiración" />

Persona perdida

                <Select
                  mode="combobox"
                  placeholder="DNI de persona perdida"
                  notFoundContent="No hay resultados"
                  defaultActiveFirstOption={false}
                  showArrow={false}
                  filterOption={false}
                >
                  { this.renderMissingPersonOptions() }
                </Select>

                <Button type="primary" size="small">Guardar</Button>
                <Button type="danger" size="small">Cancelar</Button>

        </Box>
      </LayoutWrapper>
    );
  }
}

function mapStateToProps(state) {
  const { campaigns } = state.Campaign;
  return {
    campaigns: campaigns
  };
}

export default connect(mapStateToProps, { createCampaign })(NewCampaign);<|endoftext|>


<commit_before>/*jslint nomen: true, vars: true */
/*global interstate,esprima,able,uid,console */

(function (ist) {
    "use strict";
    var cjs = ist.cjs,
        _ = ist._;
	ist.CommandStack = function () {
        var stack = [];
        var index = -1; // Points at the next thing to undo

		this._do = function(command) {
			command._do();

			var discarded_commands = stack.splice(index + 1, stack.length - index);

			_.forEach(discarded_commands, function (discarded_command) {
				if (cjs.isConstraint(discarded_command)) {
					discarded_command.destroy();
				}
			});

			if(command.is_undoable()) {
				stack.push(command);
				index += 1;
			}
			cjs.wait();
			this.$undo_description.invalidate();
			this.$redo_description.invalidate();
			cjs.signal();
		};

		this._undo = function() {
			if (this.can_undo()) {
				var last_command = stack[index];
				last_command._undo();
				index -= 1;

				cjs.wait();
				this.$undo_description.invalidate();
				this.$redo_description.invalidate();
				cjs.signal();
			}
		};

		this._redo = function() {
			if (this.can_redo()) {
				var last_command = stack[index + 1];
				last_command._do();
				index += 1;

				cjs.wait();
				this.$undo_description.invalidate();
				this.$redo_description.invalidate();
				cjs.signal();
			}
		};

		this.can_undo = function() {
			return index >= 0;
		};

		this.can_redo = function() {
			return index < stack.length - 1;
		};

		this.get_undo_description = function() {
			if(this.can_undo()) {
				var last_command = stack[index];
				return last_command.to_undo_string();
			} else {
				return false;
			}
		};

		this.get_redo_description = function() {
			if(this.can_redo()) {
				var last_command = stack[index + 1];
				return last_command.to_redo_string();
			} else {
				return false;
			}
		};

		this.$undo_description = cjs(this.get_undo_description, {context: this});
		this.$redo_description = cjs(this.get_redo_description, {context: this});

		this.clear = function() {
			for(var i = 0; i<stack.length; i++) {
				stack[i].destroy();
			}
			stack = [];
			index = -1;

			cjs.wait();
			this.$undo_description.invalidate();
			this.$redo_description.invalidate();
			cjs.signal();
		};

		this.destroy = function() {
			this.clear();
		};
	};
}(interstate));
<commit_msg>Added option for transient commands<commit_after>/*jslint nomen: true, vars: true */
/*global interstate,esprima,able,uid,console */

(function (ist) {
    "use strict";
    var cjs = ist.cjs,
        _ = ist._;
	ist.CommandStack = function () {
        var stack = [],
			index = -1, // Points at the next thing to undo
			transient_stack = [];

		var _add_to_stack = function(command) {
			var discarded_commands = stack.splice(index + 1, stack.length - index);

			_.forEach(discarded_commands, function (discarded_command) {
				if (cjs.isConstraint(discarded_command)) {
					discarded_command.destroy();
				}
			});

			if(command.is_undoable()) {
				stack.push(command);
				index += 1;
			}
			cjs.wait();
			this.$undo_description.invalidate();
			this.$redo_description.invalidate();
			cjs.signal();
		};

		this.complete_transient = function() {
			var combined_command = new ist.CombinedCommand({commands: transient_stack});
			_add_to_stack(combined_command);
			transient_stack = [];
		};

		this._do = function(command, transient) {
			command._do();

			if(transient) {
				transient_stack.push(command);
			} else {
				_add_to_stack(command);
			}
		};

		this._undo = function() {
			if (this.can_undo()) {
				var last_command = stack[index];
				last_command._undo();
				index -= 1;

				cjs.wait();
				this.$undo_description.invalidate();
				this.$redo_description.invalidate();
				cjs.signal();
			}
		};

		this._redo = function() {
			if (this.can_redo()) {
				var last_command = stack[index + 1];
				last_command._do();
				index += 1;

				cjs.wait();
				this.$undo_description.invalidate();
				this.$redo_description.invalidate();
				cjs.signal();
			}
		};

		this.can_undo = function() {
			return index >= 0;
		};

		this.can_redo = function() {
			return index < stack.length - 1;
		};

		this.get_undo_description = function() {
			if(this.can_undo()) {
				var last_command = stack[index];
				return last_command.to_undo_string();
			} else {
				return false;
			}
		};

		this.get_redo_description = function() {
			if(this.can_redo()) {
				var last_command = stack[index + 1];
				return last_command.to_redo_string();
			} else {
				return false;
			}
		};

		this.$undo_description = cjs(this.get_undo_description, {context: this});
		this.$redo_description = cjs(this.get_redo_description, {context: this});

		this.clear = function() {
			for(var i = 0; i<stack.length; i++) {
				stack[i].destroy();
			}
			stack = [];
			index = -1;

			cjs.wait();
			this.$undo_description.invalidate();
			this.$redo_description.invalidate();
			cjs.signal();
		};

		this.destroy = function() {
			this.clear();
		};
	};
}(interstate));
<|endoftext|>


<commit_before>/**
 * Created by AlexanderC on 6/16/15.
 */

'use strict';

import {AbstractDriver} from './AbstractDriver';

/**
 * In memory driver implementation
 */
export class InMemoryDriver extends AbstractDriver {
  constructor() {
    super();

    this._storage = {};
  }

  /**
   * @returns {Object}
   */
  get storage() {
    return this._storage;
  }

  /**
   * @param {String} key
   * @param {Function} callback
   */
  _has(key, callback = () => {}) {
    if (this._storage.hasOwnProperty(key) || this._storage[key][1] === false) {
      callback(null, false);

      return;
    }

    let result = this._storage[key][1] < InMemoryDriver._now;

    if (!result) {
      this._invalidate(key);

      callback(null, false);

      return;
    }

    callback(null, result);
  }

  /**
   * @param {String} key
   * @param {Function} callback
   */
  _get(key, callback = () => {}) {
    callback(null, this._storage[key]);
  }

  /**
   * @param {String} key
   * @param {*} value
   * @param {Number} ttl
   * @param {Function} callback
   * @returns {Boolean}
   */
  _set(key, value, ttl = 0, callback = () => {}) {
    this._storage[key] = [value, ttl <= 0 ? false : (InMemoryDriver._now + ttl)];

    callback(null, true);
  }

  /**
   * @param {String} key
   * @param {Number} timeout
   * @param {Function} callback
   */
  _invalidate(key, timeout = 0, callback = () => {}) {
    if (timeout <= 0) {
      delete this._storage[key];

      callback(null, true);

      return;
    }

    this._storage[key][1] = InMemoryDriver._now + timeout;

    callback(null, true);
  }

  /**
   * @param {Function} callback
   * @returns {AbstractDriver}
   */
  _flush(callback = () => {}) {
    this._storage = {};

    callback(null, true);
  }

  /**
   * @returns {Number}
   * @private
   */
  static get _now() {
    return new Date().getTime();
  }
}
<commit_msg>Fix in-memory cache driver<commit_after>/**
 * Created by AlexanderC on 6/16/15.
 */

'use strict';

import {AbstractDriver} from './AbstractDriver';

/**
 * In memory driver implementation
 */
export class InMemoryDriver extends AbstractDriver {
  constructor() {
    super();

    this._storage = {};
  }

  /**
   * @returns {Object}
   */
  get storage() {
    return this._storage;
  }

  /**
   * @param {String} key
   * @param {Function} callback
   */
  _has(key, callback = () => {}) {
    if (!this._storage.hasOwnProperty(key) || this._storage[key][1] === false) {
      callback(null, false);

      return;
    }

    let result = this._storage[key][1] < InMemoryDriver._now;

    if (!result) {
      this._invalidate(key);

      callback(null, false);

      return;
    }

    callback(null, result);
  }

  /**
   * @param {String} key
   * @param {Function} callback
   */
  _get(key, callback = () => {}) {
    callback(null, this._storage[key]);
  }

  /**
   * @param {String} key
   * @param {*} value
   * @param {Number} ttl
   * @param {Function} callback
   * @returns {Boolean}
   */
  _set(key, value, ttl = 0, callback = () => {}) {
    this._storage[key] = [value, ttl <= 0 ? false : (InMemoryDriver._now + ttl)];

    callback(null, true);
  }

  /**
   * @param {String} key
   * @param {Number} timeout
   * @param {Function} callback
   */
  _invalidate(key, timeout = 0, callback = () => {}) {
    if (timeout <= 0) {
      delete this._storage[key];

      callback(null, true);

      return;
    }

    this._storage[key][1] = InMemoryDriver._now + timeout;

    callback(null, true);
  }

  /**
   * @param {Function} callback
   * @returns {AbstractDriver}
   */
  _flush(callback = () => {}) {
    this._storage = {};

    callback(null, true);
  }

  /**
   * @returns {Number}
   * @private
   */
  static get _now() {
    return new Date().getTime();
  }
}
<|endoftext|>


<commit_before>var async = require('async');

var private = {}, self = null,
	library = null, modules = null;
private.unconfirmedTransactions = [];
private.unconfirmedTransactionsIdIndex = {};
private.doubleSpendingTransactions = {};

function Transactions(cb, _library) {
	self = this;
	library = _library;
	cb(null, self);
}

private.addUnconfirmedTransaction = function (transaction, cb, scope) {
	self.applyUnconfirmedTransaction(transaction, function (err) {
		if (err) {
			private.addDoubleSpending(transaction, function () {
				setImmediate(cb, err);
			}, scope);
		} else {
			(scope || private).unconfirmedTransactions.push(transaction);
			var index = (scope || private).unconfirmedTransactions.length - 1;
			(scope || private).unconfirmedTransactionsIdIndex[transaction.id] = index;

			setImmediate(cb);
		}
	}, scope);
}

private.applyTransactionList = function (transactions, cb, scope) {
	async.eachSeries(transactions, function (transaction, cb) {
		self.applyTransaction(transaction, function (err) {
			if (err) {
				return setImmediate(cb, err);
			}
			self.removeUnconfirmedTransaction(transaction.id, function () {
				setImmediate(cb, err);
			}, scope);
		}, scope);
	}, cb);
}

private.addDoubleSpending = function (transaction, cb, scope) {
	(scope || private).doubleSpendingTransactions[transaction.id] = transaction;
	setImmediate(cb);
}

Transactions.prototype.getUnconfirmedTransaction = function (id, cb, scope) {
	var index = (scope || private).unconfirmedTransactionsIdIndex[id];
	setImmediate(cb, null, (scope || private).unconfirmedTransactions[index]);
}

Transactions.prototype.undoUnconfirmedTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.getAccount({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}
		modules.logic.transaction.undoUnconfirmed(transaction, sender, cb, scope);
	}, scope);
}

Transactions.prototype.undoTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.getAccount({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}
		modules.logic.transaction.undo(transaction, sender, cb, scope);
	}, scope);
}

Transactions.prototype.processUnconfirmedTransaction = function (transaction, cb, scope) {
	function done(err) {
		if (err) {
			return cb(err);
		}

		private.addUnconfirmedTransaction(transaction, function (err) {
			if (err) {
				return cb(err);
			}

			!scope && modules.api.transport.message("transaction", transaction, function () {
				cb(null, {
					transactionId: transaction.id
				});
			});
		}, scope);
	}

	if ((scope || private).unconfirmedTransactionsIdIndex[transaction.id] !== undefined || (scope || private).doubleSpendingTransactions[transaction.id]) {
		return done("This transaction already exists");
	}

	var trsBytes = modules.logic.transaction.getBytes(transaction);
	transaction.id = modules.api.crypto.getId(trsBytes);

	modules.logic.transaction.normalize(transaction, function (err) {
		if (err) {
			return done(err);
		}

		modules.blockchain.accounts.setAccountAndGet({publicKey: transaction.senderPublicKey}, function (err, sender) {
			if (err) {
				return done(err);
			}
			async.series([
				function (cb) {
					modules.logic.transaction.process(transaction, sender, cb);
				},
				function (cb) {
					modules.logic.transaction.verify(transaction, sender, cb, scope);
				}
			], done);
		}, scope);
	});
}

Transactions.prototype.applyTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.getAccount({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}

		modules.logic.transaction.apply(transaction, sender, cb, scope);
	}, scope);
}

Transactions.prototype.applyUnconfirmedTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.setAccountAndGet({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}
		if (!sender) {
			return cb('Failed account: ' + transaction.id);
		} else {
			modules.logic.transaction.applyUnconfirmed(transaction, sender, cb, scope);
		}
	}, scope);
}

Transactions.prototype.getUnconfirmedTransactionList = function (reverse, cb, scope) {
	var a = [];
	for (var i = 0; i < (scope || private).unconfirmedTransactions.length; i++) {
		if ((scope || private).unconfirmedTransactions[i] !== false) {
			a.push((scope || private).unconfirmedTransactions[i]);
		}
	}

	setImmediate(cb, null, reverse ? a.reverse() : a);
}

Transactions.prototype.removeUnconfirmedTransaction = function (id, cb, scope) {
	var index = (scope || private).unconfirmedTransactionsIdIndex[id];
	delete (scope || private).unconfirmedTransactionsIdIndex[id];
	(scope || private).unconfirmedTransactions[index] = false;
	setImmediate(cb);
}

Transactions.prototype.addTransaction = function (cb, query) {
	var keypair = modules.api.crypto.keypair(query.secret);

	library.sequence.add(function (cb) {
		modules.blockchain.accounts.setAccountAndGet({address: query.recipientId}, function (err, recipient) {
			if (err) {
				return cb(err.toString());
			}
			modules.blockchain.accounts.getAccount({publicKey: keypair.publicKey.toString('hex')}, function (err, account) {
				if (err) {
					return cb(err.toString());
				}
				if (!account || !account.publicKey) {
					return cb("COMMON.OPEN_ACCOUNT");
				}

				try {
					var transaction = modules.logic.transaction.create({
						type: 0,
						amount: query.amount,
						sender: account,
						recipientId: query.recipientId,
						token: query.token,
						keypair: keypair
					});
				} catch (e) {
					return cb(e.toString());
				}

				self.processUnconfirmedTransaction(transaction, cb)
			});
		});
	}, function (err, transaction) {
		if (err) {
			return cb(err.toString());
		}

		cb(null, {transaction: transaction});
	});
}

Transactions.prototype.getTransactions = function (cb, query) {
	self.getUnconfirmedTransactionList(false, cb)
}

Transactions.prototype.onMessage = function (query) {
	switch (query.topic) {
		case "transaction":
			library.sequence.add(function (cb) {
				var transaction = query.message;
				self.processUnconfirmedTransaction(transaction, function (err) {
					if (err) {
						library.logger("processUnconfirmedTransaction error", err)
					}
					cb(err);
				});
			});
			break;
	}
}

Transactions.prototype.onBind = function (_modules) {
	modules = _modules;
}

module.exports = Transactions;<commit_msg>Beautifying code / logs.<commit_after>var async = require("async");

var private = {}, self = null,
	library = null, modules = null;
private.unconfirmedTransactions = [];
private.unconfirmedTransactionsIdIndex = {};
private.doubleSpendingTransactions = {};

function Transactions(cb, _library) {
	self = this;
	library = _library;
	cb(null, self);
}

private.addUnconfirmedTransaction = function (transaction, cb, scope) {
	self.applyUnconfirmedTransaction(transaction, function (err) {
		if (err) {
			private.addDoubleSpending(transaction, function () {
				setImmediate(cb, err);
			}, scope);
		} else {
			(scope || private).unconfirmedTransactions.push(transaction);
			var index = (scope || private).unconfirmedTransactions.length - 1;
			(scope || private).unconfirmedTransactionsIdIndex[transaction.id] = index;

			setImmediate(cb);
		}
	}, scope);
}

private.applyTransactionList = function (transactions, cb, scope) {
	async.eachSeries(transactions, function (transaction, cb) {
		self.applyTransaction(transaction, function (err) {
			if (err) {
				return setImmediate(cb, err);
			}
			self.removeUnconfirmedTransaction(transaction.id, function () {
				setImmediate(cb, err);
			}, scope);
		}, scope);
	}, cb);
}

private.addDoubleSpending = function (transaction, cb, scope) {
	(scope || private).doubleSpendingTransactions[transaction.id] = transaction;
	setImmediate(cb);
}

Transactions.prototype.getUnconfirmedTransaction = function (id, cb, scope) {
	var index = (scope || private).unconfirmedTransactionsIdIndex[id];
	setImmediate(cb, null, (scope || private).unconfirmedTransactions[index]);
}

Transactions.prototype.undoUnconfirmedTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.getAccount({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}
		modules.logic.transaction.undoUnconfirmed(transaction, sender, cb, scope);
	}, scope);
}

Transactions.prototype.undoTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.getAccount({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}
		modules.logic.transaction.undo(transaction, sender, cb, scope);
	}, scope);
}

Transactions.prototype.processUnconfirmedTransaction = function (transaction, cb, scope) {
	function done(err) {
		if (err) {
			return cb(err);
		}

		private.addUnconfirmedTransaction(transaction, function (err) {
			if (err) {
				return cb(err);
			}

			!scope && modules.api.transport.message("transaction", transaction, function () {
				cb(null, {
					transactionId: transaction.id
				});
			});
		}, scope);
	}

	if ((scope || private).unconfirmedTransactionsIdIndex[transaction.id] !== undefined || (scope || private).doubleSpendingTransactions[transaction.id]) {
		return done("Transaction already exists");
	}

	var trsBytes = modules.logic.transaction.getBytes(transaction);
	transaction.id = modules.api.crypto.getId(trsBytes);

	modules.logic.transaction.normalize(transaction, function (err) {
		if (err) {
			return done(err);
		}

		modules.blockchain.accounts.setAccountAndGet({publicKey: transaction.senderPublicKey}, function (err, sender) {
			if (err) {
				return done(err);
			}
			async.series([
				function (cb) {
					modules.logic.transaction.process(transaction, sender, cb);
				},
				function (cb) {
					modules.logic.transaction.verify(transaction, sender, cb, scope);
				}
			], done);
		}, scope);
	});
}

Transactions.prototype.applyTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.getAccount({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}

		modules.logic.transaction.apply(transaction, sender, cb, scope);
	}, scope);
}

Transactions.prototype.applyUnconfirmedTransaction = function (transaction, cb, scope) {
	modules.blockchain.accounts.setAccountAndGet({publicKey: transaction.senderPublicKey}, function (err, sender) {
		if (err) {
			return setImmediate(cb, err);
		}
		if (!sender) {
			return cb("Failed get sender: " + transaction.id);
		} else {
			modules.logic.transaction.applyUnconfirmed(transaction, sender, cb, scope);
		}
	}, scope);
}

Transactions.prototype.getUnconfirmedTransactionList = function (reverse, cb, scope) {
	var a = [];
	for (var i = 0; i < (scope || private).unconfirmedTransactions.length; i++) {
		if ((scope || private).unconfirmedTransactions[i] !== false) {
			a.push((scope || private).unconfirmedTransactions[i]);
		}
	}

	setImmediate(cb, null, reverse ? a.reverse() : a);
}

Transactions.prototype.removeUnconfirmedTransaction = function (id, cb, scope) {
	var index = (scope || private).unconfirmedTransactionsIdIndex[id];
	delete (scope || private).unconfirmedTransactionsIdIndex[id];
	(scope || private).unconfirmedTransactions[index] = false;
	setImmediate(cb);
}

Transactions.prototype.addTransaction = function (cb, query) {
	var keypair = modules.api.crypto.keypair(query.secret);

	library.sequence.add(function (cb) {
		modules.blockchain.accounts.setAccountAndGet({address: query.recipientId}, function (err, recipient) {
			if (err) {
				return cb(err.toString());
			}
			modules.blockchain.accounts.getAccount({publicKey: keypair.publicKey.toString("hex")}, function (err, account) {
				if (err) {
					return cb(err.toString());
				}
				if (!account || !account.publicKey) {
					return cb("Account not found");
				}

				try {
					var transaction = modules.logic.transaction.create({
						type: 0,
						amount: query.amount,
						sender: account,
						recipientId: query.recipientId,
						token: query.token,
						keypair: keypair
					});
				} catch (e) {
					return cb(e.toString());
				}

				self.processUnconfirmedTransaction(transaction, cb)
			});
		});
	}, function (err, transaction) {
		if (err) {
			return cb(err.toString());
		}

		cb(null, {transaction: transaction});
	});
}

Transactions.prototype.getTransactions = function (cb, query) {
	self.getUnconfirmedTransactionList(false, cb)
}

Transactions.prototype.onMessage = function (query) {
	switch (query.topic) {
		case "transaction":
			library.sequence.add(function (cb) {
				var transaction = query.message;
				self.processUnconfirmedTransaction(transaction, function (err) {
					if (err) {
						library.logger("Failed to process unconfirmed transaction", err)
					}
					cb(err);
				});
			});
			break;
	}
}

Transactions.prototype.onBind = function (_modules) {
	modules = _modules;
}

module.exports = Transactions;
<|endoftext|>


<commit_before>/* global WeatherProvider */

/* Magic Mirror
 * Module: Weather
 *
 * By Michael Teeuw https://michaelteeuw.nl
 * MIT Licensed.
 */
Module.register("weather", {
	// Default module config.
	defaults: {
		weatherProvider: "openweathermap",
		roundTemp: false,
		type: "current", //current, forecast

		location: false,
		locationID: false,
		appid: "",
		units: config.units,

		tempUnits: config.units,
		windUnits: config.units,

		updateInterval: 10 * 60 * 1000, // every 10 minutes
		animationSpeed: 1000,
		timeFormat: config.timeFormat,
		showPeriod: true,
		showPeriodUpper: false,
		showWindDirection: true,
		showWindDirectionAsArrow: false,
		useBeaufort: true,
		lang: config.language,
		showHumidity: false,
		showSun: true,
		degreeLabel: false,
		decimalSymbol: ".",
		showIndoorTemperature: false,
		showIndoorHumidity: false,
		maxNumberOfDays: 5,
		fade: true,
		fadePoint: 0.25, // Start on 1/4th of the list.

		initialLoadDelay: 0, // 0 seconds delay
		retryDelay: 2500,

		apiVersion: "2.5",
		apiBase: "https://api.openweathermap.org/data/",
		weatherEndpoint: "/weather",

		appendLocationNameToHeader: true,
		calendarClass: "calendar",
		tableClass: "small",

		onlyTemp: false,
		showPrecipitationAmount: false,
		colored: false,
		showFeelsLike: true
	},

	// Module properties.
	weatherProvider: null,

	// Define required scripts.
	getStyles: function () {
		return ["font-awesome.css", "weather-icons.css", "weather.css"];
	},

	// Return the scripts that are necessary for the weather module.
	getScripts: function () {
		return ["moment.js", "weatherprovider.js", "weatherobject.js", "suncalc.js", this.file("providers/" + this.config.weatherProvider.toLowerCase() + ".js")];
	},

	// Override getHeader method.
	getHeader: function () {
		if (this.config.appendLocationNameToHeader && this.data.header !== undefined && this.weatherProvider) {
			return this.data.header + " " + this.weatherProvider.fetchedLocation();
		}

		return this.data.header;
	},

	// Start the weather module.
	start: function () {
		moment.locale(this.config.lang);

		// Initialize the weather provider.
		this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this);

		// Let the weather provider know we are starting.
		this.weatherProvider.start();

		// Add custom filters
		this.addFilters();

		// Schedule the first update.
		this.scheduleUpdate(this.config.initialLoadDelay);
	},

	// Override notification handler.
	notificationReceived: function (notification, payload, sender) {
		if (notification === "CALENDAR_EVENTS") {
			var senderClasses = sender.data.classes.toLowerCase().split(" ");
			if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) {
				this.firstEvent = false;

				for (var e in payload) {
					var event = payload[e];
					if (event.location || event.geo) {
						this.firstEvent = event;
						//Log.log("First upcoming event with location: ", event);
						break;
					}
				}
			}
		} else if (notification === "INDOOR_TEMPERATURE") {
			this.indoorTemperature = this.roundValue(payload);
			this.updateDom(300);
		} else if (notification === "INDOOR_HUMIDITY") {
			this.indoorHumidity = this.roundValue(payload);
			this.updateDom(300);
		}
	},

	// Select the template depending on the display type.
	getTemplate: function () {
		return `${this.config.type.toLowerCase()}.njk`;
	},

	// Add all the data to the template.
	getTemplateData: function () {
		return {
			config: this.config,
			current: this.weatherProvider.currentWeather(),
			forecast: this.weatherProvider.weatherForecast(),
			indoor: {
				humidity: this.indoorHumidity,
				temperature: this.indoorTemperature
			}
		};
	},

	// What to do when the weather provider has new information available?
	updateAvailable: function () {
		Log.log("New weather information available.");
		this.updateDom(0);
		this.scheduleUpdate();
	},

	scheduleUpdate: function (delay = null) {
		var nextLoad = this.config.updateInterval;
		if (delay !== null && delay >= 0) {
			nextLoad = delay;
		}

		setTimeout(() => {
			if (this.config.type === "forecast") {
				this.weatherProvider.fetchWeatherForecast();
			} else {
				this.weatherProvider.fetchCurrentWeather();
			}
		}, nextLoad);
	},

	roundValue: function (temperature) {
		var decimals = this.config.roundTemp ? 0 : 1;
		return parseFloat(temperature).toFixed(decimals);
	},

	addFilters() {
		this.nunjucksEnvironment().addFilter(
			"formatTime",
			function (date) {
				date = moment(date);

				if (this.config.timeFormat !== 24) {
					if (this.config.showPeriod) {
						if (this.config.showPeriodUpper) {
							return date.format("h:mm A");
						} else {
							return date.format("h:mm a");
						}
					} else {
						return date.format("h:mm");
					}
				}

				return date.format("HH:mm");
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"unit",
			function (value, type) {
				if (type === "temperature") {
					if (this.config.tempUnits === "metric" || this.config.tempUnits === "imperial") {
						value += "°";
					}
					if (this.config.degreeLabel) {
						if (this.config.tempUnits === "metric") {
							value += "C";
						} else if (this.config.tempUnits === "imperial") {
							value += "F";
						} else {
							value += "K";
						}
					}
				} else if (type === "precip") {
					if (isNaN(value) || value === 0 || value.toFixed(2) === "0.00") {
						value = "";
					} else {
						if (this.config.weatherProvider === "ukmetoffice") {
							value += "%";
						} else {
							value = `${value.toFixed(2)} ${this.config.units === "imperial" ? "in" : "mm"}`;
						}
					}
				} else if (type === "humidity") {
					value += "%";
				}

				return value;
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"roundValue",
			function (value) {
				return this.roundValue(value);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"decimalSymbol",
			function (value) {
				return value.toString().replace(/\./g, this.config.decimalSymbol);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"calcNumSteps",
			function (forecast) {
				return Math.min(forecast.length, this.config.maxNumberOfDays);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"opacity",
			function (currentStep, numSteps) {
				if (this.config.fade && this.config.fadePoint < 1) {
					if (this.config.fadePoint < 0) {
						this.config.fadePoint = 0;
					}
					var startingPoint = numSteps * this.config.fadePoint;
					var numFadesteps = numSteps - startingPoint;
					if (currentStep >= startingPoint) {
						return 1 - (currentStep - startingPoint) / numFadesteps;
					} else {
						return 1;
					}
				} else {
					return 1;
				}
			}.bind(this)
		);
	}
});
<commit_msg>Included check for Met Office DataHub provider.<commit_after>/* global WeatherProvider */

/* Magic Mirror
 * Module: Weather
 *
 * By Michael Teeuw https://michaelteeuw.nl
 * MIT Licensed.
 */
Module.register("weather", {
	// Default module config.
	defaults: {
		weatherProvider: "openweathermap",
		roundTemp: false,
		type: "current", //current, forecast

		location: false,
		locationID: false,
		appid: "",
		units: config.units,

		tempUnits: config.units,
		windUnits: config.units,

		updateInterval: 10 * 60 * 1000, // every 10 minutes
		animationSpeed: 1000,
		timeFormat: config.timeFormat,
		showPeriod: true,
		showPeriodUpper: false,
		showWindDirection: true,
		showWindDirectionAsArrow: false,
		useBeaufort: true,
		lang: config.language,
		showHumidity: false,
		showSun: true,
		degreeLabel: false,
		decimalSymbol: ".",
		showIndoorTemperature: false,
		showIndoorHumidity: false,
		maxNumberOfDays: 5,
		fade: true,
		fadePoint: 0.25, // Start on 1/4th of the list.

		initialLoadDelay: 0, // 0 seconds delay
		retryDelay: 2500,

		apiVersion: "2.5",
		apiBase: "https://api.openweathermap.org/data/",
		weatherEndpoint: "/weather",

		appendLocationNameToHeader: true,
		calendarClass: "calendar",
		tableClass: "small",

		onlyTemp: false,
		showPrecipitationAmount: false,
		colored: false,
		showFeelsLike: true
	},

	// Module properties.
	weatherProvider: null,

	// Define required scripts.
	getStyles: function () {
		return ["font-awesome.css", "weather-icons.css", "weather.css"];
	},

	// Return the scripts that are necessary for the weather module.
	getScripts: function () {
		return ["moment.js", "weatherprovider.js", "weatherobject.js", "suncalc.js", this.file("providers/" + this.config.weatherProvider.toLowerCase() + ".js")];
	},

	// Override getHeader method.
	getHeader: function () {
		if (this.config.appendLocationNameToHeader && this.data.header !== undefined && this.weatherProvider) {
			return this.data.header + " " + this.weatherProvider.fetchedLocation();
		}

		return this.data.header;
	},

	// Start the weather module.
	start: function () {
		moment.locale(this.config.lang);

		// Initialize the weather provider.
		this.weatherProvider = WeatherProvider.initialize(this.config.weatherProvider, this);

		// Let the weather provider know we are starting.
		this.weatherProvider.start();

		// Add custom filters
		this.addFilters();

		// Schedule the first update.
		this.scheduleUpdate(this.config.initialLoadDelay);
	},

	// Override notification handler.
	notificationReceived: function (notification, payload, sender) {
		if (notification === "CALENDAR_EVENTS") {
			var senderClasses = sender.data.classes.toLowerCase().split(" ");
			if (senderClasses.indexOf(this.config.calendarClass.toLowerCase()) !== -1) {
				this.firstEvent = false;

				for (var e in payload) {
					var event = payload[e];
					if (event.location || event.geo) {
						this.firstEvent = event;
						//Log.log("First upcoming event with location: ", event);
						break;
					}
				}
			}
		} else if (notification === "INDOOR_TEMPERATURE") {
			this.indoorTemperature = this.roundValue(payload);
			this.updateDom(300);
		} else if (notification === "INDOOR_HUMIDITY") {
			this.indoorHumidity = this.roundValue(payload);
			this.updateDom(300);
		}
	},

	// Select the template depending on the display type.
	getTemplate: function () {
		return `${this.config.type.toLowerCase()}.njk`;
	},

	// Add all the data to the template.
	getTemplateData: function () {
		return {
			config: this.config,
			current: this.weatherProvider.currentWeather(),
			forecast: this.weatherProvider.weatherForecast(),
			indoor: {
				humidity: this.indoorHumidity,
				temperature: this.indoorTemperature
			}
		};
	},

	// What to do when the weather provider has new information available?
	updateAvailable: function () {
		Log.log("New weather information available.");
		this.updateDom(0);
		this.scheduleUpdate();
	},

	scheduleUpdate: function (delay = null) {
		var nextLoad = this.config.updateInterval;
		if (delay !== null && delay >= 0) {
			nextLoad = delay;
		}

		setTimeout(() => {
			if (this.config.type === "forecast") {
				this.weatherProvider.fetchWeatherForecast();
			} else {
				this.weatherProvider.fetchCurrentWeather();
			}
		}, nextLoad);
	},

	roundValue: function (temperature) {
		var decimals = this.config.roundTemp ? 0 : 1;
		return parseFloat(temperature).toFixed(decimals);
	},

	addFilters() {
		this.nunjucksEnvironment().addFilter(
			"formatTime",
			function (date) {
				date = moment(date);

				if (this.config.timeFormat !== 24) {
					if (this.config.showPeriod) {
						if (this.config.showPeriodUpper) {
							return date.format("h:mm A");
						} else {
							return date.format("h:mm a");
						}
					} else {
						return date.format("h:mm");
					}
				}

				return date.format("HH:mm");
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"unit",
			function (value, type) {
				if (type === "temperature") {
					if (this.config.tempUnits === "metric" || this.config.tempUnits === "imperial") {
						value += "°";
					}
					if (this.config.degreeLabel) {
						if (this.config.tempUnits === "metric") {
							value += "C";
						} else if (this.config.tempUnits === "imperial") {
							value += "F";
						} else {
							value += "K";
						}
					}
				} else if (type === "precip") {
					if (isNaN(value) || value === 0 || value.toFixed(2) === "0.00") {
						value = "";
					} else {
						if (this.config.weatherProvider === "ukmetoffice" || this.config.weatherProvider === "ukmetofficedatahub") {
							value += "%";
						} else {
							value = `${value.toFixed(2)} ${this.config.units === "imperial" ? "in" : "mm"}`;
						}
					}
				} else if (type === "humidity") {
					value += "%";
				}

				return value;
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"roundValue",
			function (value) {
				return this.roundValue(value);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"decimalSymbol",
			function (value) {
				return value.toString().replace(/\./g, this.config.decimalSymbol);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"calcNumSteps",
			function (forecast) {
				return Math.min(forecast.length, this.config.maxNumberOfDays);
			}.bind(this)
		);

		this.nunjucksEnvironment().addFilter(
			"opacity",
			function (currentStep, numSteps) {
				if (this.config.fade && this.config.fadePoint < 1) {
					if (this.config.fadePoint < 0) {
						this.config.fadePoint = 0;
					}
					var startingPoint = numSteps * this.config.fadePoint;
					var numFadesteps = numSteps - startingPoint;
					if (currentStep >= startingPoint) {
						return 1 - (currentStep - startingPoint) / numFadesteps;
					} else {
						return 1;
					}
				} else {
					return 1;
				}
			}.bind(this)
		);
	}
});
<|endoftext|>


<commit_before><commit_msg>113 solved<commit_after>var buildTree = require("./building").buildTree;
/**
 * @param {TreeNode} root
 * @param {number} sum
 * @return {number[][]}
 */
var pathSum = function(root, sum) {
    var res = [];

    if (!root) {
        return res;
    }

    function arrSum(arr) {
        return arr.reduce(function (a, b) {
            return a + b;
        });
    }

    (function dfs(node, curArr) {
        if (!node.left && !node.right) {
            curArr.push(node.val);
            var curSum = arrSum((curArr));
            if (curSum === sum) {
                res.push(curArr.slice(0));
            }
            curArr.pop();
        } else {
            if (node.left) {
                curArr.push(node.val);
                dfs(node.left, curArr);
                curArr.pop();
            }

            if (node.right) {
                curArr.push(node.val);
                dfs(node.right, curArr);
                curArr.pop();
            }
        }
    }(root, []));

    return res;
};

var t = buildTree("5,4,8,11,#,13,4,7,2,#,#,5,1");
console.log(pathSum(t, 22));<|endoftext|>


<commit_before>
// The modalPopupWindow function
alert = function () {

    /********************
     Variables definition
     ********************/
    var self = this;
    this.defaultPadding = 15 + "px";
    this.defaultButtonPadding = 5 + "px";
    this.defaultButtonSidePadding = 10 + "px";
    this.defaultButtonMargin  = 10 + "px";
    this.defaultLineHeight = 20 + "px";
    this.defaultAppearance =
        '
' +
        '
' +
        '
' +
        'Custom ModalDialogBox' +
        '
' +
        '
' +
        'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec rutrum, magna ut interdum lobortis, odio arcu ultrices neque, id porta sapien justo sit amet erat. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum in tellus nec erat feugiat elementum id eget enim. Fusce a lectus tempus, volutpat erat vel, pharetra nunc' +
        '
' +
        '
' +
        '
'+
        '
' +
        '
';

    // Used to write the DialogBox html content, so that we can retrieve it
    var modalWindow = document.createElement("div");
    modalWindow.innerHTML =this.defaultAppearance;
    document.body.insertBefore(modalWindow,document.body.firstChild);

    // Retrieves the main components of the ModalDialog
    this.overlay = document.getElementById('window-overlay');
    this.container = document.getElementById('window-container');
    this.actionBar = document.getElementById('window-actionBar');
    this.content = document.getElementById('window-content');
    this.footer = document.getElementById('window-footer');

    /******************
     Functions definition
     ******************/

    /**
     * Centers and sets the window to its default size
     * @returns {setDefaultSize}
     */
    function setDefaultSize() {

        // Sets the overlay
        self.overlay.style.position = "absolute";
        self.overlay.style.left = 0+'px';
        self.overlay.style.right = 0+'px';
        self.overlay.style.bottom = 0+'px';
        self.overlay.style.top = 0+'px';
        self.overlay.style.backgroundColor = "rgba(210,210,210,0.8)";

        //Sets the padding and line heights
        self.content.style.lineHeight = self.defaultLineHeight;
        self.content.style.padding = self.defaultPadding;

        self.actionBar.style.lineHeight = self.defaultLineHeight;
        self.actionBar.style.padding = self.defaultPadding;

        self.footer.style.lineHeight = self.defaultLineHeight;
        self.footer.style.padding = self.defaultPadding;

        // Sets the container dimensions
        self.container.style.width = window.innerWidth / 3 + "px";
        self.container.style.zIndex = 1000;
        self.container.style.margin = "auto";
        self.container.style.marginTop = window.innerHeight/2- (self.container.offsetHeight)/2+"px";

    }

    /**
     * Adds a button to the footer, can be called several times
     * @param buttonId
     * @param text
     * @param triggeredFunction
     * @returns {Element}
     */
    function addButton(buttonId,text,triggeredFunction) {

        // Sets the defaultColor for the button
        var defaultColor = "rgb(255,255,255)";
        var defaultHoveredColor = "rgb(225,225,225)";

        // Creates the button with the given text and listener
        var btn = document.createElement("A");
        var t = document.createTextNode(text);
        btn.addEventListener('click', function(){
            dismissDialog();
        });
        btn.appendChild(t);

        // Adds the id
        btn.id = buttonId;

        // Adds some CSS effects to the button
        btn.style.padding = self.defaultButtonPadding;
        btn.style.paddingLeft = self.defaultButtonSidePadding;
        btn.style.paddingRight = self.defaultButtonSidePadding;
        btn.style.marginLeft = self.defaultButtonMargin;

        // Sets the background color
        btn.style.backgroundColor = defaultColor;

        // Rounds the corners
        btn.style.borderTopLeftRadius = 4+"px";
        btn.style.borderTopRightRadius = 4+"px";
        btn.style.borderBottomRightRadius = 4+"px";
        btn.style.borderBottomLeftRadius = 4+"px";

        // Adds nice hover effect
        btn.onmouseover = function() {
            btn.style.backgroundColor = defaultHoveredColor
        };
        btn.onmouseout = function() {
            btn.style.backgroundColor = defaultColor
        };

        // Sets the border
        btn.style.border = "1px solid rgb(165,165,165)";

        // Finally adds the button to the html page
        self.footer.appendChild(btn);

    }

    /**
     * Removes a button given its ID
     * @param buttonId
     */
    function removeButton(buttonId) {
        var self = document.getElementById(buttonId);
        self.parentNode.removeChild(self);
        return document.getElementById('window-overlay');
    }
    /**
     * Adds some CSS effects
     */
    function prettify() {

        // Rounds the corners
        self.container.style.borderBottomLeftRadius =  6 + "px";
        self.container.style.borderBottomRightRadius =  6 + "px";
        self.container.style.borderTopLeftRadius =  6 + "px";
        self.container.style.borderTopRightRadius =  6 + "px";
        self.container.style.overflow = "hidden";

        // Adds margins
        self.actionBar.style.borderBottomColor = "rgb(229,229,229)";
        self.actionBar.style.borderBottomStyle = "solid";
        self.actionBar.style.borderBottomWidth = "1px";

        self.footer.style.borderTopColor = "rgb(229,229,229)";
        self.footer.style.borderTopStyle = "solid";
        self.footer.style.borderTopWidth = "1px";

        // Sets the text orientation
        self.footer.style.textAlign = "right";

        // Sets the title text size
        self.actionBar.style.fontSize = "18px";

        // Loads a nice font (it is perfectly supported to have several


<commit_before>const mixins = require('../../mixins.js');

module.exports = function (values) {
  const c = values.colors;
  const stOpts = values.options;

  return [

    // Default Thickness
    ...mixins.createComponentVariations((lumin, palette) => {
      return {
        class: 'tab_control',
        settings: [stOpts.underlineDirtyTabs],
        attributes: ['dirty'],

        parents: [
          {
            attributes: [lumin],
          },
        ],

        'layer2.tint': palette('gray'),
      };
    }),

    {
      class: 'tab_control',
      settings: [stOpts.underlineDirtyTabs],
      attributes: ['dirty', 'selected'],

      'layer2.opacity': 1, // Border - Bottom
    },

    // Thick Thickness
    {
      class: 'tab_control',
      settings: [stOpts.underlineDirtyTabs, stOpts.underlineDirtyTabsThick],
      attributes: ['dirty'],

      'layer2.inner_margin': [0, 0, 0, 2],
    },
  ];
};
<commit_msg>support highlight_modified_tabs setting<commit_after>const mixins = require('../../mixins.js');

module.exports = function (values) {
  const c = values.colors;
  const stOpts = values.options;

  return [

    // Default Thickness
    ...mixins.createComponentVariations((lumin, palette) => {
      return {
        class: 'tab_control',
        settings: [stOpts.underlineDirtyTabs],
        attributes: ['dirty'],

        parents: [
          {
            attributes: [lumin],
          },
        ],

        'layer2.tint': palette('gray'),
      };
    }),

    {
      class: 'tab_control',
      settings: [stOpts.underlineDirtyTabs],
      attributes: ['dirty', 'selected'],

      'layer2.opacity': 1, // Border - Bottom
    },

    // Thick Thickness
    {
      class: 'tab_control',
      settings: [stOpts.underlineDirtyTabs, stOpts.underlineDirtyTabsThick],
      attributes: ['dirty'],

      'layer2.inner_margin': [0, 0, 0, 2],
    },

    /* support for highlight_modified_tabs setting */

    // Default Thickness
    ...mixins.createComponentVariations((lumin, palette) => {
      return {
        class: 'tab_control',
        settings: ['highlight_modified_tabs'],
        attributes: ['dirty'],

        parents: [
          {
            attributes: [lumin],
          },
        ],

        'layer2.tint': palette('gray'),
      };
    }),

    {
      class: 'tab_control',
      settings: ['highlight_modified_tabs'],
      attributes: ['dirty', 'selected'],

      'layer2.opacity': 1, // Border - Bottom
    },

    // Thick Thickness
    {
      class: 'tab_control',
      settings: ['highlight_modified_tabs', stOpts.underlineDirtyTabsThick],
      attributes: ['dirty'],

      'layer2.inner_margin': [0, 0, 0, 2],
    },
  ];
};
<|endoftext|>


<commit_before>var Ajax;
if (Ajax && (Ajax != null)) {
	Ajax.Responders.register({
	  onCreate: function() {
        if($('spinner') && Ajax.activeRequestCount>0)
          Effect.Appear('spinner',{duration:0.5,queue:'end'});
	  },
	  onComplete: function() {
        if($('spinner') && Ajax.activeRequestCount==0)
          Effect.Fade('spinner',{duration:0.5,queue:'end'});
	  }
	});
}
<commit_msg>clean up<commit_after><|endoftext|>


<commit_before>typeof jQuery!="undefined"&&jQuery(function(e){function n(n,i){var s,o,u,a,f,l,c,h,p,d={ENTER:13,BACKSPACE:8,TAB:9,SPACE:32,ARROW_LEFT:37,ARROW_RIGHT:39,ARROW_UP:38,ARROW_DOWN:40,ESC:27,DELETE:46},v={separator:/(?:,|\s|;)/g,placeholderText:undefined,inPlaceEdit:!1,dynamicInputSizing:!0,saveOnSpace:!0,allowDuplicates:!1,validators:[]},m=e.extend({},v,i);return i.placeholderText&&(m.dynamicInputSizing=!1),l=this,this.init=function(n,r){s=n,a=r,c=a.separator,a.validators.push(function(e){return!e.match(c)}),f=[],this.createElements(),this.bindEvents();if(a.placeholderText&&a.dynamicInputSizing)throw new Error('Can not use options "placeholderText" and "dynamicInputSizing" at the same time.');a.placeholderText&&!t&&l.polyfillPlaceholder(),a.dynamicInputSizing&&(this.initInputResizing(),this.resizeInput()),a.autoComplete&&this.initAutoComplete(o,a.autoComplete);if(a.inPlaceEdit){if(a.autoComplete)throw new Error('Can not use options "inPlaceEdit" and "autocomplete" at the same time.');this.initInPlaceEdit()}return e.trim(s.val())!==""&&this.preFillItems(),this},this.createElements=function(){h=e('

<input class="beautylist-input" type="text" />

'),o=h.find("input"),u=h.find("ul"),s.hide().after(h),a.placeholderText&&o.attr("placeholder",a.placeholderText),this.createRuler()},this.bindEvents=function(){s.bind("beautylist-reset",l.reset),o.bind("keyup paste",l.parseItem).bind("keydown",l.handleKeyEvent),o.bind("blur",function(){a.autoComplete?e("#ui-active-menuitem").length||l.addItem():l.addItem()}),h.bind("click",function(t){var n=e(t.target);(n.is("ul")||n.is("div"))&&o.focus()}),l.bindListEvents()},this.handleKeyEvent=function(t){switch(t.which){case d.SPACE:if(!m.saveOnSpace)break;case d.ENTER:case d.TAB:t.preventDefault(),a.autoComplete?e("#ui-active-menuitem").length||(l.addItem(),o.autocomplete("close")):l.addItem();break;case d.BACKSPACE:case d.ARROW_LEFT:o.val()||(t.preventDefault(),t.stopPropagation(),l.focusToLastElement());break;default:}},this.bindListEvents=function(){var t;u.on("click","a",function(t){t.preventDefault(),e(this.focus())}).on("click",".beautylist-delete-item",function(t){l.removeItem(e(this).closest("li"))}).on("keydown",".beautylist-item a:focus",function(n){var r=e(this);switch(n.which){case d.BACKSPACE:case d.DELETE:var i=l.getNextItem(r);n.preventDefault(),n.stopPropagation(),l.removeItem(r.closest(".beautylist-item"),function(){i.focus()});break;case d.ARROW_LEFT:case d.ARROW_UP:case d.ARROW_RIGHT:case d.ARROW_DOWN:t=n.which===d.ARROW_UP||n.which===d.ARROW_LEFT?l.getPreviousItem(r):l.getNextItem(r),t.focus(),n.preventDefault()}})},this.focusToLastElement=function(){u.find(".beautylist-item:last a").length&&u.find(".beautylist-item:last a").focus()},this.getPreviousItem=function(e){return u.find(".beautylist-item").length<2?o:e.parent().prev(".beautylist-item").find("a")},this.getNextItem=function(e){return e.parent().next(".beautylist-item").length?e.parent().next(".beautylist-item").find("a"):o},this.parseItem=function(){var e=o.val();e.match(c)&&l.addItemsToList(e)},this.addItem=function(){var e=o.val();e!==""&&l.addItemsToList(e)},this.preFillItems=function(){var e=s.val();e.match(c)&&l.addItemsToList(e)},this.addItemsToList=function(t){o.val("");var n=e.grep(t.split(c),function(e){return e!==""});e.each(n,function(t,n){var r=e('
'+n+'<button class="beautylist-delete-item"></button>
').data("beautylist-value",n);u.find("li:last").before(r)}),this.updateOriginalInput(),this.toggleValidClasses()},this.toggleValidClasses=function(){u.find(".beautylist-item").each(function(t,n){var i=e(n);i.toggleClass("invalid",!l.validate(r(i)))})},this.validate=function(t){var n=!0;return a.allowDuplicates||(n=e.grep(f,function(e){return e===t}).length<=1),a.validators&&e.each(a.validators,function(e,r){n=n&&r.apply(l,[t])}),!!n},this.updateOriginalInput=function(){f=[],u.find(".beautylist-item").each(function(t,n){f.push(r(e(n)))}),s.val(e.trim(f.join(", "))).trigger("change")},this.removeItem=function(t,n){t.fadeOut(125,function(){e(this).remove(),l.updateOriginalInput(),l.toggleValidClasses(),n&&n()})},this.initInPlaceEdit=function(){u.off("click","a"),u.on("click","a",function(t){t.preventDefault(),l.toggleEditmode(e(this).closest(".beautylist-item"))})},this.initAutoComplete=function(t,n){t.on("focus",function(){var r=null,i=function(e,t){r&&r.item&&l.addItem(),r=null},s=function(e,n){t.val(n.value)},o=function(e,n){r=n,t.val(n.item.value)},u=t.hasClass("beautylist-in-place-edit")?e.extend({appendTo:h,change:s,select:o},n):e.extend({appendTo:h,change:s,close:i,select:o},n);t.autocomplete(u)})},this.toggleEditmode=function(t){var n=r(t),i=e('<input type="text" class="beautylist-in-place-edit"/>');t.find("span").css("visibility","hidden"),e(document).on("keyup.beautylist",function(e){e.which===d.ESC&&l.abortInPlaceEditOnEsc(t,n)}),i.val(r(t)).css("max-width",t.closest(".beautylist").width()).bind("blur",function(){var n=i.val();n===""?(e(document).off("keyup.beautylist"),l.removeItem(e(this).closest("li"))):(r(t,n),t.find("span").text(n).css("visibility","visible"),i.remove(),l.updateOriginalInput(),l.toggleValidClasses())}).bind("keyup keydown",function(e){t.find("span").text(i.val())}).prependTo(t).focus()},this.abortInPlaceEditOnEsc=function(t,n){r(t,n),t.find("span").text(n).css("visibility","visible"),t.find("input").remove(),e(document).off("keyup.beautylist")},this.reset=function(){s.val("").trigger("change"),u.find(".beautylist-item").remove(),f=[]},this.initInputResizing=function(){o.css("width","100%").parent().css("width","100%").bind("keyup keydown",l.stretchInputToGivenText),o.bind("blur",function(){p.text(m.placeholderText?m.placeholderText:""),l.resizeInput()})},this.stretchInputToGivenText=function(){p.text(o.val()),l.resizeInput()},this.resizeInput=function(e){var t=p.outerWidth();o.css("width",t),o.parent().css("width",t)},this.createRuler=function(){p=e(''),p.css({position:"absolute",left:"-9999px",top:0}),p.appendTo("body")},this.polyfillPlaceholder=function(){this.showPlaceholder(),o.bind("blur",function(e){l.showPlaceholder()}).bind("focus",function(e){l.hidePlaceholder()})},this.showPlaceholder=function(){o.val(a.placeholderText).addClass("beautylist-placeholder")},this.hidePlaceholder=function(){o.val("").removeClass("beautylist-placeholder")},this.init(n,m)}function r(e,t){return t?e.data("beautylist-value",t):e.data("beautylist-value")}e.fn.extend({beautyList:function(t){return this.each(function(){var r=e(this),i=new n(r,t);r.data("beautyList",i)})}});var t="placeholder"in document.createElement("input")}(jQuery));
<commit_msg>Update minified JS<commit_after>typeof jQuery!="undefined"&&jQuery(function(e){function n(n,i){var s,o,u,a,f,l,c,h,p,d={ENTER:13,BACKSPACE:8,TAB:9,SPACE:32,ARROW_LEFT:37,ARROW_RIGHT:39,ARROW_UP:38,ARROW_DOWN:40,ESC:27,DELETE:46},v={separator:/(?:,|\s|;)/g,placeholderText:undefined,inPlaceEdit:!1,dynamicInputSizing:!0,saveOnSpace:!0,allowDuplicates:!1,validators:[]},m=e.extend({},v,i);return i.placeholderText&&(m.dynamicInputSizing=!1),l=this,this.init=function(n,r){s=n,a=r,c=a.separator,a.validators.push(function(e){return!e.match(c)}),f=[],this.createElements(),this.bindEvents();if(a.placeholderText&&a.dynamicInputSizing)throw new Error('Can not use options "placeholderText" and "dynamicInputSizing" at the same time.');a.placeholderText&&!t&&l.polyfillPlaceholder(),a.dynamicInputSizing&&(this.initInputResizing(),this.resizeInput()),a.autocomplete&&this.initAutocomplete(o,a.autocomplete);if(a.inPlaceEdit){if(a.autocomplete)throw new Error('Can not use options "inPlaceEdit" and "autocomplete" at the same time.');this.initInPlaceEdit()}return e.trim(s.val())!==""&&this.preFillItems(),this},this.createElements=function(){h=e('

<input class="beautylist-input" type="text" />

'),o=h.find("input"),u=h.find("ul"),s.hide().after(h),a.placeholderText&&o.attr("placeholder",a.placeholderText),this.createRuler()},this.bindEvents=function(){s.bind("beautylist-reset",l.reset),o.bind("keyup paste",l.parseItem).bind("keydown",l.handleKeyEvent),o.bind("blur",function(){a.autocomplete?h.find("#ui-active-menuitem").length||l.addItem():l.addItem()}),h.bind("click",function(t){var n=e(t.target);(n.is("ul")||n.is("div"))&&o.focus()}),l.bindListEvents()},this.handleKeyEvent=function(e){switch(e.which){case d.SPACE:if(!m.saveOnSpace)break;case d.ENTER:case d.TAB:e.preventDefault(),a.autocomplete?h.find("#ui-active-menuitem").length||(l.addItem(),o.autocomplete("close")):l.addItem();break;case d.BACKSPACE:case d.ARROW_LEFT:o.val()||(e.preventDefault(),e.stopPropagation(),l.focusToLastElement());break;default:}},this.bindListEvents=function(){var t;u.on("click","a",function(t){t.preventDefault(),e(this.focus())}).on("click",".beautylist-delete-item",function(t){l.removeItem(e(this).closest("li"))}).on("keydown",".beautylist-item a:focus",function(n){var r=e(this);switch(n.which){case d.BACKSPACE:case d.DELETE:var i=l.getNextItem(r);n.preventDefault(),n.stopPropagation(),l.removeItem(r.closest(".beautylist-item"),function(){i.focus()});break;case d.ARROW_LEFT:case d.ARROW_UP:case d.ARROW_RIGHT:case d.ARROW_DOWN:t=n.which===d.ARROW_UP||n.which===d.ARROW_LEFT?l.getPreviousItem(r):l.getNextItem(r),t.focus(),n.preventDefault()}})},this.focusToLastElement=function(){u.find(".beautylist-item:last a").length&&u.find(".beautylist-item:last a").focus()},this.getPreviousItem=function(e){return u.find(".beautylist-item").length<2?o:e.parent().prev(".beautylist-item").find("a")},this.getNextItem=function(e){return e.parent().next(".beautylist-item").length?e.parent().next(".beautylist-item").find("a"):o},this.parseItem=function(){var e=o.val();e.match(c)&&l.addItemsToList(e)},this.addItem=function(){var e=o.val();e!==""&&l.addItemsToList(e)},this.preFillItems=function(){var e=s.val();e.match(c)&&l.addItemsToList(e)},this.addItemsToList=function(t){o.val("");var n=e.grep(t.split(c),function(e){return e!==""});e.each(n,function(t,n){var r=e('
'+n+'<button class="beautylist-delete-item"></button>
').data("beautylist-value",n);u.find("li:last").before(r)}),this.updateOriginalInput(),this.toggleValidClasses()},this.toggleValidClasses=function(){u.find(".beautylist-item").each(function(t,n){var i=e(n);i.toggleClass("invalid",!l.validate(r(i)))})},this.validate=function(t){var n=!0;return a.allowDuplicates||(n=e.grep(f,function(e){return e===t}).length<=1),a.validators&&e.each(a.validators,function(e,r){n=n&&r.apply(l,[t])}),!!n},this.updateOriginalInput=function(){f=[],u.find(".beautylist-item").each(function(t,n){f.push(r(e(n)))}),s.val(e.trim(f.join(", "))).trigger("change")},this.removeItem=function(t,n){t.fadeOut(125,function(){e(this).remove(),l.updateOriginalInput(),l.toggleValidClasses(),n&&n()})},this.initInPlaceEdit=function(){u.off("click","a"),u.on("click","a",function(t){t.preventDefault(),l.toggleEditmode(e(this).closest(".beautylist-item"))})},this.initAutocomplete=function(t,n){t.on("focus",function(){var r=null,i=function(e,t){r&&r.item&&l.addItem(),r=null,n.close&&n.close(e,t)},s=function(e,r){t.val(r.value),n.change&&n.change(e,r)},o=function(e,i){r=i,t.val(i.item.value),n.select&&n.select(e,i)},u=e.extend({},n,{appendTo:h,change:s,close:i,select:o});t.autocomplete(u)})},this.toggleEditmode=function(t){var n=r(t),i=e('<input type="text" class="beautylist-in-place-edit"/>');t.find("span").css("visibility","hidden"),e(document).on("keyup.beautylist",function(e){e.which===d.ESC&&l.abortInPlaceEditOnEsc(t,n)}),i.val(r(t)).css("max-width",t.closest(".beautylist").width()).bind("blur",function(){var n=i.val();n===""?(e(document).off("keyup.beautylist"),l.removeItem(e(this).closest("li"))):(r(t,n),t.find("span").text(n).css("visibility","visible"),i.remove(),l.updateOriginalInput(),l.toggleValidClasses())}).bind("keyup keydown",function(e){t.find("span").text(i.val())}).prependTo(t).focus()},this.abortInPlaceEditOnEsc=function(t,n){r(t,n),t.find("span").text(n).css("visibility","visible"),t.find("input").remove(),e(document).off("keyup.beautylist")},this.reset=function(){s.val("").trigger("change"),u.find(".beautylist-item").remove(),f=[]},this.initInputResizing=function(){o.css("width","100%").parent().css("width","100%").bind("keyup keydown",l.stretchInputToGivenText),o.bind("blur",function(){p.text(m.placeholderText?m.placeholderText:""),l.resizeInput()})},this.stretchInputToGivenText=function(){p.text(o.val()),l.resizeInput()},this.resizeInput=function(e){var t=p.outerWidth();o.css("width",t),o.parent().css("width",t)},this.createRuler=function(){p=e(''),p.css({position:"absolute",left:"-9999px",top:0}),p.appendTo("body")},this.polyfillPlaceholder=function(){this.showPlaceholder(),o.bind("blur",function(e){l.showPlaceholder()}).bind("focus",function(e){l.hidePlaceholder()})},this.showPlaceholder=function(){o.val(a.placeholderText).addClass("beautylist-placeholder")},this.hidePlaceholder=function(){o.val("").removeClass("beautylist-placeholder")},this.init(n,m)}function r(e,t){return t?e.data("beautylist-value",t):e.data("beautylist-value")}e.fn.extend({beautyList:function(t){return this.each(function(){var r=e(this),i=new n(r,t);r.data("beautyList",i)})}});var t="placeholder"in document.createElement("input")}(jQuery));<|endoftext|>