<commit_before>var muting_ui = (function () {

var exports = {};

function timestamp_ms() {
    return (new Date()).getTime();
}

var last_topic_update = 0;

exports.rerender = function () {
    // Note: We tend to optimistically rerender muting preferences before
    // the back end actually acknowledges the mute.  This gives a more
    // immediate feel to the user, and if the back end fails temporarily,
    // re-doing a mute or unmute is a pretty recoverable thing.

    stream_list.update_streams_sidebar();
    if (current_msg_list.muting_enabled) {
        current_msg_list.update_muting_and_rerender();
    }
    if (current_msg_list !== home_msg_list) {
        home_msg_list.update_muting_and_rerender();
    }
};

exports.notify_with_undo_option = (function () {
    var meta = {
        hide_me_time: null,
        alert_hover_state: false,
        $mute: null,
    };
    var animate = {
        fadeOut: function () {
            if (meta.$mute) {
                meta.$mute.fadeOut(500).removeClass("show");
            }
        },
        fadeIn: function () {
            if (meta.$mute) {
                meta.$mute.fadeIn(500).addClass("show");
            }
        },
    };
    setInterval(function () {
        if (meta.hide_me_time < new Date().getTime() && !meta.alert_hover_state) {
            animate.fadeOut();
        }
    }, 100);

    return function (stream_id, topic) {
        var stream_name = stream_data.maybe_get_stream_name(stream_id);

        var $exit = $("#unmute_muted_topic_notification .exit-me");

        meta.undo = function () {
            // it should reference the meta variable and not get stuck with
            // a pass-by-value of stream, topic.
            exports.unmute(stream_id, topic);
        };

        if (!meta.$mute) {
            meta.$mute = $("#unmute_muted_topic_notification");

            $exit.click(function () {
                animate.fadeOut();
            });

            meta.$mute.find("#unmute").click(function () {
                // it should reference the meta variable and not get stuck with
                // a pass-by-value of stream, topic.
                meta.undo();
                animate.fadeOut();
            });
        }

        // add a four second delay before closing up.
        meta.hide_me_time = new Date().getTime() + 4000;

        meta.$mute.find(".stream").text(stream_name);
        meta.$mute.find(".topic").text(topic);

        animate.fadeIn();

        // if the user mouses over the notification, don't hide it.
        meta.$mute.mouseenter(function () {
            meta.alert_hover_state = true;
        });

        // once the user's mouse leaves the notification, restart the countdown.
        meta.$mute.mouseleave(function () {
            meta.alert_hover_state = false;
            // add at least 2000ms but if more than that exists just keep the
            // current amount.
            meta.hide_me_time = Math.max(meta.hide_me_time, new Date().getTime() + 2000);
        });
    };
}());

exports.dismiss_mute_confirmation = function () {
    var $mute = $("#unmute_muted_topic_notification");
    if ($mute) {
        $mute.fadeOut(500).removeClass("show");
    }
};

exports.persist_mute = function (stream_id, topic_name) {
    var data = {
        stream_id: stream_id,
        topic: topic_name,
        op: 'add',
    };
    last_topic_update = timestamp_ms();
    channel.patch({
        url: '/json/users/me/subscriptions/muted_topics',
        idempotent: true,
        data: data,
    });
};

exports.persist_unmute = function (stream_id, topic_name) {
    var data = {
        stream_id: stream_id,
        topic: topic_name,
        op: 'remove',
    };
    last_topic_update = timestamp_ms();
    channel.patch({
        url: '/json/users/me/subscriptions/muted_topics',
        idempotent: true,
        data: data,
    });
};

exports.handle_updates = function (muted_topics) {
    if (timestamp_ms() < last_topic_update + 1000) {
        // This topic update is either the one that we just rendered, or,
        // much less likely, it's coming from another device and would probably
        // be overwriting this device's preferences with stale data.
        return;
    }

    exports.update_muted_topics(muted_topics);
    exports.rerender();
};

exports.update_muted_topics = function (muted_topics) {
    muting.set_muted_topics(muted_topics);
    unread_ui.update_unread_counts();
};

exports.set_up_muted_topics_ui = function (muted_topics) {
    var muted_topics_table = $("#muted_topics_table tbody");
    muted_topics_table.empty();
    _.each(muted_topics, function (tup) {
        var stream_id = tup[0];
        var topic = tup[1];

        var stream = stream_data.maybe_get_stream_name(stream_id);

        if (!stream) {
            blueslip.warn('Unknown stream_id in set_up_muted_topics_ui: ' + stream_id);
            return;
        }

        var template_data = {
            stream: stream,
            stream_id: stream_id,
            topic: topic,
        };

        var row = templates.render('muted_topic_ui_row', template_data);
        muted_topics_table.append(row);
    });
};

exports.mute = function (stream_id, topic) {
    stream_popover.hide_topic_popover();
    muting.add_muted_topic(stream_id, topic);
    unread_ui.update_unread_counts();
    exports.rerender();
    exports.persist_mute(stream_id, topic);
    exports.notify_with_undo_option(stream_id, topic);
    exports.set_up_muted_topics_ui(muting.get_muted_topics());
};

exports.unmute = function (stream_id, topic) {
    // we don't run a unmute_notify function because it isn't an issue as much
    // if someone accidentally unmutes a stream rather than if they mute it
    // and miss out on info.
    stream_popover.hide_topic_popover();
    muting.remove_muted_topic(stream_id, topic);
    unread_ui.update_unread_counts();
    exports.rerender();
    exports.persist_unmute(stream_id, topic);
    exports.set_up_muted_topics_ui(muting.get_muted_topics());
    exports.dismiss_mute_confirmation();
};

exports.toggle_mute = function (message) {
    var stream_id = message.stream_id;
    var topic = util.get_message_topic(message);

    if (muting.is_topic_muted(stream_id, topic)) {
        exports.unmute(stream_id, topic);
    } else if (message.type === 'stream') {
        exports.mute(stream_id, topic);
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = muting_ui;
}
window.muting_ui = muting_ui;
<commit_msg>minor: Rename $mute to $container.<commit_after>var muting_ui = (function () {

var exports = {};

function timestamp_ms() {
    return (new Date()).getTime();
}

var last_topic_update = 0;

exports.rerender = function () {
    // Note: We tend to optimistically rerender muting preferences before
    // the back end actually acknowledges the mute.  This gives a more
    // immediate feel to the user, and if the back end fails temporarily,
    // re-doing a mute or unmute is a pretty recoverable thing.

    stream_list.update_streams_sidebar();
    if (current_msg_list.muting_enabled) {
        current_msg_list.update_muting_and_rerender();
    }
    if (current_msg_list !== home_msg_list) {
        home_msg_list.update_muting_and_rerender();
    }
};

exports.notify_with_undo_option = (function () {
    var meta = {
        hide_me_time: null,
        alert_hover_state: false,
        $container: null,
    };
    var animate = {
        fadeOut: function () {
            if (meta.$container) {
                meta.$container.fadeOut(500).removeClass("show");
            }
        },
        fadeIn: function () {
            if (meta.$container) {
                meta.$container.fadeIn(500).addClass("show");
            }
        },
    };
    setInterval(function () {
        if (meta.hide_me_time < new Date().getTime() && !meta.alert_hover_state) {
            animate.fadeOut();
        }
    }, 100);

    return function (stream_id, topic) {
        var stream_name = stream_data.maybe_get_stream_name(stream_id);

        var $exit = $("#unmute_muted_topic_notification .exit-me");

        meta.undo = function () {
            // it should reference the meta variable and not get stuck with
            // a pass-by-value of stream, topic.
            exports.unmute(stream_id, topic);
        };

        if (!meta.$container) {
            meta.$container = $("#unmute_muted_topic_notification");

            $exit.click(function () {
                animate.fadeOut();
            });

            meta.$container.find("#unmute").click(function () {
                // it should reference the meta variable and not get stuck with
                // a pass-by-value of stream, topic.
                meta.undo();
                animate.fadeOut();
            });
        }

        // add a four second delay before closing up.
        meta.hide_me_time = new Date().getTime() + 4000;

        meta.$container.find(".stream").text(stream_name);
        meta.$container.find(".topic").text(topic);

        animate.fadeIn();

        // if the user mouses over the notification, don't hide it.
        meta.$container.mouseenter(function () {
            meta.alert_hover_state = true;
        });

        // once the user's mouse leaves the notification, restart the countdown.
        meta.$container.mouseleave(function () {
            meta.alert_hover_state = false;
            // add at least 2000ms but if more than that exists just keep the
            // current amount.
            meta.hide_me_time = Math.max(meta.hide_me_time, new Date().getTime() + 2000);
        });
    };
}());

exports.dismiss_mute_confirmation = function () {
    var $container = $("#unmute_muted_topic_notification");
    if ($container) {
        $container.fadeOut(500).removeClass("show");
    }
};

exports.persist_mute = function (stream_id, topic_name) {
    var data = {
        stream_id: stream_id,
        topic: topic_name,
        op: 'add',
    };
    last_topic_update = timestamp_ms();
    channel.patch({
        url: '/json/users/me/subscriptions/muted_topics',
        idempotent: true,
        data: data,
    });
};

exports.persist_unmute = function (stream_id, topic_name) {
    var data = {
        stream_id: stream_id,
        topic: topic_name,
        op: 'remove',
    };
    last_topic_update = timestamp_ms();
    channel.patch({
        url: '/json/users/me/subscriptions/muted_topics',
        idempotent: true,
        data: data,
    });
};

exports.handle_updates = function (muted_topics) {
    if (timestamp_ms() < last_topic_update + 1000) {
        // This topic update is either the one that we just rendered, or,
        // much less likely, it's coming from another device and would probably
        // be overwriting this device's preferences with stale data.
        return;
    }

    exports.update_muted_topics(muted_topics);
    exports.rerender();
};

exports.update_muted_topics = function (muted_topics) {
    muting.set_muted_topics(muted_topics);
    unread_ui.update_unread_counts();
};

exports.set_up_muted_topics_ui = function (muted_topics) {
    var muted_topics_table = $("#muted_topics_table tbody");
    muted_topics_table.empty();
    _.each(muted_topics, function (tup) {
        var stream_id = tup[0];
        var topic = tup[1];

        var stream = stream_data.maybe_get_stream_name(stream_id);

        if (!stream) {
            blueslip.warn('Unknown stream_id in set_up_muted_topics_ui: ' + stream_id);
            return;
        }

        var template_data = {
            stream: stream,
            stream_id: stream_id,
            topic: topic,
        };

        var row = templates.render('muted_topic_ui_row', template_data);
        muted_topics_table.append(row);
    });
};

exports.mute = function (stream_id, topic) {
    stream_popover.hide_topic_popover();
    muting.add_muted_topic(stream_id, topic);
    unread_ui.update_unread_counts();
    exports.rerender();
    exports.persist_mute(stream_id, topic);
    exports.notify_with_undo_option(stream_id, topic);
    exports.set_up_muted_topics_ui(muting.get_muted_topics());
};

exports.unmute = function (stream_id, topic) {
    // we don't run a unmute_notify function because it isn't an issue as much
    // if someone accidentally unmutes a stream rather than if they mute it
    // and miss out on info.
    stream_popover.hide_topic_popover();
    muting.remove_muted_topic(stream_id, topic);
    unread_ui.update_unread_counts();
    exports.rerender();
    exports.persist_unmute(stream_id, topic);
    exports.set_up_muted_topics_ui(muting.get_muted_topics());
    exports.dismiss_mute_confirmation();
};

exports.toggle_mute = function (message) {
    var stream_id = message.stream_id;
    var topic = util.get_message_topic(message);

    if (muting.is_topic_muted(stream_id, topic)) {
        exports.unmute(stream_id, topic);
    } else if (message.type === 'stream') {
        exports.mute(stream_id, topic);
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = muting_ui;
}
window.muting_ui = muting_ui;
<|endoftext|>


<commit_before>/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity, Text, StyleSheet, View, TouchableOpacityPropTypes } from 'react-native';

import { getAdjustedStyle } from './utilities';
/**
 * Simple component to be used in conjunction with HeaderRow component.
 *
 * Renders a title and if passed, a sorting icon.
 *
 * @param {String}       title                 Text to display in the cell
 * @param {String}       columnKey             The key for the column the cell heads.
 * @param {Func}         onPressAction         Action for dispatching on press
 * @param {Func}         dispatch              Dispatcher to backing reducer
 * @param {ReactElement} SortAscComponent      Icon component for ascending sorting
 * @param {ReactElement} SortDescComponent     Icon component for descending sorting
 * @param {ReactElement} SortNeutralComponent  Icon component for neutral state, no sort.
 * @param {Object}       containerStyle        Style object for the wrapping Touchable or View.
 * @param {Object}       textStyle             Style object for the inner text component.
 * @param {Number}        width               Optional flex property to inject into styles.
 * @param {Bool}          isLastCell          Indicator for if this cell is the last
 *                                            in a row. Removing the borderRight if true.
 */
const HeaderCell = React.memo(
  ({
    title,
    columnKey,
    sortDirection,
    SortAscComponent,
    SortDescComponent,
    SortNeutralComponent,
    onPressAction,
    dispatch,
    sortable,
    containerStyle,
    textStyle,
    width,
    isLastCell,
    ...otherProps
  }) => {
    const onPress = () => {
      dispatch(onPressAction(columnKey));
    };

    const Icon = () => {
      switch (sortDirection) {
        case 'ASC': {
          return SortAscComponent;
        }
        case 'DESC': {
          return SortDescComponent;
        }
        default: {
          return SortNeutralComponent;
        }
      }
    };

    const Container = onPressAction ? TouchableOpacity : View;

    const internalContainerStyle = getAdjustedStyle(containerStyle, width, isLastCell);

    return (
      <Container style={internalContainerStyle} onPress={onPress} {...otherProps}>
        <Text style={textStyle}>{title}</Text>
        {sortable && <Icon />}
      </Container>
    );
  }
);

const defaultStyles = StyleSheet.create({
  containerStyle: {},
  textStyle: {},
});

HeaderCell.propTypes = {
  ...TouchableOpacityPropTypes,
  title: PropTypes.string.isRequired,
  columnKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  onPressAction: PropTypes.func,
  dispatch: PropTypes.func,
  sortDirection: PropTypes.oneOf(['ASC', 'DESC']),
  SortAscComponent: PropTypes.element,
  SortDescComponent: PropTypes.element,
  SortNeutralComponent: PropTypes.element,
  containerStyle: PropTypes.object,
  textStyle: PropTypes.object,
  width: PropTypes.number,
  sortable: PropTypes.bool,
  isLastCell: PropTypes.bool,
};

HeaderCell.defaultProps = {
  dispatch: null,
  onPressAction: null,
  sortDirection: null,
  SortAscComponent: null,
  SortDescComponent: null,
  SortNeutralComponent: null,
  containerStyle: defaultStyles.containerStyle,
  textStyle: defaultStyles.textStyle,
  sortable: false,
  width: 0,
  isLastCell: false,
};

export default HeaderCell;
<commit_msg>Add corrected HeaderCell docstring<commit_after>/* eslint-disable react/forbid-prop-types */
import React from 'react';
import PropTypes from 'prop-types';
import { TouchableOpacity, Text, StyleSheet, View, TouchableOpacityPropTypes } from 'react-native';

import { getAdjustedStyle } from './utilities';
/**
 * Simple component to be used in conjunction with HeaderRow component.
 *
 * Renders a title and if passed, a sorting icon.
 *
 * @param {String}       title                 Text to display in the cell
 * @param {String}       columnKey             The key for the column the cell heads.
 * @param {Func}         onPressAction         Action for dispatching on press
 * @param {Func}         dispatch              Dispatcher to backing reducer
 * @param {ReactElement} SortAscComponent      Icon component for ascending sorting
 * @param {ReactElement} SortDescComponent     Icon component for descending sorting
 * @param {ReactElement} SortNeutralComponent  Icon component for neutral state, no sort.
 * @param {Object}       containerStyle        Style object for the wrapping Touchable or View.
 * @param {Object}       textStyle             Style object for the inner Text component.
 * @param {Number}       width               Optional flex property to inject into styles.
 * @param {Bool}         isLastCell          Indicator for if this cell is the last
 *                                            in a row. Removing the borderRight if true.
 */
const HeaderCell = React.memo(
  ({
    title,
    columnKey,
    sortDirection,
    SortAscComponent,
    SortDescComponent,
    SortNeutralComponent,
    onPressAction,
    dispatch,
    sortable,
    containerStyle,
    textStyle,
    width,
    isLastCell,
    ...otherProps
  }) => {
    const onPress = () => {
      dispatch(onPressAction(columnKey));
    };

    const Icon = () => {
      switch (sortDirection) {
        case 'ASC': {
          return SortAscComponent;
        }
        case 'DESC': {
          return SortDescComponent;
        }
        default: {
          return SortNeutralComponent;
        }
      }
    };

    const Container = onPressAction ? TouchableOpacity : View;

    const internalContainerStyle = getAdjustedStyle(containerStyle, width, isLastCell);

    return (
      <Container style={internalContainerStyle} onPress={onPress} {...otherProps}>
        <Text style={textStyle}>{title}</Text>
        {sortable && <Icon />}
      </Container>
    );
  }
);

const defaultStyles = StyleSheet.create({
  containerStyle: {},
  textStyle: {},
});

HeaderCell.propTypes = {
  ...TouchableOpacityPropTypes,
  title: PropTypes.string.isRequired,
  columnKey: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
  onPressAction: PropTypes.func,
  dispatch: PropTypes.func,
  sortDirection: PropTypes.oneOf(['ASC', 'DESC']),
  SortAscComponent: PropTypes.element,
  SortDescComponent: PropTypes.element,
  SortNeutralComponent: PropTypes.element,
  containerStyle: PropTypes.object,
  textStyle: PropTypes.object,
  width: PropTypes.number,
  sortable: PropTypes.bool,
  isLastCell: PropTypes.bool,
};

HeaderCell.defaultProps = {
  dispatch: null,
  onPressAction: null,
  sortDirection: null,
  SortAscComponent: null,
  SortDescComponent: null,
  SortNeutralComponent: null,
  containerStyle: defaultStyles.containerStyle,
  textStyle: defaultStyles.textStyle,
  sortable: false,
  width: 0,
  isLastCell: false,
};

export default HeaderCell;
<|endoftext|>


<commit_before>// Controller for Official Revision application (applies for both server and client).

'use strict';

var assign               = require('es5-ext/object/assign')
  , hyphenToCamel        = require('es5-ext/string/#/hyphen-to-camel')
  , save                 = require('mano/utils/save')
  , normalizeOptions     = require('es5-ext/object/normalize-options')
  , commonController     = require('../user')
  , matchBusinessProcess = require('../utils/official-matcher');

module.exports = function (/*options*/) {
	var options    = normalizeOptions(arguments[0])
	  , stepName   = options.stepName || 'revision'
	  , matcher    = options.matcher || matchBusinessProcess
	  , controller = {};

	// Common controller - login and password change.
	assign(controller, commonController);

	// Approve revision.
	controller['revision/[0-9][a-z0-9]+/approve'] = {
		match: function (businessProcessId) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			return this.processingStep.revisionApprovalProgress === 1;
		},
		validate: Function.prototype,
		submit: function () {
			this.processingStep.processor = this.user;
			this.processingStep.officialStatus = 'approved';
		},
		redirectUrl: '/'
	};

	// Send for corrections
	controller['revision/[0-9][a-z0-9]+/return'] = {
		match: function (businessProcessId) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			return this.processingStep.sendBackStatusesProgress === 1 &&
				this.processingStep.revisionProgress === 1;
		},
		validate: Function.prototype,
		submit: function () {
			this.processingStep.processor = this.user;
			this.processingStep.officialStatus = 'sentBack';
		},
		redirectUrl: '/'
	};

	// Reject revision.
	controller['revision/[0-9][a-z0-9]+/reject'] = {
		match: function (businessProcessId) {
			return matcher.call(this, businessProcessId, stepName);
		},
		submit: function () {
			this.processingStep.processor = this.user;
			save.apply(this, arguments);
			this.processingStep.officialStatus = 'rejected';
		},
		redirectUrl: '/'
	};

	// Requirement upload revision.
	controller['revision-requirement-upload/[0-9][a-z0-9]+/[0-9a-z-]+'] = {
		match: function (businessProcessId, documentUniqueKey) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			documentUniqueKey = hyphenToCamel.call(documentUniqueKey);
			return this.processingStep.requirementUploads.processable.some(function (requirementUpload) {
				if (requirementUpload.document.uniqueKey === documentUniqueKey) {
					return true;
				}
			}, this);
		},
		formHtmlId: 'form-revision-requirement-upload'
	};

	// Payment receipt revision.
	controller['form-revision-payment-receipt-upload/[0-9][a-z0-9]+/[0-9a-z-]+'] = {
		match: function (businessProcessId, receiptKey) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			var paymentReceiptUpload =
				this.businessProcess.paymentReceiptUploads.map.get(hyphenToCamel.call(receiptKey));
			if (!paymentReceiptUpload) return false;

			return this.processingStep.paymentReceiptUploads.processable.has(paymentReceiptUpload);
		},
		formHtmlId: 'form-revision-payment-receipt-upload'
	};

	// Data forms revision.
	controller['revision-data-forms/[0-9][a-z0-9]+'] = {
		match: function (businessProcessId, receiptKey) {
			return matcher.call(this, businessProcessId, stepName);
		},
		redirectUrl: function () {
			return '/' + this.businessProcess.__id__ + '/data';
		},
		formHtmlId: 'form-revision-data-forms'
	};

	return controller;
};
<commit_msg>Remove obsolete redirectUrl<commit_after>// Controller for Official Revision application (applies for both server and client).

'use strict';

var assign               = require('es5-ext/object/assign')
  , hyphenToCamel        = require('es5-ext/string/#/hyphen-to-camel')
  , save                 = require('mano/utils/save')
  , normalizeOptions     = require('es5-ext/object/normalize-options')
  , commonController     = require('../user')
  , matchBusinessProcess = require('../utils/official-matcher');

module.exports = function (/*options*/) {
	var options    = normalizeOptions(arguments[0])
	  , stepName   = options.stepName || 'revision'
	  , matcher    = options.matcher || matchBusinessProcess
	  , controller = {};

	// Common controller - login and password change.
	assign(controller, commonController);

	// Approve revision.
	controller['revision/[0-9][a-z0-9]+/approve'] = {
		match: function (businessProcessId) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			return this.processingStep.revisionApprovalProgress === 1;
		},
		validate: Function.prototype,
		submit: function () {
			this.processingStep.processor = this.user;
			this.processingStep.officialStatus = 'approved';
		},
		redirectUrl: '/'
	};

	// Send for corrections
	controller['revision/[0-9][a-z0-9]+/return'] = {
		match: function (businessProcessId) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			return this.processingStep.sendBackStatusesProgress === 1 &&
				this.processingStep.revisionProgress === 1;
		},
		validate: Function.prototype,
		submit: function () {
			this.processingStep.processor = this.user;
			this.processingStep.officialStatus = 'sentBack';
		},
		redirectUrl: '/'
	};

	// Reject revision.
	controller['revision/[0-9][a-z0-9]+/reject'] = {
		match: function (businessProcessId) {
			return matcher.call(this, businessProcessId, stepName);
		},
		submit: function () {
			this.processingStep.processor = this.user;
			save.apply(this, arguments);
			this.processingStep.officialStatus = 'rejected';
		},
		redirectUrl: '/'
	};

	// Requirement upload revision.
	controller['revision-requirement-upload/[0-9][a-z0-9]+/[0-9a-z-]+'] = {
		match: function (businessProcessId, documentUniqueKey) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			documentUniqueKey = hyphenToCamel.call(documentUniqueKey);
			return this.processingStep.requirementUploads.processable.some(function (requirementUpload) {
				if (requirementUpload.document.uniqueKey === documentUniqueKey) {
					return true;
				}
			}, this);
		},
		formHtmlId: 'form-revision-requirement-upload'
	};

	// Payment receipt revision.
	controller['form-revision-payment-receipt-upload/[0-9][a-z0-9]+/[0-9a-z-]+'] = {
		match: function (businessProcessId, receiptKey) {
			if (!matcher.call(this, businessProcessId, stepName)) return false;

			var paymentReceiptUpload =
				this.businessProcess.paymentReceiptUploads.map.get(hyphenToCamel.call(receiptKey));
			if (!paymentReceiptUpload) return false;

			return this.processingStep.paymentReceiptUploads.processable.has(paymentReceiptUpload);
		},
		formHtmlId: 'form-revision-payment-receipt-upload'
	};

	// Data forms revision.
	controller['revision-data-forms/[0-9][a-z0-9]+'] = {
		match: function (businessProcessId, receiptKey) {
			return matcher.call(this, businessProcessId, stepName);
		},
		formHtmlId: 'form-revision-data-forms'
	};

	return controller;
};
<|endoftext|>


<commit_before>const React = require('react');
const ReactDOM = require('react-dom');
const utilities = require("../../../node_modules/simple-react-utilities/js/utilities.js");

import Filter from './filter.js';
import { Card } from './components/card.js';
import { CardGroup } from './components/card-group.js';
import { ShowHideButton } from './components/show-hide-button.js';

export class CardBook extends React.Component {
  /**
   * constructor for CardBook
   * @param  {object} props [element properties/attributes passed in at initialization]
   */
  constructor(props) {
    super(props);

    var sortedCardData = utilities.sortObjectsByProp(this.props.cardData, "name");

    this.state = {
      cards : sortedCardData,
      filters : []
    };

    this.resetState = this.resetState.bind(this);
    this.executeFilters = this.executeFilters.bind(this);
    this.startFilteringBy = this.startFilteringBy.bind(this);
    this.stopFilteringBy = this.stopFilteringBy.bind(this);
  }

  executeFilters(filters) {
    var _this = this;
    var cards = this.props.cardData;
    let filterArgs;

    for (let filter in filters) {
      filterArgs = filters[filter].filterArgs;

      if (filterArgs.length) {
        cards = filters[filter].filterFunc(filterArgs[0], cards); // run once to cut down to this filter

        for (let i = 1, l = filterArgs.length; i < l; i++) {
          cards = cards.concat(filters[filter].filterFunc(filterArgs[i],this.props.cardData)); // loop through cards to add back
        }
      }
    }

    cards = utilities.sortObjectsByProp(cards, "name");
    cards = utilities.arrayUnique(cards);

    if (!Array.isArray(cards)) {
      cards = [];
    }

    this.setState({
      cards : cards,
      filters : this.state.filters
    });
  }

  startFilteringBy(filterName,filterObject) {
    let filters = this.state.filters;
    filters[filterName] = filters[filterName] || {};
    filters[filterName].filterArgs = filters[filterName].filterArgs || [];

    // add the filter args and update the filter function
    filters[filterName].filterArgs.push(filterObject.filterArgs);
    filters[filterName].filterFunc = filterObject.filterFunc;

    // TODO: workaround for search filter
    if (filterName === 'search') {

      filters[filterName].filterArgs = [filterObject.filterArgs];
    }

    // save
    this.setState({
      cards : [],
      filters : filters[filterName]
    });

    // update
    this.executeFilters(this.state.filters);
  }

  stopFilteringBy(filterName,filterObject) {
    let filters = this.state.filters;
    let i = 0;

    filters[filterName] = filters[filterName] || {};
    filters[filterName].filterArgs = filters[filterName].filterArgs || [];

    // remove the filter args
    filters[filterName].filterArgs.forEach((filterArg) => {
      if (filterArg === filterObject.filterArgs) {
        filters[filterName].filterArgs.splice(i, 1);
      }
      i++;
    });

    // save
    this.setState(Object.assign({}, this.state, {
      filters : filters[filterName]
    }));

    // update
    this.executeFilters(this.state.filters);
  }

  resetState() {
    var sortedCardData = utilities.sortObjectsByProp(this.props.cardData, "name");

    this.setState({
      cards : sortedCardData,
      filters : []
    });
  }

  componentDidMount() {
    this.updateHeight();
  }

  componentDidUpdate() {
    this.updateHeight();
  }

  updateHeight() {
    let cardContainer = document.querySelector('.card-container');
    cardContainer.style.height = 'auto';
    let currentHeight = cardContainer.offsetHeight;
    let newHeight = Math.ceil(currentHeight/3) + 350;
    cardContainer.style.height = newHeight+'px';

    console.log(currentHeight);
    console.log(newHeight);
  }

  /**
   * puts everything in the DOM
   */
  render() {
    let i = 0;
    let j = 0;

    return

{this.props.label} ({this.state.cards.length})

                  {this.props.searchFilter(this.startFilteringBy, this.stopFilteringBy)}

                    {this.props.filters.map((renderFilterButtons) => {
                      i++;
                      return
{renderFilterButtons(this.startFilteringBy, this.stopFilteringBy)}
;
                    })}

Advanced Filters<ShowHideButton target={".advanced-filters"} showText="+" hideText="-" startClosed="true"/>

                    {this.props.advancedFilters.map((renderFilterButtons) => {
                      j++;
                      return
{renderFilterButtons(this.startFilteringBy, this.stopFilteringBy)}
;
                    })}

                    <CardGroup cards={this.state.cards} />

;
  }
}
<commit_msg>fix columns for non-desktop devices<commit_after>const React = require('react');
const ReactDOM = require('react-dom');
const utilities = require("../../../node_modules/simple-react-utilities/js/utilities.js");

import Filter from './filter.js';
import { Card } from './components/card.js';
import { CardGroup } from './components/card-group.js';
import { ShowHideButton } from './components/show-hide-button.js';

export class CardBook extends React.Component {
  /**
   * constructor for CardBook
   * @param  {object} props [element properties/attributes passed in at initialization]
   */
  constructor(props) {
    super(props);

    var sortedCardData = utilities.sortObjectsByProp(this.props.cardData, "name");

    this.state = {
      cards : sortedCardData,
      filters : []
    };

    this.resetState = this.resetState.bind(this);
    this.executeFilters = this.executeFilters.bind(this);
    this.startFilteringBy = this.startFilteringBy.bind(this);
    this.stopFilteringBy = this.stopFilteringBy.bind(this);
  }

  executeFilters(filters) {
    var _this = this;
    var cards = this.props.cardData;
    let filterArgs;

    for (let filter in filters) {
      filterArgs = filters[filter].filterArgs;

      if (filterArgs.length) {
        cards = filters[filter].filterFunc(filterArgs[0], cards); // run once to cut down to this filter

        for (let i = 1, l = filterArgs.length; i < l; i++) {
          cards = cards.concat(filters[filter].filterFunc(filterArgs[i],this.props.cardData)); // loop through cards to add back
        }
      }
    }

    cards = utilities.sortObjectsByProp(cards, "name");
    cards = utilities.arrayUnique(cards);

    if (!Array.isArray(cards)) {
      cards = [];
    }

    this.setState({
      cards : cards,
      filters : this.state.filters
    });
  }

  startFilteringBy(filterName,filterObject) {
    let filters = this.state.filters;
    filters[filterName] = filters[filterName] || {};
    filters[filterName].filterArgs = filters[filterName].filterArgs || [];

    // add the filter args and update the filter function
    filters[filterName].filterArgs.push(filterObject.filterArgs);
    filters[filterName].filterFunc = filterObject.filterFunc;

    // TODO: workaround for search filter
    if (filterName === 'search') {

      filters[filterName].filterArgs = [filterObject.filterArgs];
    }

    // save
    this.setState({
      cards : [],
      filters : filters[filterName]
    });

    // update
    this.executeFilters(this.state.filters);
  }

  stopFilteringBy(filterName,filterObject) {
    let filters = this.state.filters;
    let i = 0;

    filters[filterName] = filters[filterName] || {};
    filters[filterName].filterArgs = filters[filterName].filterArgs || [];

    // remove the filter args
    filters[filterName].filterArgs.forEach((filterArg) => {
      if (filterArg === filterObject.filterArgs) {
        filters[filterName].filterArgs.splice(i, 1);
      }
      i++;
    });

    // save
    this.setState(Object.assign({}, this.state, {
      filters : filters[filterName]
    }));

    // update
    this.executeFilters(this.state.filters);
  }

  resetState() {
    var sortedCardData = utilities.sortObjectsByProp(this.props.cardData, "name");

    this.setState({
      cards : sortedCardData,
      filters : []
    });
  }

  componentDidMount() {
    let timeout;
    this.updateHeight();

    function throttled() {
      clearTimeout(timeout);
      timeout = setTimeout(this.updateHeight, 0);
    }

    window.addEventListener("resize", throttled);
  }

  componentDidUpdate() {
    this.updateHeight();
  }

  updateHeight() {
    let cardContainer = document.querySelector('.card-container');
    cardContainer.style.height = 'auto';
    let currentHeight = cardContainer.offsetHeight;
    let denominator = 3;

    if (window.innerWidth < 920) {
      denominator = 2;
    }

    let newHeight = Math.ceil(currentHeight/denominator) + 350;
    cardContainer.style.height = newHeight+'px';

    console.log(currentHeight);
    console.log(newHeight);
  }

  /**
   * puts everything in the DOM
   */
  render() {
    let i = 0;
    let j = 0;

    return

{this.props.label} ({this.state.cards.length})

                  {this.props.searchFilter(this.startFilteringBy, this.stopFilteringBy)}

                    {this.props.filters.map((renderFilterButtons) => {
                      i++;
                      return
{renderFilterButtons(this.startFilteringBy, this.stopFilteringBy)}
;
                    })}

Advanced Filters<ShowHideButton target={".advanced-filters"} showText="+" hideText="-" startClosed="true"/>

                    {this.props.advancedFilters.map((renderFilterButtons) => {
                      j++;
                      return
{renderFilterButtons(this.startFilteringBy, this.stopFilteringBy)}
;
                    })}

                    <CardGroup cards={this.state.cards} />

;
  }
}
<|endoftext|>


<commit_before><commit_msg>Update LocationManager.js<commit_after><|endoftext|>


<commit_before>var test = require('tape')

var GraphArray = require('../')
var Observ = require('observ')
var ObservStruct = require('observ-struct')

var getTypes (types) {
  return function (raw) {
    return types[raw.type]
  }
}

test('type creation and update by .set()', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = Observ()
        obs.type = 'Test'
        return obs
      },
      AnotherNode: function(context){
        var obs = Observ()
        obs.type = 'AnotherNode'
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', value: 'foo' }
  ])

  var obj = obs.get(0)
  t.equal(obj.type, 'Test')
  t.deepEqual(obj(), { node: 'Test', value: 'foo' })

  obs.set([
    { node: 'Test', value: 'bar' }
  ])

  // make sure the object was not regenerated
  var obj2 = obs.get(0)
  t.equal(obj, obj2)

  var destroyed = false
  obj2.destroy = function(){
    destroyed = true
  }

  obs.set([
    { node: 'AnotherNode', value: 'bar' }
  ])

  t.ok(destroyed, 'destroy called on object')

  // make sure the object was regenerated
  var obj3 = obs.get(0)
  t.notEqual(obj2, obj3)
  t.equal(obj3.type, 'AnotherNode')

  var destroyed = false
  obj3.destroy = function(){
    destroyed = true
  }

  obs.set([])
  t.ok(destroyed, 'destroy called on object')

  t.end()
})

test('type add / remove by .set()', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Foo: function(context){
        var obs = Observ()
        obs.type = 'Foo'
        return obs
      },
      Bar: function(context){
        var obs = Observ()
        obs.type = 'Bar'
        return obs
      }
    })
  })

  var changes = []
  obs.onUpdate(function(change){
    changes.push(change)
  })

  obs.set([
    {node: 'Foo', value: 123},
    {node: 'Bar', value: 456}
  ])

  t.equal(obs.getLength(), 2)
  t.equal(obs.get(0).type, 'Foo')
  t.equal(obs.get(1).type, 'Bar')

  // check updates
  t.equal(changes.length, 1)
  t.equal(changes[0].length, 2+2)
  t.deepEqual(changes[0].slice(0,2), [0, 0])
  t.equal(changes[0][2], obs.get(0)); t.equal(changes[0][3], obs.get(1))
  changes.length = 0

  obs.set([
    {node: 'Foo', value: 123},
    {node: 'Bar', value: 456},
    {node: 'Bar', value: 789},
  ])

  t.equal(obs.getLength(), 3)
  t.equal(obs.get(2).type, 'Bar')

  // check updates
  t.equal(changes.length, 1)
  t.equal(changes[0].length, 2+1)
  t.deepEqual(changes[0].slice(0,2), [2, 0])
  t.equal(changes[0][2], obs.get(2))
  changes.length = 0

  obs.set([
    {node: 'Bar', value: 456},
    {node: 'Bar', value: 789},
  ])

  t.equal(obs.getLength(), 2)

  // check updates
  t.equal(changes.length, 2)
  t.equal(changes[0].length, 2+1)
  t.deepEqual(changes[0].slice(0,2), [0, 1])
  t.equal(changes[0][2], obs.get(0))
  t.deepEqual(changes[1], [1, 1])

  t.end()
})

test('setting type updates parent state', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = ObservStruct({
          value: Observ()
        })
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', value: 'foo' }
  ])

  var obj = obs.get(0)
  obj.value.set('bar')

  t.deepEqual(obs(), [{ node: 'Test', value: 'bar' }])

  t.end()
})

test('move a type by reference', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  var obj1 = obs.get(0)
  var obj2 = obs.get(1)
  var obj3 = obs.get(2)

  obs.move(obj2, 0)

  t.deepEqual(obs(), [
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  t.equal(obs.get(0), obj2)

  obs.move(obj1, 2)

  t.deepEqual(obs(), [
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' },
    { node: 'Test', id: '1', value: 'foo' }
  ])

  t.equal(obs.get(2), obj1)
  t.equal(obs.get(1), obj3)

  t.end()

})

test('push and insert a type by descriptor', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  var obj1 = obs.get(0)
  var obj2 = obs.get(1)
  var obj3 = obs.get(2)

  obs.insert({ node: 'Test', id: '4', value: 'foobar'}, 1)

  t.deepEqual(obs(), [
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '4', value: 'foobar'},
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  obs.push({ node: 'Test', id: '5', value: 'foobaz'})

  t.deepEqual(obs(), [
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '4', value: 'foobar'},
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' },
    { node: 'Test', id: '5', value: 'foobaz'}
  ])

  t.deepEqual(obs.get(1)(), { node: 'Test', id: '4', value: 'foobar'})
  t.deepEqual(obs.get(4)(), { node: 'Test', id: '5', value: 'foobaz'})

  t.end()
})

test('change type from child', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Foo: function Foo(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })

        obs.type = 'Foo'

        return obs
      },

      Bar: function Bar(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })

        obs.type = 'Bar'

        return obs
      }
    })
  })

  obs.set([ { node: 'Foo', id: 'test', value: 456 } ])

  var obj = obs.get(0)
  t.equal(obj.type, 'Foo')

  obj.set({ node: 'Bar', id: 'test', value: 456 })

  var obj2 = obs.get(0)
  t.equal(obj2.value(), 456)
  t.equal(obj2.type, 'Bar')

  obj2.set({ node: 'Foo', id: 'test', value: 456 })

  var obj3 = obs.get(0)
  t.equal(obj3.type, 'Foo')

  t.end()
})
<commit_msg>s/getLength/size<commit_after>var test = require('tape')

var GraphArray = require('../')
var Observ = require('observ')
var ObservStruct = require('observ-struct')

var getTypes (types) {
  return function (raw) {
    return types[raw.type]
  }
}

test('type creation and update by .set()', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = Observ()
        obs.type = 'Test'
        return obs
      },
      AnotherNode: function(context){
        var obs = Observ()
        obs.type = 'AnotherNode'
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', value: 'foo' }
  ])

  var obj = obs.get(0)
  t.equal(obj.type, 'Test')
  t.deepEqual(obj(), { node: 'Test', value: 'foo' })

  obs.set([
    { node: 'Test', value: 'bar' }
  ])

  // make sure the object was not regenerated
  var obj2 = obs.get(0)
  t.equal(obj, obj2)

  var destroyed = false
  obj2.destroy = function(){
    destroyed = true
  }

  obs.set([
    { node: 'AnotherNode', value: 'bar' }
  ])

  t.ok(destroyed, 'destroy called on object')

  // make sure the object was regenerated
  var obj3 = obs.get(0)
  t.notEqual(obj2, obj3)
  t.equal(obj3.type, 'AnotherNode')

  var destroyed = false
  obj3.destroy = function(){
    destroyed = true
  }

  obs.set([])
  t.ok(destroyed, 'destroy called on object')

  t.end()
})

test('type add / remove by .set()', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Foo: function(context){
        var obs = Observ()
        obs.type = 'Foo'
        return obs
      },
      Bar: function(context){
        var obs = Observ()
        obs.type = 'Bar'
        return obs
      }
    })
  })

  var changes = []
  obs.onUpdate(function(change){
    changes.push(change)
  })

  obs.set([
    {node: 'Foo', value: 123},
    {node: 'Bar', value: 456}
  ])

  t.equal(obs.size(), 2)
  t.equal(obs.get(0).type, 'Foo')
  t.equal(obs.get(1).type, 'Bar')

  // check updates
  t.equal(changes.length, 1)
  t.equal(changes[0].length, 2+2)
  t.deepEqual(changes[0].slice(0,2), [0, 0])
  t.equal(changes[0][2], obs.get(0)); t.equal(changes[0][3], obs.get(1))
  changes.length = 0

  obs.set([
    {node: 'Foo', value: 123},
    {node: 'Bar', value: 456},
    {node: 'Bar', value: 789},
  ])

  t.equal(obs.size(), 3)
  t.equal(obs.get(2).type, 'Bar')

  // check updates
  t.equal(changes.length, 1)
  t.equal(changes[0].length, 2+1)
  t.deepEqual(changes[0].slice(0,2), [2, 0])
  t.equal(changes[0][2], obs.get(2))
  changes.length = 0

  obs.set([
    {node: 'Bar', value: 456},
    {node: 'Bar', value: 789},
  ])

  t.equal(obs.size(), 2)

  // check updates
  t.equal(changes.length, 2)
  t.equal(changes[0].length, 2+1)
  t.deepEqual(changes[0].slice(0,2), [0, 1])
  t.equal(changes[0][2], obs.get(0))
  t.deepEqual(changes[1], [1, 1])

  t.end()
})

test('setting type updates parent state', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = ObservStruct({
          value: Observ()
        })
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', value: 'foo' }
  ])

  var obj = obs.get(0)
  obj.value.set('bar')

  t.deepEqual(obs(), [{ node: 'Test', value: 'bar' }])

  t.end()
})

test('move a type by reference', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  var obj1 = obs.get(0)
  var obj2 = obs.get(1)
  var obj3 = obs.get(2)

  obs.move(obj2, 0)

  t.deepEqual(obs(), [
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  t.equal(obs.get(0), obj2)

  obs.move(obj1, 2)

  t.deepEqual(obs(), [
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' },
    { node: 'Test', id: '1', value: 'foo' }
  ])

  t.equal(obs.get(2), obj1)
  t.equal(obs.get(1), obj3)

  t.end()

})

test('push and insert a type by descriptor', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Test: function(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })
        return obs
      }
    })
  })

  obs.set([
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  var obj1 = obs.get(0)
  var obj2 = obs.get(1)
  var obj3 = obs.get(2)

  obs.insert({ node: 'Test', id: '4', value: 'foobar'}, 1)

  t.deepEqual(obs(), [
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '4', value: 'foobar'},
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' }
  ])

  obs.push({ node: 'Test', id: '5', value: 'foobaz'})

  t.deepEqual(obs(), [
    { node: 'Test', id: '1', value: 'foo' },
    { node: 'Test', id: '4', value: 'foobar'},
    { node: 'Test', id: '2', value: 'bar' },
    { node: 'Test', id: '3', value: 'baz' },
    { node: 'Test', id: '5', value: 'foobaz'}
  ])

  t.deepEqual(obs.get(1)(), { node: 'Test', id: '4', value: 'foobar'})
  t.deepEqual(obs.get(4)(), { node: 'Test', id: '5', value: 'foobaz'})

  t.end()
})

test('change type from child', function(t){

  var obs = GraphArray({
    getType: getTypes({
      Foo: function Foo(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })

        obs.type = 'Foo'

        return obs
      },

      Bar: function Bar(context){
        var obs = ObservStruct({
          id: Observ(),
          value: Observ()
        })

        obs.type = 'Bar'

        return obs
      }
    })
  })

  obs.set([ { node: 'Foo', id: 'test', value: 456 } ])

  var obj = obs.get(0)
  t.equal(obj.type, 'Foo')

  obj.set({ node: 'Bar', id: 'test', value: 456 })

  var obj2 = obs.get(0)
  t.equal(obj2.value(), 456)
  t.equal(obj2.type, 'Bar')

  obj2.set({ node: 'Foo', id: 'test', value: 456 })

  var obj3 = obs.get(0)
  t.equal(obj3.type, 'Foo')

  t.end()
})
<|endoftext|>


<commit_before>var $ = require('jquery');
var _ = require('underscore');
var cdb = require('cartodb.js');
var template = require('./widget-dropdown-template.tpl');

/**
 * Standard widget dropdown view
 *
 */
module.exports = cdb.core.View.extend({
  className: 'CDB-Dropdown',

  events: {
    'click .js-pin': '_pin',
    'click .js-toggle': '_toggle',
    'click .js-delete': '_delete'
  },

  initialize: function (opts) {
    if (!opts.target) {
      throw new Error('target is not defined');
    }

    this.viewModel = new cdb.core.Model({ open: false });

    this._$target = this.options.target;
    this._$parent = this.options.parent;
    this._initBinds();
  },

  render: function () {
    this._bindESC();
    this._bindGlobalClick();

    this.$el.html(
      template()
    );

    return this;
  },

  _initBinds: function () {
    this.add_related_model(this.viewModel);

    this.viewModel.bind('change:open', this._onChangeOpen, this);

    this._$target.click(
      _.bind(this._toggleClick, this)
    );
  },

  _bindGlobalClick: function () {
    $(document).bind('click.' + this.cid,_.bind(this._onGlobalClick, this));
  },

  _unbindGlobalClick: function () {
    $(document).unbind('click.' + this.cid);
  },

  _bindESC: function () {
    $(document).bind('keyup.' + this.cid, _.bind(this._onKeyUp, this));
  },

  _unbindESC: function () {
    $(document).unbind('keyup.' + this.cid);
  },

  _onGlobalClick: function (ev) {
    if (this._$target.get(0) === ev.target) {
    } else {
      this.viewModel.set('open', false);
    }
  },

  _onKeyUp: function (ev) {
    if (ev.keyCode === 27) {
      this.viewModel.set('open', false);
      return false;
    }
  },

  _onChangeOpen: function() {
    if (this.viewModel.get('open')) {
      this._open();
    } else {
      this._close();
    }
  },

  _delete: function() {
    this.viewModel.set('open', false);
    this.trigger('click', 'delete');
  },

  _pin: function() {
    this.trigger('click', 'pin');
    this.viewModel.set('open', false);
  },

  _toggle: function() {
    this.viewModel.set('open', false);
    this.trigger('click', 'toggle');
  },

  _open: function() {
    this.render();
    this._$parent.append(this.$el);
    this.$el.show();
  },

  _close: function() {
    this.$el.hide();
    this._unbindGlobalClick();
  },

  _toggleClick: function() {
    this.viewModel.set('open', !this.viewModel.get('open'));
  },

  clean: function () {
    this._unbindESC();
    this._unbindGlobalClick();
    this._$target.off('click');
    cdb.core.View.prototype.clean.call(this);
  }

});
<commit_msg>Refactor method<commit_after>var $ = require('jquery');
var _ = require('underscore');
var cdb = require('cartodb.js');
var template = require('./widget-dropdown-template.tpl');

/**
 * Standard widget dropdown view
 *
 */
module.exports = cdb.core.View.extend({
  className: 'CDB-Dropdown',

  events: {
    'click .js-pin': '_pin',
    'click .js-toggle': '_toggle',
    'click .js-delete': '_delete'
  },

  initialize: function (opts) {
    if (!opts.target) {
      throw new Error('target is not defined');
    }

    this.viewModel = new cdb.core.Model({ open: false });

    this._$target = this.options.target;
    this._$parent = this.options.parent;
    this._initBinds();
  },

  render: function () {
    this._bindESC();
    this._bindGlobalClick();

    this.$el.html(
      template()
    );

    return this;
  },

  _initBinds: function () {
    this.add_related_model(this.viewModel);

    this.viewModel.bind('change:open', this._onChangeOpen, this);

    this._$target.click(
      _.bind(this._toggleClick, this)
    );
  },

  _bindGlobalClick: function () {
    $(document).bind('click.' + this.cid,_.bind(this._onGlobalClick, this));
  },

  _unbindGlobalClick: function () {
    $(document).unbind('click.' + this.cid);
  },

  _bindESC: function () {
    $(document).bind('keyup.' + this.cid, _.bind(this._onKeyUp, this));
  },

  _unbindESC: function () {
    $(document).unbind('keyup.' + this.cid);
  },

  _onGlobalClick: function (ev) {
    if (this._$target.get(0) !== $(ev.target).closest(this._$target).get(0)) {
      this.viewModel.set('open', false);
    }
  },

  _onKeyUp: function (ev) {
    if (ev.keyCode === 27) {
      this.viewModel.set('open', false);
      return false;
    }
  },

  _onChangeOpen: function() {
    if (this.viewModel.get('open')) {
      this._open();
    } else {
      this._close();
    }
  },

  _delete: function() {
    this.viewModel.set('open', false);
    this.trigger('click', 'delete');
  },

  _pin: function() {
    this.trigger('click', 'pin');
    this.viewModel.set('open', false);
  },

  _toggle: function() {
    this.viewModel.set('open', false);
    this.trigger('click', 'toggle');
  },

  _open: function() {
    this.render();
    this._$parent.append(this.$el);
    this.$el.show();
  },

  _close: function() {
    this.$el.hide();
    this._unbindGlobalClick();
  },

  _toggleClick: function() {
    this.viewModel.set('open', !this.viewModel.get('open'));
  },

  clean: function () {
    this._unbindESC();
    this._unbindGlobalClick();
    this._$target.off('click');
    cdb.core.View.prototype.clean.call(this);
  }

});
<|endoftext|>


<commit_before>(function (){
    function initMCE() {
      tinyMCE.init({
      	mode : "textareas",
      	width : "800",
      	height : "600",
      	theme : "advanced",
      	theme_advanced_toolbar_location : "top",
      	theme_advanced_toolbar_align : "left",
      	theme_advanced_buttons1 : "fullscreen,separator,preview,separator,bold,italic,underline,strikethrough,separator,bullist,numlist,outdent,indent,separator,undo,redo,separator,link,unlink,anchor,separator,image,cleanup,help,separator,code",
      	theme_advanced_buttons2 : "",
      	theme_advanced_buttons3 : "",
      	auto_cleanup_word : true,
      	relative_urls : false,
      	plugins : "table,save,advhr,advimage,advlink,emotions,iespell,insertdatetime,preview,zoom,flash,searchreplace,print,contextmenu,fullscreen",
      	plugin_insertdate_dateFormat : "%m/%d/%Y",
      	plugin_insertdate_timeFormat : "%H:%M:%S",
      	extended_valid_elements : "a[name|href|target=_blank|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
      	fullscreen_settings : {
      		theme_advanced_path_location : "top",
      		theme_advanced_buttons1 : "fullscreen,separator,preview,separator,cut,copy,paste,separator,undo,redo,separator,search,replace,separator,code,separator,cleanup,separator,bold,italic,underline,strikethrough,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,help",
      		theme_advanced_buttons2 : "removeformat,styleselect,formatselect,fontselect,fontsizeselect,separator,bullist,numlist,outdent,indent,separator,link,unlink,anchor",
      		theme_advanced_buttons3 : "sub,sup,separator,image,insertdate,inserttime,separator,tablecontrols,separator,hr,advhr,visualaid,separator,charmap,emotions,iespell,flash,separator,print"
      	}
      });
    }

    initMCE();
})();<commit_msg>Updated Tiny MCE config to used dali_advimage plugin.<commit_after>(function (){
    function initMCE() {
      tinyMCE.init({
      	mode : "textareas",
      	width : "800",
      	height : "600",
      	theme : "advanced",
      	theme_advanced_toolbar_location : "top",
      	theme_advanced_toolbar_align : "left",
      	theme_advanced_buttons1 : "fullscreen,separator,preview,separator,bold,italic,underline,strikethrough,separator,bullist,numlist,outdent,indent,separator,undo,redo,separator,link,unlink,anchor,separator,image,cleanup,help,separator,code",
      	theme_advanced_buttons2 : "",
      	theme_advanced_buttons3 : "",
      	auto_cleanup_word : true,
      	relative_urls : false,
      	plugins : "table,save,advhr,dali_advimage,advlink,emotions,iespell,insertdatetime,preview,zoom,flash,searchreplace,print,contextmenu,fullscreen",
      	plugin_insertdate_dateFormat : "%m/%d/%Y",
      	plugin_insertdate_timeFormat : "%H:%M:%S",
      	extended_valid_elements : "a[name|href|target=_blank|title|onclick],img[class|src|border=0|alt|title|hspace|vspace|width|height|align|onmouseover|onmouseout|name],hr[class|width|size|noshade],font[face|size|color|style],span[class|align|style]",
      	fullscreen_settings : {
      		theme_advanced_path_location : "top",
      		theme_advanced_buttons1 : "fullscreen,separator,preview,separator,cut,copy,paste,separator,undo,redo,separator,search,replace,separator,code,separator,cleanup,separator,bold,italic,underline,strikethrough,separator,forecolor,backcolor,separator,justifyleft,justifycenter,justifyright,justifyfull,separator,help",
      		theme_advanced_buttons2 : "removeformat,styleselect,formatselect,fontselect,fontsizeselect,separator,bullist,numlist,outdent,indent,separator,link,unlink,anchor",
      		theme_advanced_buttons3 : "sub,sup,separator,image,insertdate,inserttime,separator,tablecontrols,separator,hr,advhr,visualaid,separator,charmap,emotions,iespell,flash,separator,print"
      	}
      });
    }

    initMCE();
})();<|endoftext|>


<commit_before>
var express = require('express');
var http = require('http');
var path = require('path');
var favicon = require('serve-favicon');
var methodOverride = require('method-override');
var session = require('express-session');
var bodyParser = require('body-parser');
var qs = require('querystring');
var multer = require('multer');
var flash = require('connect-flash');
var cookieParser = require('cookie-parser');
var log4js = require('log4js');

var errorHandler = require('errorhandler');
var serveStatic = require('serve-static');
var mongoStore = require('connect-mongo')(session);
var settings = require('./settings');
var cfg = {
//  logLevel:'DEBUG', // TODO add log control
  'ligle-model':{
    upDir:'./public/images/upload/',
    staticDir:'/images/upload/'
  },
  'ligle-db': {
    db: 'ligleEngine',
    host: '127.0.0.1',
    port: 27017
  },
  'ligle-routes': {
  }
};

var ligle = require('ligle-engine')(cfg);

var logger = ligle.util.logger('normal','DEBUG');
// export something to use for other modules
exports.ligle = ligle;
exports.getLogger = ligle.util.logger;

var UPDIR = settings.uploadPath;

// wrap app into callback, so that we can do something before we
// start. such as: open database

ligle.start(function(){
  var app = express();

  // all environments
  app.set('port', process.env.PORT || settings.port);
  app.set('views', path.join(__dirname, 'views'));
  app.set('view engine', 'ejs');

  app.use(favicon(settings.faviconPath ? __dirname + '/public/images/favicon.ico' : ''));
  app.use(methodOverride());
  app.use(log4js.connectLogger(logger, {level:log4js.levels.INFO}));
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: false }));// false to use querystring
  app.use(multer({ dest: UPDIR}));
  app.use(cookieParser(settings.cookieSecret));
  app.use(session({
	  secret: settings.cookieSecret,
	  name: settings.db,
	  cookie: {maxAge: settings.cookieLife},
	  store: new mongoStore({db: settings.db}),
    resave: false,
    saveUninitialized: false
  }));
  app.use(flash()); // used to save message into req temporarily

  // new framework

  // engine里面的服务，并没有完成，因此先不要使用，先自己开发。
  // var globalService = ligle.service;
  // app.use(globalService.basic);

  // 自定义的服务。

  // 这里的语句不能放在文件开头，因为services也依赖app.js。（好好思索一
  // 下，为什么必须放在这里，以及模块互相依赖的时候，是如何加载的）
  var localService = require('./services');
  for(var s  in localService){
    logger.debug('adding routes:',s);
    app.use(localService[s]);
  }

  app.use(serveStatic(path.join(__dirname, 'public')));

  app.use(function(req,res){
	  res.render('error');
  });

  // development only
  var env = process.env.NODE_ENV || 'development';
  if ('development' == env) {
    // configure stuff here
    app.use(errorHandler());
  }

  http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
  });
});

<commit_msg>关闭一些引擎底层的log。<commit_after>
var express = require('express');
var http = require('http');
var path = require('path');
var favicon = require('serve-favicon');
var methodOverride = require('method-override');
var session = require('express-session');
var bodyParser = require('body-parser');
var qs = require('querystring');
var multer = require('multer');
var flash = require('connect-flash');
var cookieParser = require('cookie-parser');
var log4js = require('log4js');

var errorHandler = require('errorhandler');
var serveStatic = require('serve-static');
var mongoStore = require('connect-mongo')(session);
var settings = require('./settings');
var cfg = {
//  logLevel:'DEBUG', // TODO add log control
  'ligle-model':{
    upDir:'./public/images/upload/',
    staticDir:'/images/upload/'
  },
  'ligle-db': {
    db: 'ligleEngine',
    host: '127.0.0.1',
    port: 27017
  },
  'ligle-routes': {
  }
};

var ligle = require('ligle-engine')(cfg);

var logger = ligle.util.logger('normal','INFO');
// export something to use for other modules
exports.ligle = ligle;
var getLogger = exports.getLogger = ligle.util.logger;

// to suppress the verbose log
getLogger('ligle-base','INFO');
getLogger('ligle-middware','INFO');
getLogger('ligle-routes','INFO');
getLogger('ligle-model','INFO');
getLogger('ligle-db','INFO');

var UPDIR = settings.uploadPath;

// wrap app into callback, so that we can do something before we
// start. such as: open database

ligle.start(function(){
  var app = express();

  // all environments
  app.set('port', process.env.PORT || settings.port);
  app.set('views', path.join(__dirname, 'views'));
  app.set('view engine', 'ejs');

  app.use(favicon(settings.faviconPath ? __dirname + '/public/images/favicon.ico' : ''));
  app.use(methodOverride());
  app.use(log4js.connectLogger(logger, {level:log4js.levels.INFO}));
  app.use(bodyParser.json());
  app.use(bodyParser.urlencoded({ extended: false }));// false to use querystring
  app.use(multer({ dest: UPDIR}));
  app.use(cookieParser(settings.cookieSecret));
  app.use(session({
	  secret: settings.cookieSecret,
	  name: settings.db,
	  cookie: {maxAge: settings.cookieLife},
	  store: new mongoStore({db: settings.db}),
    resave: false,
    saveUninitialized: false
  }));
  app.use(flash()); // used to save message into req temporarily

  // new framework

  // engine里面的服务，并没有完成，因此先不要使用，先自己开发。
  // var globalService = ligle.service;
  // app.use(globalService.basic);

  // 自定义的服务。

  // 这里的语句不能放在文件开头，因为services也依赖app.js。（好好思索一
  // 下，为什么必须放在这里，以及模块互相依赖的时候，是如何加载的）
  var localService = require('./services');
  for(var s  in localService){
    logger.debug('adding routes:',s);
    app.use(localService[s]);
  }

  app.use(serveStatic(path.join(__dirname, 'public')));

  app.use(function(req,res){
	  res.render('error');
  });

  // development only
  var env = process.env.NODE_ENV || 'development';
  if ('development' == env) {
    // configure stuff here
    app.use(errorHandler());
  }

  http.createServer(app).listen(app.get('port'), function(){
    console.log('Express server listening on port ' + app.get('port'));
  });
});

<|endoftext|>


<commit_before>IONUX.Models.EditableResource = Backbone.Model.extend({
  idAttribute: '_id',
  schema: function(){
    return this.make_schema();
  },
  initialize: function(){},
  url: function(){
    return window.location.pathname.replace(/edit$/,'');
  },
  make_schema: function(){
    var self = this;
    var schema = {};
    _.each(this.attributes, function(value, key){
      if (!_.isObject(value) && !(key=='ts_updated' || key=='ts_created')){
        console.log(key, value, typeof value);
        switch(typeof(value)){
          case 'boolean':
            schema[key] = 'Checkbox';
            break;
          case 'number':
            schema[key] = 'Number';
            break;
          default:
            schema[key] = 'Text'
        };
      };
    });
    return schema;
  },
});

IONUX.Models.Search = Backbone.Model.extend();

IONUX.Models.Search = Backbone.Model.extend({
    url: function(){
        return "/search/?query="+this.get("search_query");
    },
    parse: function(resp){
        make_iso_timestamps(resp);
        return resp.data;
    }
});

// For use with collections of Resource Types, i.e. InstrumentDevice, PlatformDevice, etc.
IONUX.Models.Session = Backbone.Model.extend({
    defaults: {
        actor_id: null,
        user_id: null,
        name: "Guest",
        is_logged_in: false,
        is_registered: null,
        version: {},
        roles: [],
        ui_mode: 'PRODUCTION',
    },
    url: '/session/',
    parse: function(resp){
        return resp.data;
    }
});

IONUX.Models.Resource = Backbone.Model.extend({});

IONUX.Models.EventType = Backbone.Model.extend({
    url: '/event_types/',
    parse: function(resp){
        return resp.data;
    },
});

IONUX.Models.Layout = Backbone.Model.extend({
  url: '/layout',
  parse: function(resp){
    return resp.data;
  },
});

// Timestamp conversion methods to call when parsing response.
// Maybe put these into IONUX.Helpers namespace?
var epoch_to_iso = function(epoch_time){
    try {
      return new Date(parseInt(epoch_time)).toISOString().replace(/T/, ' ').replace(/.\d{3}Z$/, 'Z');
    } catch (err) {
      return epoch_time;
    };
};

var make_iso_timestamps = function(resp) {
  _.each(resp, function(val, key) {
      if (key == 'ts_created' || key == 'ts_updated'){
        resp[key] = epoch_to_iso(val);
      };
      if (typeof val == 'object') {
        make_iso_timestamps(val);
      };
  });
  return;
};

IONUX.Models.ResourceExtension = Backbone.Model.extend({
    url: function(){
        return '/'+this.get('resource_type')+'/extension/'+this.get('resource_id')+'/';
    },
    parse: function(resp){
        make_iso_timestamps(resp);
        return resp.data;
    }
});

IONUX.Models.Observatory = Backbone.Model.extend({
  url: "/observatories/",
  idAttribute: "_id",
});

IONUX.Models.ObservatoryFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/observatories/"+this.get("observatory_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.UserRequest = Backbone.Model.extend({});

IONUX.Models.Platform = Backbone.Model.extend({
  url: "/platforms/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.PlatformFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/platforms/"+this.get("platform_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.PlatformModel = Backbone.Model.extend({
  url: '/platform_models/',
  idAttribute: '_id',

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp;
  }
});

IONUX.Models.PlatformModelFacepageModel = Backbone.Model.extend({
  url: function() {
    return '/platform_models/'+this.get('platform_model_id')+'/';
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.Instrument = Backbone.Model.extend({
  url: "/instruments/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

// IONUX.Models.Instrument = Backbone.Model.extend({
//   url: "/instrument_models/",
//   idAttribute: "_id"
// });

IONUX.Models.InstrumentFacepageModelLegacy = Backbone.Model.extend({
  url: function(){
    return "/instruments/"+this.get("instrument_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.InstrumentModel = Backbone.Model.extend({
  url: '/instrument_models/',
  idAttribute: '_id',

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  }
});

IONUX.Models.InstrumentModelFacepageModel = Backbone.Model.extend({
  url: function() {
    return '/instrument_models/'+this.get('instrument_model_id')+'/';
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.InstrumentAgent = Backbone.Model.extend({
  url: '/instrument_agents/',
  idAttribute: '_id',

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.InstrumentAgentFacepageModel = Backbone.Model.extend({
  url: function() {
    return '/instrument_agents/'+this.get('instrument_agent_id')+'/';
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.DataProcessDefinition = Backbone.Model.extend({
  url: "/data_process_definitions/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.DataProcessDefinitionFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/data_process_definitions/"+this.get("data_process_definition_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.DataProduct = Backbone.Model.extend({
  url: "/data_products/",
  idAttribute: "_id",

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp;
  }
});

IONUX.Models.DataProductFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/data_products/"+this.get("data_product_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.FrameOfReference = Backbone.Model.extend({
  url: "/frame_of_references/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.FrameOfReferenceFacepage = Backbone.Model.extend({
  url: function() {
    return "/frame_of_references/"+this.get("frame_of_reference_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.UserRegistrationModel = IONUX.Models.EditableResource.extend({
  url: "/userprofile/",
  idAttribute: "_id",

  schema: {
    'contact': {
      type: 'Object',
      title: false,
      subSchema: {
        individual_names_given: { type: 'Text', title: 'Given Name(s)' },
        individual_name_family: { type: 'Text', title: 'Family Name' },
        organization_name:      { type: 'Text', title: 'Organization Name' },
        position_name:          { type: 'Text', title: 'Position' },
        email:                  { type: 'Text', title: 'Email', dataType: 'email', validators: ['required', 'email']},
        street_address:         { type: 'Text', title: 'Street Address' },
        city:                   { type: 'Text', title: 'City' },
        postal_code:            { type: 'Text', title: 'Postal Code' },
        country:                { type: 'Text', title: 'Country' },
        url:                    { type: 'Text', title: 'Contact URL' },
        phones:                 { type: 'List', itemType: 'Phone' },
      },
    },

    'variables': {
      type: 'Object',
      title: false,
      subSchema: {
        notification_contact:   { type: 'Radio',    title: 'Notification Method', options: ['Email', 'SMS'] },
        sms_email:              { type: 'Checkbox', title: "Use email->SMS" },
        ooi_system_change:      { type: 'Checkbox', title: "OOI system change information" },
        ooi_project_updates:    { type: 'Checkbox', title: "OOI project updates" },
        ocean_leadership_news:  { type: 'Checkbox', title: "Ocean Leadership News" },
        ux_improvement_program: { type: 'Checkbox', title: "Participate in OOI User Experience Improvement Program" },
      }
    },

  },

  attr_convert: {
    'name': {
      parse: function(v) {
        /**
         * Input: value of name field.
         * Ouptut: the same. Not presented on form.
         */
        return v;
      },
      serialize: function(v) {
        /**
         * Input: whatever value we parsed initially. May be empty.
         * Output: the concatentation of contact.individual_names_given + individual_name_family
         */
        var contact = this.get('contact');
        return contact.individual_names_given + " " + contact.individual_name_family;
      },
    },
    'variables': {
      parse: function(v) {
        /**
         * Input: array of { name: <key>, value: <value> } literal objects
         * Output: object with keys -> values
         */
        return _.object(_.map(v, function(vv) { return [vv.name, vv.value]; } ));
      },
      serialize: function(v) {
        /**
         * Input: object with keys -> values
         * Output: array of { name: <key>, value: <value> } literal objects
         */
        return _.map(v, function(vv, kk) { return { name: kk, value: vv }; });
      },
    },
  },

  attr_convert_serialize: function(attrs) {
    /**
     * Call this from your toJSON.
     */
    attrs = _.clone(attrs);
    var self = this;
    _.each(this.attr_convert, function(v, k) {
      if (_.has(attrs, k)) {
        attrs[k] = v.serialize.call(self, attrs[k]);
      }
    });

    return attrs;
  },

  attr_convert_parse: function(data) {
    /**
     * Call this from your parse method.
     */
    data = _.clone(data);
    var self = this;
    _.each(this.attr_convert, function(v, k) {
      if (_.has(data, k)) {
        data[k] = v.parse.call(self, data[k]);
      }
    });

    return data;
  },

  toJSON: function() {
    var o = IONUX.Models.EditableResource.prototype.toJSON.call(this);
    o = this.attr_convert_serialize(o);

    return o;
  },

  parse: function(resp) {
    var data = resp.data;
    if (data != null)
      data = this.attr_convert_parse(data);
    return data;
  },

  merge: function(attribute, value) {
    /**
     * Instead of overwriting full objects, this method merges the passed in value
     * on top of the current value.
     */

    var curval = _.clone(this.get(attribute) || {});
    _.extend(curval, value);
    this.set(attribute, curval);

    return curval;
  },
});

IONUX.Models.User = Backbone.Model.extend({
  url: "/users/",
  idAttribute: "_id"
});

IONUX.Models.UserFacepageModel = Backbone.Model.extend({
  url: function() {
    return "/users/"+this.get("user_id")+"/";
  },
  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.ResourceType = Backbone.Model.extend({})
<commit_msg>Set ContactInfo type_ on user reg<commit_after>IONUX.Models.EditableResource = Backbone.Model.extend({
  idAttribute: '_id',
  schema: function(){
    return this.make_schema();
  },
  initialize: function(){},
  url: function(){
    return window.location.pathname.replace(/edit$/,'');
  },
  make_schema: function(){
    var self = this;
    var schema = {};
    _.each(this.attributes, function(value, key){
      if (!_.isObject(value) && !(key=='ts_updated' || key=='ts_created')){
        console.log(key, value, typeof value);
        switch(typeof(value)){
          case 'boolean':
            schema[key] = 'Checkbox';
            break;
          case 'number':
            schema[key] = 'Number';
            break;
          default:
            schema[key] = 'Text'
        };
      };
    });
    return schema;
  },
});

IONUX.Models.Search = Backbone.Model.extend();

IONUX.Models.Search = Backbone.Model.extend({
    url: function(){
        return "/search/?query="+this.get("search_query");
    },
    parse: function(resp){
        make_iso_timestamps(resp);
        return resp.data;
    }
});

// For use with collections of Resource Types, i.e. InstrumentDevice, PlatformDevice, etc.
IONUX.Models.Session = Backbone.Model.extend({
    defaults: {
        actor_id: null,
        user_id: null,
        name: "Guest",
        is_logged_in: false,
        is_registered: null,
        version: {},
        roles: [],
        ui_mode: 'PRODUCTION',
    },
    url: '/session/',
    parse: function(resp){
        return resp.data;
    }
});

IONUX.Models.Resource = Backbone.Model.extend({});

IONUX.Models.EventType = Backbone.Model.extend({
    url: '/event_types/',
    parse: function(resp){
        return resp.data;
    },
});

IONUX.Models.Layout = Backbone.Model.extend({
  url: '/layout',
  parse: function(resp){
    return resp.data;
  },
});

// Timestamp conversion methods to call when parsing response.
// Maybe put these into IONUX.Helpers namespace?
var epoch_to_iso = function(epoch_time){
    try {
      return new Date(parseInt(epoch_time)).toISOString().replace(/T/, ' ').replace(/.\d{3}Z$/, 'Z');
    } catch (err) {
      return epoch_time;
    };
};

var make_iso_timestamps = function(resp) {
  _.each(resp, function(val, key) {
      if (key == 'ts_created' || key == 'ts_updated'){
        resp[key] = epoch_to_iso(val);
      };
      if (typeof val == 'object') {
        make_iso_timestamps(val);
      };
  });
  return;
};

IONUX.Models.ResourceExtension = Backbone.Model.extend({
    url: function(){
        return '/'+this.get('resource_type')+'/extension/'+this.get('resource_id')+'/';
    },
    parse: function(resp){
        make_iso_timestamps(resp);
        return resp.data;
    }
});

IONUX.Models.Observatory = Backbone.Model.extend({
  url: "/observatories/",
  idAttribute: "_id",
});

IONUX.Models.ObservatoryFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/observatories/"+this.get("observatory_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.UserRequest = Backbone.Model.extend({});

IONUX.Models.Platform = Backbone.Model.extend({
  url: "/platforms/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.PlatformFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/platforms/"+this.get("platform_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.PlatformModel = Backbone.Model.extend({
  url: '/platform_models/',
  idAttribute: '_id',

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp;
  }
});

IONUX.Models.PlatformModelFacepageModel = Backbone.Model.extend({
  url: function() {
    return '/platform_models/'+this.get('platform_model_id')+'/';
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.Instrument = Backbone.Model.extend({
  url: "/instruments/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

// IONUX.Models.Instrument = Backbone.Model.extend({
//   url: "/instrument_models/",
//   idAttribute: "_id"
// });

IONUX.Models.InstrumentFacepageModelLegacy = Backbone.Model.extend({
  url: function(){
    return "/instruments/"+this.get("instrument_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.InstrumentModel = Backbone.Model.extend({
  url: '/instrument_models/',
  idAttribute: '_id',

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  }
});

IONUX.Models.InstrumentModelFacepageModel = Backbone.Model.extend({
  url: function() {
    return '/instrument_models/'+this.get('instrument_model_id')+'/';
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.InstrumentAgent = Backbone.Model.extend({
  url: '/instrument_agents/',
  idAttribute: '_id',

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.InstrumentAgentFacepageModel = Backbone.Model.extend({
  url: function() {
    return '/instrument_agents/'+this.get('instrument_agent_id')+'/';
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.DataProcessDefinition = Backbone.Model.extend({
  url: "/data_process_definitions/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.DataProcessDefinitionFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/data_process_definitions/"+this.get("data_process_definition_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.DataProduct = Backbone.Model.extend({
  url: "/data_products/",
  idAttribute: "_id",

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp;
  }
});

IONUX.Models.DataProductFacepageModel = Backbone.Model.extend({
  url: function(){
    return "/data_products/"+this.get("data_product_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.FrameOfReference = Backbone.Model.extend({
  url: "/frame_of_references/",
  idAttribute: "_id",

  parse: function(resp){
    make_iso_timestamps(resp);
    return resp;
  },
});

IONUX.Models.FrameOfReferenceFacepage = Backbone.Model.extend({
  url: function() {
    return "/frame_of_references/"+this.get("frame_of_reference_id")+"/";
  },

  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.UserRegistrationModel = IONUX.Models.EditableResource.extend({
  url: "/userprofile/",
  idAttribute: "_id",

  schema: {
    'contact': {
      type: 'Object',
      title: false,
      subSchema: {
        individual_names_given: { type: 'Text', title: 'Given Name(s)' },
        individual_name_family: { type: 'Text', title: 'Family Name' },
        organization_name:      { type: 'Text', title: 'Organization Name' },
        position_name:          { type: 'Text', title: 'Position' },
        email:                  { type: 'Text', title: 'Email', dataType: 'email', validators: ['required', 'email']},
        street_address:         { type: 'Text', title: 'Street Address' },
        city:                   { type: 'Text', title: 'City' },
        postal_code:            { type: 'Text', title: 'Postal Code' },
        country:                { type: 'Text', title: 'Country' },
        url:                    { type: 'Text', title: 'Contact URL' },
        phones:                 { type: 'List', itemType: 'Phone' },
      },
    },

    'variables': {
      type: 'Object',
      title: false,
      subSchema: {
        notification_contact:   { type: 'Radio',    title: 'Notification Method', options: ['Email', 'SMS'] },
        sms_email:              { type: 'Checkbox', title: "Use email->SMS" },
        ooi_system_change:      { type: 'Checkbox', title: "OOI system change information" },
        ooi_project_updates:    { type: 'Checkbox', title: "OOI project updates" },
        ocean_leadership_news:  { type: 'Checkbox', title: "Ocean Leadership News" },
        ux_improvement_program: { type: 'Checkbox', title: "Participate in OOI User Experience Improvement Program" },
      }
    },

  },

  attr_convert: {
    'name': {
      parse: function(v) {
        /**
         * Input: value of name field.
         * Ouptut: the same. Not presented on form.
         */
        return v;
      },
      serialize: function(v) {
        /**
         * Input: whatever value we parsed initially. May be empty.
         * Output: the concatentation of contact.individual_names_given + individual_name_family
         */
        var contact = this.get('contact');
        return contact.individual_names_given + " " + contact.individual_name_family;
      },
    },
    'variables': {
      parse: function(v) {
        /**
         * Input: array of { name: <key>, value: <value> } literal objects
         * Output: object with keys -> values
         */
        return _.object(_.map(v, function(vv) { return [vv.name, vv.value]; } ));
      },
      serialize: function(v) {
        /**
         * Input: object with keys -> values
         * Output: array of { name: <key>, value: <value> } literal objects
         */
        return _.map(v, function(vv, kk) { return { name: kk, value: vv }; });
      },
    },
  },

  attr_convert_serialize: function(attrs) {
    /**
     * Call this from your toJSON.
     */
    attrs = _.clone(attrs);
    var self = this;
    _.each(this.attr_convert, function(v, k) {
      if (_.has(attrs, k)) {
        attrs[k] = v.serialize.call(self, attrs[k]);
      }
    });

    return attrs;
  },

  attr_convert_parse: function(data) {
    /**
     * Call this from your parse method.
     */
    data = _.clone(data);
    var self = this;
    _.each(this.attr_convert, function(v, k) {
      if (_.has(data, k)) {
        data[k] = v.parse.call(self, data[k]);
      }
    });

    return data;
  },

  toJSON: function() {
    var o = IONUX.Models.EditableResource.prototype.toJSON.call(this);
    o = this.attr_convert_serialize(o);

    o['contact']['type_'] = 'ContactInfo';

    return o;
  },

  parse: function(resp) {
    var data = resp.data;
    if (data != null)
      data = this.attr_convert_parse(data);
    return data;
  },

  merge: function(attribute, value) {
    /**
     * Instead of overwriting full objects, this method merges the passed in value
     * on top of the current value.
     */

    var curval = _.clone(this.get(attribute) || {});
    _.extend(curval, value);
    this.set(attribute, curval);

    return curval;
  },
});

IONUX.Models.User = Backbone.Model.extend({
  url: "/users/",
  idAttribute: "_id"
});

IONUX.Models.UserFacepageModel = Backbone.Model.extend({
  url: function() {
    return "/users/"+this.get("user_id")+"/";
  },
  parse: function(resp) {
    make_iso_timestamps(resp);
    return resp.data;
  }
});

IONUX.Models.ResourceType = Backbone.Model.extend({})
<|endoftext|>


<commit_before>cdb.geo.ui.Text = cdb.core.View.extend({

  className: "cartodb-overlay overlay-text",

  events: {
    "click": "stopPropagation"
  },

  default_options: { },

  stopPropagation: function(e) {

    e.stopPropagation();

  },

  initialize: function() {

    _.defaults(this.options, this.default_options);

    this.template = this.options.template;

    var self = this;

    $(window).on("map_resized", function() {
      self._place();
    });

    $(window).on("resize", function() {
      self._place();
    });

  },

  _applyStyle: function() {

    var style      = this.model.get("style");

    var boxColor   = style["box-color"];
    var boxOpacity = style["box-opacity"];
    var boxWidth   = style["box-width"];
    var fontFamily = style["font-family-name"];

    this.$text.css(style);
    this.$text.css("font-size", style["font-size"] + "px");

    var fontFamilyClass = "";

    if      (fontFamily  == "Droid Sans") fontFamilyClass = "droid";
    else if (fontFamily  == "Vollkorn")   fontFamilyClass = "vollkorn";
    else if (fontFamily  == "Open Sans")  fontFamilyClass = "open_sans";
    else if (fontFamily  == "Roboto")     fontFamilyClass = "roboto";

    var rgbaCol = 'rgba(' + parseInt(boxColor.slice(-6,-4),16)
    + ',' + parseInt(boxColor.slice(-4,-2),16)
    + ',' + parseInt(boxColor.slice(-2),16)
    +', ' + boxOpacity + ' )';

    this.$el
    .removeClass("droid")
    .removeClass("vollkorn")
    .removeClass("roboto")
    .removeClass("open_sans");

    this.$el.addClass(fontFamilyClass);
    this.$el.css({
      backgroundColor: rgbaCol,
      maxWidth:        boxWidth
    });

  },

  _place: function(position) {

    var extra = position || this.model.get("extra");

    var top   = this.model.get("y");
    var left  = this.model.get("x");

    var bottom_position = extra.bottom - this.$el.height();
    var right_position  = extra.right  - this.$el.width();

    // position percentages
    var top_percentage  = extra.top_percentage;
    var left_percentage = extra.left_percentage;

    var right  = "auto";
    var bottom = "auto";

    var marginTop  = 0;
    var marginLeft = 0;

    var width  = extra.width;
    var height = extra.height;

    var portrait_dominant_side  = extra.portrait_dominant_side;
    var landscape_dominant_side = extra.landscape_dominant_side;

    if (portrait_dominant_side === 'bottom' && bottom_position <= 250) {

      top = "auto";
      bottom = bottom_position;

    } else if (top_percentage > 45 && top_percentage < 55) {

      top = "50%";
      marginTop = -height/2;

    }

    if (landscape_dominant_side === 'right' && right_position <= 250) {

      left = "auto";
      right = right_position;

    } else if (left_percentage > 45 && left_percentage < 55) {

      left = "50%";
      marginLeft = -width/2;

    }

    this.$el.css({
      width: width,
      marginLeft: marginLeft,
      marginTop: marginTop,
      top: top,
      left: left,
      right: right,
      bottom: bottom
    });

  },

  render: function() {

    this._place();

    this.$el.html(this.template(_.extend(this.model.attributes, { text: this.model.attributes.extra.rendered_text })));

    this.$text = this.$el.find(".text");

    this._applyStyle();

    return this;

  }

});
<commit_msg>removes auto width<commit_after>cdb.geo.ui.Text = cdb.core.View.extend({

  className: "cartodb-overlay overlay-text",

  events: {
    "click": "stopPropagation"
  },

  default_options: { },

  stopPropagation: function(e) {

    e.stopPropagation();

  },

  initialize: function() {

    _.defaults(this.options, this.default_options);

    this.template = this.options.template;

    var self = this;

    $(window).on("map_resized", function() {
      self._place();
    });

    $(window).on("resize", function() {
      self._place();
    });

  },

  _applyStyle: function() {

    var style      = this.model.get("style");

    var boxColor   = style["box-color"];
    var boxOpacity = style["box-opacity"];
    var boxWidth   = style["box-width"];
    var fontFamily = style["font-family-name"];

    this.$text.css(style);
    this.$text.css("font-size", style["font-size"] + "px");

    var fontFamilyClass = "";

    if      (fontFamily  == "Droid Sans") fontFamilyClass = "droid";
    else if (fontFamily  == "Vollkorn")   fontFamilyClass = "vollkorn";
    else if (fontFamily  == "Open Sans")  fontFamilyClass = "open_sans";
    else if (fontFamily  == "Roboto")     fontFamilyClass = "roboto";

    var rgbaCol = 'rgba(' + parseInt(boxColor.slice(-6,-4),16)
    + ',' + parseInt(boxColor.slice(-4,-2),16)
    + ',' + parseInt(boxColor.slice(-2),16)
    +', ' + boxOpacity + ' )';

    this.$el
    .removeClass("droid")
    .removeClass("vollkorn")
    .removeClass("roboto")
    .removeClass("open_sans");

    this.$el.addClass(fontFamilyClass);
    this.$el.css({
      backgroundColor: rgbaCol,
      maxWidth:        boxWidth
    });

  },

  _place: function(position) {

    var extra = position || this.model.get("extra");

    var top   = this.model.get("y");
    var left  = this.model.get("x");

    var bottom_position = extra.bottom - this.$el.height();
    var right_position  = extra.right  - this.$el.width();

    // position percentages
    var top_percentage  = extra.top_percentage;
    var left_percentage = extra.left_percentage;

    var right  = "auto";
    var bottom = "auto";

    var marginTop  = 0;
    var marginLeft = 0;

    var width  = extra.width;
    var height = extra.height;

    var portrait_dominant_side  = extra.portrait_dominant_side;
    var landscape_dominant_side = extra.landscape_dominant_side;

    if (portrait_dominant_side === 'bottom' && bottom_position <= 250) {

      top = "auto";
      bottom = bottom_position;

    } else if (top_percentage > 45 && top_percentage < 55) {

      top = "50%";
      marginTop = -height/2;

    }

    if (landscape_dominant_side === 'right' && right_position <= 250) {

      left = "auto";
      right = right_position;

    } else if (left_percentage > 45 && left_percentage < 55) {

      left = "50%";
      marginLeft = -width/2;

    }

    this.$el.css({
      marginLeft: marginLeft,
      marginTop: marginTop,
      top: top,
      left: left,
      right: right,
      bottom: bottom
    });

  },

  render: function() {

    this._place();

    this.$el.html(this.template(_.extend(this.model.attributes, { text: this.model.attributes.extra.rendered_text })));

    this.$text = this.$el.find(".text");

    this._applyStyle();

    return this;

  }

});
<|endoftext|>


<commit_before>'use strict';

var smallYes = 'yes' || 'y';
var smallNo = 'no' || 'n';
var capYes = 'YES' || 'Y';
var capNo = 'NO' || 'N';

function questionName() {
  var name = prompt('Is my name Henry?');
  if (name.toLowerCase() === smallYes) {
    alert('Correctamundo');
  } else {
    alert('Please try again!');
    console.log(name);
  }
}

function questionColor() {
  var color = prompt('Do you think my favorite color is red?');
  if (color.toUpperCase() === capNo) {
    alert('Try Again!');
  } else {
    alert('Good Job!');
    console.log(color);
  }
}

function questionFood() {
  var food = prompt('Is my favorite food pizza?');
  if (food.toLowerCase() === smallYes) {
    alert('Give this person a slice!');
  } else {
    alert('No pizza for you!');
    console.log(food);
  }
}

function questionActivity() {
  var know = prompt('Do I look like I know what I\'m doing?');
  if (know.toUpperCase() === capYes) {
    alert('Well that\'s good!');
  } else {
    alert('well... ****');
    console.log(know);
  }
}

function questionDriving() {
  var driving = prompt('Do I like driving?');
  if (driving.toLowerCase() === smallNo) {
    alert('Sorry, try again!');
  } else {
    alert('WOOOOOOOOO');
    console.log(driving);
  }
}

var vacateTo = ['antigua','nyc','guatemala','italy'];
function questionVacation() {
  var vacate = prompt('Where have I gone in the world?' + ' ' + vacateTo[0] + ' ' + vacateTo[1] + ' ' + vacateTo[2] + ' or ' + vacateTo[3] + '?');
  if(vacate.toLowerCase() === vacateTo[0]) {
    alert('nice! I\'ve also been to ' + vacateTo[1] + ', ' + vacateTo[2] + ', and ' + vacateTo[3] + '.');

  } if(vacate.toLowerCase() === vacateTo[1]) {
    alert('nice! I\'ve also been to ' + vacateTo[0] + ', ' + vacateTo[2] + ', and ' + vacateTo[3] + '.');

  } if(vacate.toLowerCase() === vacateTo[2]) {
    alert('nice! I\'ve also been to ' + vacateTo[0] + ', ' + vacateTo[1] + ', and ' + vacateTo[3] + '.');

  } if(vacate.toLowerCase() === vacateTo[3]) {
    alert('nice! I\'ve also been to ' + vacateTo[0] + ', ' + vacateTo[1] + ', and ' + vacateTo[2] + '.');

  } else {
    alert('No, but that sounds cool!');
    console.log(vacate + driving);
  }
}

//function calls
questionName();
questionColor();
questionFood();
questionActivity();
questionDriving();
questionVacation();
<commit_msg>about_me_deploy<commit_after>'use strict';

var smallYes = 'yes' || 'y';
var smallNo = 'no' || 'n';
var capYes = 'YES' || 'Y';
var capNo = 'NO' || 'N';

function questionName() {
  var name = prompt('Is my name Henry?');
  if (name.toLowerCase() === smallYes) {
    alert('Correctamundo');
  } else {
    alert('Please try again!');
    console.log(name);
  }
}

function questionColor() {
  var color = prompt('Do you think my favorite color is red?');
  if (color.toUpperCase() === capNo) {
    alert('Try Again!');
  } else {
    alert('Good Job!');
    console.log(color);
  }
}

function questionFood() {
  var food = prompt('Is my favorite food pizza?');
  if (food.toLowerCase() === smallYes) {
    alert('Give this person a slice!');
  } else {
    alert('No pizza for you!');
    console.log(food);
  }
}

function questionActivity() {
  var know = prompt('Do I look like I know what I\'m doing?');
  if (know.toUpperCase() === capYes) {
    alert('Well that\'s good!');
  } else {
    alert('well... ****');
    console.log(know);
  }
}

function questionDriving() {
  var driving = prompt('Do I like driving?');
  if (driving.toLowerCase() === smallNo) {
    alert('Sorry, try again!');
  } else {
    alert('WOOOOOOOOO');
    console.log(driving);
  }
}

var vacateTo = ['antigua','nyc','guatemala','italy'];
function questionVacation() {
  var vacate = prompt('Where have I gone in the world?' + ' ' + vacateTo[0] + ' ' + vacateTo[1] + ' ' + vacateTo[2] + ' or ' + vacateTo[3] + '?');
  if(vacate.toLowerCase() === vacateTo[0]) {
    alert('nice! I\'ve also been to ' + vacateTo[1] + ', ' + vacateTo[2] + ', and ' + vacateTo[3] + '.');

  } if(vacate.toLowerCase() === vacateTo[1]) {
    alert('nice! I\'ve also been to ' + vacateTo[0] + ', ' + vacateTo[2] + ', and ' + vacateTo[3] + '.');

  } if(vacate.toLowerCase() === vacateTo[2]) {
    alert('nice! I\'ve also been to ' + vacateTo[0] + ', ' + vacateTo[1] + ', and ' + vacateTo[3] + '.');

  } if(vacate.toLowerCase() === vacateTo[3]) {
    alert('nice! I\'ve also been to ' + vacateTo[0] + ', ' + vacateTo[1] + ', and ' + vacateTo[2] + '.');

  } else {
    alert('No, but that sounds cool!');
    console.log(vacate + driving);
  }
}

//function calls
questionName();
questionColor();
questionFood();
questionActivity();
questionDriving();
questionVacation();
sddfsdf
<|endoftext|>