<commit_before>/**
 * Created by roy on 15/9/14.
 */
BI.SearchEditor = BI.inherit(BI.Widget, {
    _defaultConfig: function () {
        var conf = BI.SearchEditor.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            baseCls: "bi-search-editor bi-border bi-focus-shadow",
            height: 24,
            errorText: "",
            watermark: BI.i18nText("BI-Basic_Search"),
            validationChecker: BI.emptyFn,
            quitChecker: BI.emptyFn
        });
    },
    _init: function () {
        this.options.height -= 2;
        BI.SearchEditor.superclass._init.apply(this, arguments);
        var self = this, o = this.options;
        this.editor = BI.createWidget({
            type: "bi.editor",
            height: o.height,
            watermark: o.watermark,
            allowBlank: true,
            hgap: 1,
            errorText: o.errorText,
            validationChecker: o.validationChecker,
            quitChecker: o.quitChecker,
            value: o.value
        });
        this.clear = BI.createWidget({
            type: "bi.icon_button",
            stopEvent: true,
            cls: "close-font"
        });
        this.clear.on(BI.IconButton.EVENT_CHANGE, function () {
            self.setValue("");
            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT);
            // 从有内容到无内容的清空也是一次change
            self.fireEvent(BI.SearchEditor.EVENT_CHANGE);
            self.fireEvent(BI.SearchEditor.EVENT_CLEAR);
        });
        BI.createWidget({
            element: this,
            type: "bi.htape",
            items: [
                {
                    el: {
                        type: "bi.icon_label",
                        cls: "search-font"
                    },
                    width: 24
                },
                {
                    el: self.editor
                },
                {
                    el: this.clear,
                    width: 24
                }
            ]
        });
        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
        });

        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
            self.fireEvent(BI.SearchEditor.EVENT_FOCUS);
        });
        this.editor.on(BI.Editor.EVENT_BLUR, function () {
            self.fireEvent(BI.SearchEditor.EVENT_BLUR);
        });
        this.editor.on(BI.Editor.EVENT_CLICK, function () {
            self.fireEvent(BI.SearchEditor.EVENT_CLICK);
        });
        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
            self._checkClear();
            self.fireEvent(BI.SearchEditor.EVENT_CHANGE);
        });
        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
            self.fireEvent(BI.SearchEditor.EVENT_KEY_DOWN, v);
        });
        this.editor.on(BI.Editor.EVENT_SPACE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_SPACE);
        });
        this.editor.on(BI.Editor.EVENT_BACKSPACE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_BACKSPACE);
        });

        this.editor.on(BI.Editor.EVENT_VALID, function () {
            self.fireEvent(BI.SearchEditor.EVENT_VALID);
        });
        this.editor.on(BI.Editor.EVENT_ERROR, function () {
            self.fireEvent(BI.SearchEditor.EVENT_ERROR);
        });
        this.editor.on(BI.Editor.EVENT_ENTER, function () {
            self.fireEvent(BI.SearchEditor.EVENT_ENTER);
        });
        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
            self.fireEvent(BI.SearchEditor.EVENT_RESTRICT);
        });
        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
            self._checkClear();
            self.fireEvent(BI.SearchEditor.EVENT_EMPTY);
        });
        this.editor.on(BI.Editor.EVENT_REMOVE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_REMOVE);
        });
        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
            self.fireEvent(BI.SearchEditor.EVENT_CONFIRM);
        });
        this.editor.on(BI.Editor.EVENT_CHANGE_CONFIRM, function () {
            self.fireEvent(BI.SearchEditor.EVENT_CHANGE_CONFIRM);
        });
        this.editor.on(BI.Editor.EVENT_START, function () {
            self.fireEvent(BI.SearchEditor.EVENT_START);
        });
        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_PAUSE);
        });
        this.editor.on(BI.Editor.EVENT_STOP, function () {
            self.fireEvent(BI.SearchEditor.EVENT_STOP);
        });

        this.clear.invisible();
    },

    _checkClear: function () {
        if (!this.getValue()) {
            this.clear.invisible();
        } else {
            this.clear.visible();
        }
    },

    setWaterMark: function (v) {
        this.options.watermark = v;
        this.editor.setWaterMark(v);
    },

    focus: function () {
        this.editor.focus();
    },

    blur: function () {
        this.editor.blur();
    },

    getValue: function () {
        if (this.isValid()) {
            return this.editor.getValue();
        }
    },

    getKeywords: function () {
        var val = this.editor.getLastChangedValue();
        var keywords = val.match(/[\S]+/g);
        if (BI.isEndWithBlank(val)) {
            return keywords.concat([" "]);
        }
        return keywords;
    },

    getLastValidValue: function () {
        return this.editor.getLastValidValue();
    },

    getLastChangedValue: function () {
        return this.editor.getLastChangedValue();
    },

    setValue: function (v) {
        this.editor.setValue(v);
        if (BI.isKey(v)) {
            this.clear.visible();
        }
    },

    isEditing: function () {
        return this.editor.isEditing();
    },

    isValid: function () {
        return this.editor.isValid();
    }
});
BI.SearchEditor.EVENT_CHANGE = "EVENT_CHANGE";
BI.SearchEditor.EVENT_FOCUS = "EVENT_FOCUS";
BI.SearchEditor.EVENT_BLUR = "EVENT_BLUR";
BI.SearchEditor.EVENT_CLICK = "EVENT_CLICK";
BI.SearchEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
BI.SearchEditor.EVENT_SPACE = "EVENT_SPACE";
BI.SearchEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
BI.SearchEditor.EVENT_CLEAR = "EVENT_CLEAR";

BI.SearchEditor.EVENT_START = "EVENT_START";
BI.SearchEditor.EVENT_PAUSE = "EVENT_PAUSE";
BI.SearchEditor.EVENT_STOP = "EVENT_STOP";
BI.SearchEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
BI.SearchEditor.EVENT_CHANGE_CONFIRM = "EVENT_CHANGE_CONFIRM";
BI.SearchEditor.EVENT_VALID = "EVENT_VALID";
BI.SearchEditor.EVENT_ERROR = "EVENT_ERROR";
BI.SearchEditor.EVENT_ENTER = "EVENT_ENTER";
BI.SearchEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
BI.SearchEditor.EVENT_REMOVE = "EVENT_REMOVE";
BI.SearchEditor.EVENT_EMPTY = "EVENT_EMPTY";
BI.shortcut("bi.search_editor", BI.SearchEditor);<commit_msg>无JIRA任务 提供一个控制icon的接口<commit_after>/**
 * Created by roy on 15/9/14.
 */
BI.SearchEditor = BI.inherit(BI.Widget, {
    _defaultConfig: function () {
        var conf = BI.SearchEditor.superclass._defaultConfig.apply(this, arguments);
        return BI.extend(conf, {
            baseCls: "bi-search-editor bi-border bi-focus-shadow",
            height: 24,
            errorText: "",
            watermark: BI.i18nText("BI-Basic_Search"),
            validationChecker: BI.emptyFn,
            quitChecker: BI.emptyFn
        });
    },
    _init: function () {
        this.options.height -= 2;
        BI.SearchEditor.superclass._init.apply(this, arguments);
        var self = this, o = this.options;
        this.editor = BI.createWidget({
            type: "bi.editor",
            height: o.height,
            watermark: o.watermark,
            allowBlank: true,
            hgap: 1,
            errorText: o.errorText,
            validationChecker: o.validationChecker,
            quitChecker: o.quitChecker,
            value: o.value
        });
        this.clear = BI.createWidget({
            type: "bi.icon_button",
            stopEvent: true,
            cls: "close-font"
        });
        this.clear.on(BI.IconButton.EVENT_CHANGE, function () {
            self.setValue("");
            self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.STOPEDIT);
            // 从有内容到无内容的清空也是一次change
            self.fireEvent(BI.SearchEditor.EVENT_CHANGE);
            self.fireEvent(BI.SearchEditor.EVENT_CLEAR);
        });
        BI.createWidget({
            element: this,
            type: "bi.htape",
            items: [
                {
                    el: {
                        type: "bi.icon_label",
                        cls: "search-font"
                    },
                    width: 24
                },
                {
                    el: self.editor
                },
                {
                    el: this.clear,
                    width: 24
                }
            ]
        });
        this.editor.on(BI.Controller.EVENT_CHANGE, function () {
            self.fireEvent(BI.Controller.EVENT_CHANGE, arguments);
        });

        this.editor.on(BI.Editor.EVENT_FOCUS, function () {
            self.fireEvent(BI.SearchEditor.EVENT_FOCUS);
        });
        this.editor.on(BI.Editor.EVENT_BLUR, function () {
            self.fireEvent(BI.SearchEditor.EVENT_BLUR);
        });
        this.editor.on(BI.Editor.EVENT_CLICK, function () {
            self.fireEvent(BI.SearchEditor.EVENT_CLICK);
        });
        this.editor.on(BI.Editor.EVENT_CHANGE, function () {
            self._checkClear();
            self.fireEvent(BI.SearchEditor.EVENT_CHANGE);
        });
        this.editor.on(BI.Editor.EVENT_KEY_DOWN, function (v) {
            self.fireEvent(BI.SearchEditor.EVENT_KEY_DOWN, v);
        });
        this.editor.on(BI.Editor.EVENT_SPACE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_SPACE);
        });
        this.editor.on(BI.Editor.EVENT_BACKSPACE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_BACKSPACE);
        });

        this.editor.on(BI.Editor.EVENT_VALID, function () {
            self.fireEvent(BI.SearchEditor.EVENT_VALID);
        });
        this.editor.on(BI.Editor.EVENT_ERROR, function () {
            self.fireEvent(BI.SearchEditor.EVENT_ERROR);
        });
        this.editor.on(BI.Editor.EVENT_ENTER, function () {
            self.fireEvent(BI.SearchEditor.EVENT_ENTER);
        });
        this.editor.on(BI.Editor.EVENT_RESTRICT, function () {
            self.fireEvent(BI.SearchEditor.EVENT_RESTRICT);
        });
        this.editor.on(BI.Editor.EVENT_EMPTY, function () {
            self._checkClear();
            self.fireEvent(BI.SearchEditor.EVENT_EMPTY);
        });
        this.editor.on(BI.Editor.EVENT_REMOVE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_REMOVE);
        });
        this.editor.on(BI.Editor.EVENT_CONFIRM, function () {
            self.fireEvent(BI.SearchEditor.EVENT_CONFIRM);
        });
        this.editor.on(BI.Editor.EVENT_CHANGE_CONFIRM, function () {
            self.fireEvent(BI.SearchEditor.EVENT_CHANGE_CONFIRM);
        });
        this.editor.on(BI.Editor.EVENT_START, function () {
            self.fireEvent(BI.SearchEditor.EVENT_START);
        });
        this.editor.on(BI.Editor.EVENT_PAUSE, function () {
            self.fireEvent(BI.SearchEditor.EVENT_PAUSE);
        });
        this.editor.on(BI.Editor.EVENT_STOP, function () {
            self.fireEvent(BI.SearchEditor.EVENT_STOP);
        });

        this.clear.invisible();
    },

    _checkClear: function () {
        if (!this.getValue()) {
            this.clear.invisible();
        } else {
            this.clear.visible();
        }
    },

    setWaterMark: function (v) {
        this.options.watermark = v;
        this.editor.setWaterMark(v);
    },

    focus: function () {
        this.editor.focus();
    },

    blur: function () {
        this.editor.blur();
    },

    getValue: function () {
        if (this.isValid()) {
            return this.editor.getValue();
        }
    },

    getKeywords: function () {
        var val = this.editor.getLastChangedValue();
        var keywords = val.match(/[\S]+/g);
        if (BI.isEndWithBlank(val)) {
            return keywords.concat([" "]);
        }
        return keywords;
    },

    getLastValidValue: function () {
        return this.editor.getLastValidValue();
    },

    getLastChangedValue: function () {
        return this.editor.getLastChangedValue();
    },

    setValue: function (v) {
        this.editor.setValue(v);
        if (BI.isKey(v)) {
            this.clear.visible();
        }
    },

    isEditing: function () {
        return this.editor.isEditing();
    },

    isValid: function () {
        return this.editor.isValid();
    },

    showClearIcon: function () {
        this.clear.visible();
    },

    hideClearIcon: function () {
        this.clear.invisible();
    }
});
BI.SearchEditor.EVENT_CHANGE = "EVENT_CHANGE";
BI.SearchEditor.EVENT_FOCUS = "EVENT_FOCUS";
BI.SearchEditor.EVENT_BLUR = "EVENT_BLUR";
BI.SearchEditor.EVENT_CLICK = "EVENT_CLICK";
BI.SearchEditor.EVENT_KEY_DOWN = "EVENT_KEY_DOWN";
BI.SearchEditor.EVENT_SPACE = "EVENT_SPACE";
BI.SearchEditor.EVENT_BACKSPACE = "EVENT_BACKSPACE";
BI.SearchEditor.EVENT_CLEAR = "EVENT_CLEAR";

BI.SearchEditor.EVENT_START = "EVENT_START";
BI.SearchEditor.EVENT_PAUSE = "EVENT_PAUSE";
BI.SearchEditor.EVENT_STOP = "EVENT_STOP";
BI.SearchEditor.EVENT_CONFIRM = "EVENT_CONFIRM";
BI.SearchEditor.EVENT_CHANGE_CONFIRM = "EVENT_CHANGE_CONFIRM";
BI.SearchEditor.EVENT_VALID = "EVENT_VALID";
BI.SearchEditor.EVENT_ERROR = "EVENT_ERROR";
BI.SearchEditor.EVENT_ENTER = "EVENT_ENTER";
BI.SearchEditor.EVENT_RESTRICT = "EVENT_RESTRICT";
BI.SearchEditor.EVENT_REMOVE = "EVENT_REMOVE";
BI.SearchEditor.EVENT_EMPTY = "EVENT_EMPTY";
BI.shortcut("bi.search_editor", BI.SearchEditor);<|endoftext|>


<commit_before>'use strict';

exports._parent        = require('./statistics-flow');
exports._customFilters = Function.prototype;

exports['flow-nav']            = { class: { 'submitted-menu-item-active': true } };
exports['flow-rejections-nav'] = { class: { 'pills-nav-active': true } };

exports['statistics-main'] = function () {
};
<commit_msg>Issue #1796. Add filter bar<commit_after>'use strict';

var _              = require('mano').i18n.bind('View: Statistics')
  , selectService  = require('./components/filter-bar/select-service')
  , selectDateFrom = require('./components/filter-bar/select-date-from')
  , selectDateTo   = require('./components/filter-bar/select-date-to');

exports._parent        = require('./statistics-flow');
exports._customFilters = Function.prototype;

exports['flow-nav']            = { class: { 'submitted-menu-item-active': true } };
exports['flow-rejections-nav'] = { class: { 'pills-nav-active': true } };

exports['statistics-main'] = function () {
	section(
		{ class: 'section-primary users-table-filter-bar' },
		form(
			{ action: '/flow/rejections', autoSubmit: true },
			div({ class: 'users-table-filter-bar-status' },
				selectService({ label: _("All services") })),
			div(
				{ class: 'users-table-filter-bar-status' },
				label({ for: 'date-from-input' }, _("Date from"), ":"),
				selectDateFrom()
			),
			div(
				{ class: 'users-table-filter-bar-status' },
				label({ for: 'date-to-input' }, _("Date to"), ":"),
				selectDateTo()
			),
			p({ class: 'submit' }, input({ type: 'submit' }))
		)
	);
};
<|endoftext|>


<commit_before>/**
 * ComboBoxInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value
 * can be entered manually) and a {@link OO.ui.MenuSelectWidget menu of options} (from which
 * a value can be chosen instead). Users can choose options from the combo box in one of two ways:
 *
 * - by typing a value in the text input field. If the value exactly matches the value of a menu
 *   option, that option will appear to be selected.
 * - by choosing a value from the menu. The value of the chosen option will then appear in the text
 *   input field.
 *
 * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
 *
 * For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
 *
 *     @example
 *     // Example: A ComboBoxInputWidget.
 *     var comboBox = new OO.ui.ComboBoxInputWidget( {
 *         label: 'ComboBoxInputWidget',
 *         value: 'Option 1',
 *         menu: {
 *             items: [
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 1',
 *                     label: 'Option One'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 2',
 *                     label: 'Option Two'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 3',
 *                     label: 'Option Three'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 4',
 *                     label: 'Option Four'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 5',
 *                     label: 'Option Five'
 *                 } )
 *             ]
 *         }
 *     } );
 *     $( 'body' ).append( comboBox.$element );
 *
 * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
 *
 * @class
 * @extends OO.ui.TextInputWidget
 *
 * @constructor
 * @param {Object} [config] Configuration options
 * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
 * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.FloatingMenuSelectWidget menu select widget}.
 * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful in cases where
 *  the expanded menu is larger than its containing `<div>`. The specified overlay layer is usually on top of the
 *  containing `<div>` and has a larger area. By default, the menu uses relative positioning.
 */
OO.ui.ComboBoxInputWidget = function OoUiComboBoxInputWidget( config ) {
	// Configuration initialization
	config = $.extend( {
		autocomplete: false
	}, config );

	// Parent constructor
	OO.ui.ComboBoxInputWidget.parent.call( this, config );

	// Properties
	this.$overlay = config.$overlay || this.$element;
	this.dropdownButton = new OO.ui.ButtonWidget( {
		classes: [ 'oo-ui-comboBoxInputWidget-dropdownButton' ],
		indicator: 'down',
		disabled: this.disabled
	} );
	this.menu = new OO.ui.FloatingMenuSelectWidget( $.extend(
		{
			widget: this,
			input: this,
			$container: this.$element,
			disabled: this.isDisabled()
		},
		config.menu
	) );

	// Events
	this.connect( this, {
		change: 'onInputChange',
		enter: 'onInputEnter'
	} );
	this.dropdownButton.connect( this, {
		click: 'onDropdownButtonClick'
	} );
	this.menu.connect( this, {
		choose: 'onMenuChoose',
		add: 'onMenuItemsChange',
		remove: 'onMenuItemsChange'
	} );

	// Initialization
	this.$input.attr( {
		role: 'combobox',
		'aria-autocomplete': 'list'
	} );
	// Do not override options set via config.menu.items
	if ( config.options !== undefined ) {
		this.setOptions( config.options );
	}
	this.$field = $( '<div>' )
		.addClass( 'oo-ui-comboBoxInputWidget-field' )
		.append( this.$input, this.dropdownButton.$element );
	this.$element.append( this.$field );
	this.$overlay.append( this.menu.$element );
	this.onMenuItemsChange();
};

/* Setup */

OO.inheritClass( OO.ui.ComboBoxInputWidget, OO.ui.TextInputWidget );

/* Methods */

/**
 * Get the combobox's menu.
 *
 * @return {OO.ui.FloatingMenuSelectWidget} Menu widget
 */
OO.ui.ComboBoxInputWidget.prototype.getMenu = function () {
	return this.menu;
};

/**
 * Get the combobox's text input widget.
 *
 * @return {OO.ui.TextInputWidget} Text input widget
 */
OO.ui.ComboBoxInputWidget.prototype.getInput = function () {
	return this;
};

/**
 * Handle input change events.
 *
 * @private
 * @param {string} value New value
 */
OO.ui.ComboBoxInputWidget.prototype.onInputChange = function ( value ) {
	var match = this.menu.getItemFromData( value );

	this.menu.selectItem( match );
	if ( this.menu.getHighlightedItem() ) {
		this.menu.highlightItem( match );
	}

	if ( !this.isDisabled() ) {
		this.menu.toggle( true );
	}
};

/**
 * Handle input enter events.
 *
 * @private
 */
OO.ui.ComboBoxInputWidget.prototype.onInputEnter = function () {
	if ( !this.isDisabled() ) {
		this.menu.toggle( false );
	}
};

/**
 * Handle button click events.
 *
 * @private
 */
OO.ui.ComboBoxInputWidget.prototype.onDropdownButtonClick = function () {
	this.menu.toggle();
	this.$input[ 0 ].focus();
};

/**
 * Handle menu choose events.
 *
 * @private
 * @param {OO.ui.OptionWidget} item Chosen item
 */
OO.ui.ComboBoxInputWidget.prototype.onMenuChoose = function ( item ) {
	this.setValue( item.getData() );
};

/**
 * Handle menu item change events.
 *
 * @private
 */
OO.ui.ComboBoxInputWidget.prototype.onMenuItemsChange = function () {
	var match = this.menu.getItemFromData( this.getValue() );
	this.menu.selectItem( match );
	if ( this.menu.getHighlightedItem() ) {
		this.menu.highlightItem( match );
	}
	this.$element.toggleClass( 'oo-ui-comboBoxInputWidget-empty', this.menu.isEmpty() );
};

/**
 * @inheritdoc
 */
OO.ui.ComboBoxInputWidget.prototype.setDisabled = function ( disabled ) {
	// Parent method
	OO.ui.ComboBoxInputWidget.parent.prototype.setDisabled.call( this, disabled );

	if ( this.dropdownButton ) {
		this.dropdownButton.setDisabled( this.isDisabled() );
	}
	if ( this.menu ) {
		this.menu.setDisabled( this.isDisabled() );
	}

	return this;
};

/**
 * Set the options available for this input.
 *
 * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`
 * @chainable
 */
OO.ui.ComboBoxInputWidget.prototype.setOptions = function ( options ) {
	this.getMenu()
		.clearItems()
		.addItems( options.map( function ( opt ) {
			return new OO.ui.MenuOptionWidget( {
				data: opt.data,
				label: opt.label !== undefined ? opt.label : opt.data
			} );
		} ) );

	return this;
};
<commit_msg>Follow-up 294c244: Don't remove the useful class, just the old one<commit_after>/**
 * ComboBoxInputWidgets combine a {@link OO.ui.TextInputWidget text input} (where a value
 * can be entered manually) and a {@link OO.ui.MenuSelectWidget menu of options} (from which
 * a value can be chosen instead). Users can choose options from the combo box in one of two ways:
 *
 * - by typing a value in the text input field. If the value exactly matches the value of a menu
 *   option, that option will appear to be selected.
 * - by choosing a value from the menu. The value of the chosen option will then appear in the text
 *   input field.
 *
 * This widget can be used inside a HTML form, such as a OO.ui.FormLayout.
 *
 * For more information about menus and options, please see the [OOjs UI documentation on MediaWiki][1].
 *
 *     @example
 *     // Example: A ComboBoxInputWidget.
 *     var comboBox = new OO.ui.ComboBoxInputWidget( {
 *         label: 'ComboBoxInputWidget',
 *         value: 'Option 1',
 *         menu: {
 *             items: [
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 1',
 *                     label: 'Option One'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 2',
 *                     label: 'Option Two'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 3',
 *                     label: 'Option Three'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 4',
 *                     label: 'Option Four'
 *                 } ),
 *                 new OO.ui.MenuOptionWidget( {
 *                     data: 'Option 5',
 *                     label: 'Option Five'
 *                 } )
 *             ]
 *         }
 *     } );
 *     $( 'body' ).append( comboBox.$element );
 *
 * [1]: https://www.mediawiki.org/wiki/OOjs_UI/Widgets/Selects_and_Options#Menu_selects_and_options
 *
 * @class
 * @extends OO.ui.TextInputWidget
 *
 * @constructor
 * @param {Object} [config] Configuration options
 * @cfg {Object[]} [options=[]] Array of menu options in the format `{ data: …, label: … }`
 * @cfg {Object} [menu] Configuration options to pass to the {@link OO.ui.FloatingMenuSelectWidget menu select widget}.
 * @cfg {jQuery} [$overlay] Render the menu into a separate layer. This configuration is useful in cases where
 *  the expanded menu is larger than its containing `<div>`. The specified overlay layer is usually on top of the
 *  containing `<div>` and has a larger area. By default, the menu uses relative positioning.
 */
OO.ui.ComboBoxInputWidget = function OoUiComboBoxInputWidget( config ) {
	// Configuration initialization
	config = $.extend( {
		autocomplete: false
	}, config );

	// Parent constructor
	OO.ui.ComboBoxInputWidget.parent.call( this, config );

	// Properties
	this.$overlay = config.$overlay || this.$element;
	this.dropdownButton = new OO.ui.ButtonWidget( {
		classes: [ 'oo-ui-comboBoxInputWidget-dropdownButton' ],
		indicator: 'down',
		disabled: this.disabled
	} );
	this.menu = new OO.ui.FloatingMenuSelectWidget( $.extend(
		{
			widget: this,
			input: this,
			$container: this.$element,
			disabled: this.isDisabled()
		},
		config.menu
	) );

	// Events
	this.connect( this, {
		change: 'onInputChange',
		enter: 'onInputEnter'
	} );
	this.dropdownButton.connect( this, {
		click: 'onDropdownButtonClick'
	} );
	this.menu.connect( this, {
		choose: 'onMenuChoose',
		add: 'onMenuItemsChange',
		remove: 'onMenuItemsChange'
	} );

	// Initialization
	this.$input.attr( {
		role: 'combobox',
		'aria-autocomplete': 'list'
	} );
	// Do not override options set via config.menu.items
	if ( config.options !== undefined ) {
		this.setOptions( config.options );
	}
	this.$field = $( '<div>' )
		.addClass( 'oo-ui-comboBoxInputWidget-field' )
		.append( this.$input, this.dropdownButton.$element );
	this.$element
		.addClass( 'oo-ui-comboBoxInputWidget' )
		.append( this.$field );
	this.$overlay.append( this.menu.$element );
	this.onMenuItemsChange();
};

/* Setup */

OO.inheritClass( OO.ui.ComboBoxInputWidget, OO.ui.TextInputWidget );

/* Methods */

/**
 * Get the combobox's menu.
 *
 * @return {OO.ui.FloatingMenuSelectWidget} Menu widget
 */
OO.ui.ComboBoxInputWidget.prototype.getMenu = function () {
	return this.menu;
};

/**
 * Get the combobox's text input widget.
 *
 * @return {OO.ui.TextInputWidget} Text input widget
 */
OO.ui.ComboBoxInputWidget.prototype.getInput = function () {
	return this;
};

/**
 * Handle input change events.
 *
 * @private
 * @param {string} value New value
 */
OO.ui.ComboBoxInputWidget.prototype.onInputChange = function ( value ) {
	var match = this.menu.getItemFromData( value );

	this.menu.selectItem( match );
	if ( this.menu.getHighlightedItem() ) {
		this.menu.highlightItem( match );
	}

	if ( !this.isDisabled() ) {
		this.menu.toggle( true );
	}
};

/**
 * Handle input enter events.
 *
 * @private
 */
OO.ui.ComboBoxInputWidget.prototype.onInputEnter = function () {
	if ( !this.isDisabled() ) {
		this.menu.toggle( false );
	}
};

/**
 * Handle button click events.
 *
 * @private
 */
OO.ui.ComboBoxInputWidget.prototype.onDropdownButtonClick = function () {
	this.menu.toggle();
	this.$input[ 0 ].focus();
};

/**
 * Handle menu choose events.
 *
 * @private
 * @param {OO.ui.OptionWidget} item Chosen item
 */
OO.ui.ComboBoxInputWidget.prototype.onMenuChoose = function ( item ) {
	this.setValue( item.getData() );
};

/**
 * Handle menu item change events.
 *
 * @private
 */
OO.ui.ComboBoxInputWidget.prototype.onMenuItemsChange = function () {
	var match = this.menu.getItemFromData( this.getValue() );
	this.menu.selectItem( match );
	if ( this.menu.getHighlightedItem() ) {
		this.menu.highlightItem( match );
	}
	this.$element.toggleClass( 'oo-ui-comboBoxInputWidget-empty', this.menu.isEmpty() );
};

/**
 * @inheritdoc
 */
OO.ui.ComboBoxInputWidget.prototype.setDisabled = function ( disabled ) {
	// Parent method
	OO.ui.ComboBoxInputWidget.parent.prototype.setDisabled.call( this, disabled );

	if ( this.dropdownButton ) {
		this.dropdownButton.setDisabled( this.isDisabled() );
	}
	if ( this.menu ) {
		this.menu.setDisabled( this.isDisabled() );
	}

	return this;
};

/**
 * Set the options available for this input.
 *
 * @param {Object[]} options Array of menu options in the format `{ data: …, label: … }`
 * @chainable
 */
OO.ui.ComboBoxInputWidget.prototype.setOptions = function ( options ) {
	this.getMenu()
		.clearItems()
		.addItems( options.map( function ( opt ) {
			return new OO.ui.MenuOptionWidget( {
				data: opt.data,
				label: opt.label !== undefined ? opt.label : opt.data
			} );
		} ) );

	return this;
};
<|endoftext|>


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

import { SUSSOL_ORANGE, APP_FONT_FAMILY, DARKER_GREY, FINALISED_RED } from '../globalStyles/index';

export const ValidationTextInput = ({
  placeholder,
  placeholderTextColor,
  underlineColorAndroid,
  isRequired,
  label,
  invalidMessage,
  onSubmitEditing,
  onValidate,
  onChangeValidState,
  value,
  labelStyle,
  isRequiredStyle,
  invalidMessageStyle,
  textInputStyle,
}) => {
  const [inputState, setInputState] = React.useState({
    isValid: true,
    inputValue: value,
  });
  const { inputValue, isValid } = inputState;
  const { flexRow, flexColumn } = localStyles;

  const IsRequiredLabel = () =>
    isRequired && <Text style={isRequiredStyle}>{validationStrings.is_required}</Text>;
  const InvalidMessageLabel = () =>
    !isValid && <Text style={invalidMessageStyle}>{invalidMessage}</Text>;

  const onCheckValidity = React.useCallback(
    inputToCheck => {
      const newValidState = onValidate(inputToCheck);
      if (newValidState !== isValid) onChangeValidState(newValidState);
      return newValidState;
    },
    [isValid]
  );

  const onCompletedInput = React.useCallback(() => {
    onSubmitEditing(inputValue);
  }, []);

  const onChangeText = React.useCallback(
    newValue => {
      const newValidState = onCheckValidity(newValue);
      setInputState({ isValid: newValidState, inputValue: newValue });
    },
    [isValid, onChangeValidState]
  );

  React.useEffect(() => {
    onChangeText(value);
  }, [value]);

  return (
    <View style={flexColumn}>
      <View style={flexRow}>
        <View>
          <Text style={labelStyle}>{label}</Text>
          <IsRequiredLabel />
        </View>
        <View style={flexColumn}>
          <TextInput
            style={textInputStyle}
            value={inputValue}
            placeholderTextColor={placeholderTextColor}
            underlineColorAndroid={underlineColorAndroid}
            placeholder={placeholder}
            selectTextOnFocus
            returnKeyType="next"
            autoCapitalize="none"
            autoCorrect={false}
            onChangeText={onChangeText}
            onBlur={onCompletedInput}
            onSubmitEditing={onCompletedInput}
          />
          <InvalidMessageLabel />
        </View>
      </View>
    </View>
  );
};

const localStyles = StyleSheet.create({
  flexRow: { flex: 1, flexDirection: 'row' },
  flexColumn: { flex: 1, flexDirection: 'column' },
  labelStyle: { marginTop: 15, fontSize: 16, fontFamily: APP_FONT_FAMILY },
  isRequiredStyle: { fontSize: 12, color: SUSSOL_ORANGE, fontFamily: APP_FONT_FAMILY },
  invalidMessageStyle: { color: FINALISED_RED, fontFamily: APP_FONT_FAMILY },
  textInputStyle: { flex: 1, fontFamily: APP_FONT_FAMILY },
});

ValidationTextInput.defaultProps = {
  placeholder: '',
  placeholderTextColor: SUSSOL_ORANGE,
  underlineColorAndroid: DARKER_GREY,
  value: '',
  isRequired: true,
  invalidMessage: 'asdasdasdasdaszzzzzzzzzzz',
  labelStyle: localStyles.labelStyle,
  isRequiredStyle: localStyles.isRequiredStyle,
  invalidMessageStyle: localStyles.invalidMessageStyle,
  textInputStyle: localStyles.textInputStyle,
};

ValidationTextInput.propTypes = {
  placeholder: PropTypes.string,
  placeholderTextColor: PropTypes.string,
  underlineColorAndroid: PropTypes.string,
  onSubmitEditing: PropTypes.func.isRequired,
  onValidate: PropTypes.func.isRequired,
  onChangeValidState: PropTypes.func.isRequired,
  value: PropTypes.string,
  isRequired: PropTypes.bool,
  label: PropTypes.string.isRequired,
  invalidMessage: PropTypes.string,
  labelStyle: PropTypes.object,
  isRequiredStyle: PropTypes.object,
  invalidMessageStyle: PropTypes.object,
  textInputStyle: PropTypes.object,
};
<commit_msg>Add docstring to ValidationTextInput<commit_after>/* eslint-disable react/forbid-prop-types */
import React from 'react';
import { View, Text, TextInput, StyleSheet } from 'react-native';
import PropTypes from 'prop-types';
import { validationStrings } from '../localization';

import { SUSSOL_ORANGE, APP_FONT_FAMILY, DARKER_GREY, FINALISED_RED } from '../globalStyles/index';

/**
 * Uncontrolled wrapper component around a TextInput with validation
 * and labels.
 * @prop {String} placeholder           Placeholder text string
 * @prop {String} placeholderTextColor  Color of the placeholder text
 * @prop {String} underlineColorAndroid Color of the underline colour
 * @prop {Bool}   isRequired            Indicator whether to show the is required label
 * @prop {String} label                 The form label for this text input, displayed to the left.
 * @prop {String} invalidMessage        Displayed under the TextInput when the input is invalid.
 * @prop {Func}   onSubmitEditing       Callback when editing has completed.
 * @prop {Func}   onValidate            Function determining if the current input value is valid.
 * @prop {Func}   onChangeValidState    Callback when the validity state changes.
 * @prop {String} value                 The initial value of the input.
 * @prop {Object} labelStyle            Style of the label.
 * @prop {Object} isRequiredStyle       Style for the is required label.
 * @prop {Object} invalidMessageStyle   Style for the invalid message label.
 * @prop {Object} textInputStyle        Style of the underlying TextInput.
 */
export const ValidationTextInput = ({
  placeholder,
  placeholderTextColor,
  underlineColorAndroid,
  isRequired,
  label,
  invalidMessage,
  onSubmitEditing,
  onValidate,
  onChangeValidState,
  value,
  labelStyle,
  isRequiredStyle,
  invalidMessageStyle,
  textInputStyle,
}) => {
  const [inputState, setInputState] = React.useState({
    isValid: true,
    inputValue: value,
  });
  const { inputValue, isValid } = inputState;
  const { flexRow, flexColumn } = localStyles;

  const IsRequiredLabel = () =>
    isRequired && <Text style={isRequiredStyle}>{validationStrings.is_required}</Text>;
  const InvalidMessageLabel = () =>
    !isValid && <Text style={invalidMessageStyle}>{invalidMessage}</Text>;

  const onCheckValidity = React.useCallback(
    inputToCheck => {
      const newValidState = onValidate(inputToCheck);
      if (newValidState !== isValid) onChangeValidState(newValidState);
      return newValidState;
    },
    [isValid]
  );

  const onCompletedInput = React.useCallback(() => {
    onSubmitEditing(inputValue);
  }, []);

  const onChangeText = React.useCallback(
    newValue => {
      const newValidState = onCheckValidity(newValue);
      setInputState({ isValid: newValidState, inputValue: newValue });
    },
    [isValid, onChangeValidState]
  );

  React.useEffect(() => {
    onChangeText(value);
  }, [value]);

  return (
    <View style={flexColumn}>
      <View style={flexRow}>
        <View>
          <Text style={labelStyle}>{label}</Text>
          <IsRequiredLabel />
        </View>
        <View style={flexColumn}>
          <TextInput
            style={textInputStyle}
            value={inputValue}
            placeholderTextColor={placeholderTextColor}
            underlineColorAndroid={underlineColorAndroid}
            placeholder={placeholder}
            selectTextOnFocus
            returnKeyType="next"
            autoCapitalize="none"
            autoCorrect={false}
            onChangeText={onChangeText}
            onBlur={onCompletedInput}
            onSubmitEditing={onCompletedInput}
          />
          <InvalidMessageLabel />
        </View>
      </View>
    </View>
  );
};

const localStyles = StyleSheet.create({
  flexRow: { flex: 1, flexDirection: 'row' },
  flexColumn: { flex: 1, flexDirection: 'column' },
  labelStyle: { marginTop: 15, fontSize: 16, fontFamily: APP_FONT_FAMILY },
  isRequiredStyle: { fontSize: 12, color: SUSSOL_ORANGE, fontFamily: APP_FONT_FAMILY },
  invalidMessageStyle: { color: FINALISED_RED, fontFamily: APP_FONT_FAMILY },
  textInputStyle: { flex: 1, fontFamily: APP_FONT_FAMILY },
});

ValidationTextInput.defaultProps = {
  placeholder: '',
  placeholderTextColor: SUSSOL_ORANGE,
  underlineColorAndroid: DARKER_GREY,
  value: '',
  isRequired: true,
  invalidMessage: 'asdasdasdasdaszzzzzzzzzzz',
  labelStyle: localStyles.labelStyle,
  isRequiredStyle: localStyles.isRequiredStyle,
  invalidMessageStyle: localStyles.invalidMessageStyle,
  textInputStyle: localStyles.textInputStyle,
};

ValidationTextInput.propTypes = {
  placeholder: PropTypes.string,
  placeholderTextColor: PropTypes.string,
  underlineColorAndroid: PropTypes.string,
  onSubmitEditing: PropTypes.func.isRequired,
  onValidate: PropTypes.func.isRequired,
  onChangeValidState: PropTypes.func.isRequired,
  value: PropTypes.string,
  isRequired: PropTypes.bool,
  label: PropTypes.string.isRequired,
  invalidMessage: PropTypes.string,
  labelStyle: PropTypes.object,
  isRequiredStyle: PropTypes.object,
  invalidMessageStyle: PropTypes.object,
  textInputStyle: PropTypes.object,
};
<|endoftext|>


<commit_before>define([
    'd3',
    'widgets/widget',
], function(d3, Widget) {
    var barChart = Widget.extend({
        init: function(context, options) {
            this.name = 'bar-chart';
            this._super(context, options);
        },

        render: function() {
            var height = 500,
                width = 900,
                margin = 50,
                placeholder = d3.select(this.placeholder),
                measures = placeholder.node().getBoundingClientRect(),
                svg = placeholder.append('svg')
                    .attr('height', measures.height)
                    .attr('width', measures.width)
                    .classed(this.name, true)
                    .append('g'),
                x = d3.scale.ordinal().rangeRoundBands([0, width], .1, .3),
                y = d3.scale.linear().range([height, 0]),
                xAxis = d3.svg.axis().scale(x).orient('bottom'),
                yAxis = d3.svg.axis().scale(y).orient('left'),
                translate = this.i18n.translate,
                data = { stats: {} },
                indicator = this.state.yaxis.indicator,
                time = this.state.time;

            var mock = [
                { name: 'Sweden', value: 10 },
                { name: 'Angola', value: 100 },
                { name: 'Magnolia', value: 80 },
                { name: 'Nicole Kidman', value: 50 }
            ];

            var loadEverything = $.when(
              $.ajax(this.state.data.paths.waffle + 'waffle-' + this.state.language + '.json'),
              $.ajax(this.state.data.paths.stats + this.state.yaxis.indicator + '.json'),
              $.ajax(this.state.data.paths.stats + "lex" + '.json')
            ).then(function(waffle, stats, stats2) {
              $.extend(true, data, waffle[0]);
              if (!data.stats[indicator]) data.stats[indicator] = {};
              $.extend(true, data.stats[this.state.yaxis.indicator], stats[0]);
            }.bind(this)).done(function() {
              // Aliases
              var show = parseShowableObjects(this.state.show);
              var indicatorData = data.definitions.indicators[indicator];
              var category = data.definitions.categories;
              var stats = data.stats[indicator];

              x.domain(show.map(function(d) { return category[d.category].things[d.id].name; }));
              y.domain([0, d3.max(d3.entries(stats), function(d) { if (d.value[time]) return d.value[time].v; })]);

              var formatValue = d3.format(".1s");
              yAxis.tickFormat(function(d) { return formatValue(d); })

              svg.append('g')
                  .attr('class', 'y axis')
                  .attr('transform', 'translate(' + margin + ',' + margin + ')')
                  .call(yAxis);

              var chart = svg.selectAll(".bar")
                  .data(show)
                  .enter();

              chart.append("rect")
                  .attr("class", "bar")
                  .attr("x", function(d) { return margin + x(category[d.category].things[d.id].name); })
                  .attr("width", x.rangeBand())
                  .attr("y", function(d) { return margin + 15 + y(stats[d.id][time].v); })
                  .attr("height", function(d) { return height - 15 - y(stats[d.id][time].v); });

              chart.append('text')
                  .classed('bar-title', true)
                  .attr('y', function(d) { return margin + 5 + y(stats[d.id][time].v); })
                  .attr('x', function(d) { return margin + x(category[d.category].things[d.id].name) + (x.rangeBand() / 2); })
                  .text(function(d) { return category[d.category].things[d.id].name; });

              svg.append('g')
                  .attr('class', 'x axis')
                  .attr('transform', 'translate(' + margin + ',' + (margin + height) + ')')
                  .call(xAxis)
                  .selectAll('.tick text')
                  .remove();

              svg.append('text')
                  .attr('class', 'title')
                  .attr('transform', 'translate(' + (margin + 15) + ',' + (margin + 15) + ')')
                  .text(indicatorData.name);
            }.bind(this));
        },

        resize: function() {

        }
    });

    function parseShowableObjects(show) {
      var parsed = [];

      for (var category in show) {
        if ($.isEmptyObject(show[category])) {
          parsed.push({ category: category, id: category });
        } else {
          for (var id in show[category].filter) {
            parsed.push({ category: category, id: show[category].filter[id] });
          }
        }
      }

      return parsed;
    }

    return barChart;
});
<commit_msg>Removed mock data<commit_after>define([
    'd3',
    'widgets/widget',
], function(d3, Widget) {
    var barChart = Widget.extend({
        init: function(context, options) {
            this.name = 'bar-chart';
            this._super(context, options);
        },

        render: function() {
            var height = 500,
                width = 900,
                margin = 50,
                placeholder = d3.select(this.placeholder),
                measures = placeholder.node().getBoundingClientRect(),
                svg = placeholder.append('svg')
                    .attr('height', measures.height)
                    .attr('width', measures.width)
                    .classed(this.name, true)
                    .append('g'),
                x = d3.scale.ordinal().rangeRoundBands([0, width], .1, .3),
                y = d3.scale.linear().range([height, 0]),
                xAxis = d3.svg.axis().scale(x).orient('bottom'),
                yAxis = d3.svg.axis().scale(y).orient('left'),
                translate = this.i18n.translate,
                data = { stats: {} },
                indicator = this.state.yaxis.indicator,
                time = this.state.time;

            var loadEverything = $.when(
              $.ajax(this.state.data.paths.waffle + 'waffle-' + this.state.language + '.json'),
              $.ajax(this.state.data.paths.stats + this.state.yaxis.indicator + '.json'),
              $.ajax(this.state.data.paths.stats + "lex" + '.json')
            ).then(function(waffle, stats, stats2) {
              $.extend(true, data, waffle[0]);
              if (!data.stats[indicator]) data.stats[indicator] = {};
              $.extend(true, data.stats[this.state.yaxis.indicator], stats[0]);
            }.bind(this)).done(function() {
              // Aliases
              var show = parseShowableObjects(this.state.show);
              var indicatorData = data.definitions.indicators[indicator];
              var category = data.definitions.categories;
              var stats = data.stats[indicator];

              x.domain(show.map(function(d) { return category[d.category].things[d.id].name; }));
              y.domain([0, d3.max(d3.entries(stats), function(d) { if (d.value[time]) return d.value[time].v; })]);

              var formatValue = d3.format(".1s");
              yAxis.tickFormat(function(d) { return formatValue(d); })

              svg.append('g')
                  .attr('class', 'y axis')
                  .attr('transform', 'translate(' + margin + ',' + margin + ')')
                  .call(yAxis);

              var chart = svg.selectAll(".bar")
                  .data(show)
                  .enter();

              chart.append("rect")
                  .attr("class", "bar")
                  .attr("x", function(d) { return margin + x(category[d.category].things[d.id].name); })
                  .attr("width", x.rangeBand())
                  .attr("y", function(d) { return margin + 15 + y(stats[d.id][time].v); })
                  .attr("height", function(d) { return height - 15 - y(stats[d.id][time].v); });

              chart.append('text')
                  .classed('bar-title', true)
                  .attr('y', function(d) { return margin + 5 + y(stats[d.id][time].v); })
                  .attr('x', function(d) { return margin + x(category[d.category].things[d.id].name) + (x.rangeBand() / 2); })
                  .text(function(d) { return category[d.category].things[d.id].name; });

              svg.append('g')
                  .attr('class', 'x axis')
                  .attr('transform', 'translate(' + margin + ',' + (margin + height) + ')')
                  .call(xAxis)
                  .selectAll('.tick text')
                  .remove();

              svg.append('text')
                  .attr('class', 'title')
                  .attr('transform', 'translate(' + (margin + 15) + ',' + (margin + 15) + ')')
                  .text(indicatorData.name);
            }.bind(this));
        },

        resize: function() {

        }
    });

    function parseShowableObjects(show) {
      var parsed = [];

      for (var category in show) {
        if ($.isEmptyObject(show[category])) {
          parsed.push({ category: category, id: category });
        } else {
          for (var id in show[category].filter) {
            parsed.push({ category: category, id: show[category].filter[id] });
          }
        }
      }

      return parsed;
    }

    return barChart;
});
<|endoftext|>


<commit_before>/**
 * Flotr Axis Library
 */

(function () {

var
  _ = Flotr._,
  LOGARITHMIC = 'logarithmic';

function Axis (o) {

  this.orientation = 1;
  this.offset = 0;
  this.datamin = Number.MAX_VALUE;
  this.datamax = -Number.MAX_VALUE;

  _.extend(this, o);

  this._setTranslations();
}

// Prototype
Axis.prototype = {

  setScale : function () {
    var length = this.length;
    if (this.options.scaling == LOGARITHMIC) {
      this.scale = length / (log(this.max, this.options.base) - log(this.min, this.options.base));
    } else {
      this.scale = length / (this.max - this.min);
    }
  },

  calculateTicks : function () {
    var options = this.options;

    this.ticks = [];
    this.minorTicks = [];

    // User Ticks
    if(options.ticks){
      this._cleanUserTicks(options.ticks, this.ticks);
      this._cleanUserTicks(options.minorTicks || [], this.minorTicks);
    }
    else {
      if (options.mode == 'time') {
        this._calculateTimeTicks();
      } else if (options.scaling === 'logarithmic') {
        this._calculateLogTicks();
      } else {
        this._calculateTicks();
      }
    }
  },

  /**
   * Calculates the range of an axis to apply autoscaling.
   */
  calculateRange: function () {

    if (!this.used) return;

    var axis  = this,
      o       = axis.options,
      min     = o.min !== null ? o.min : axis.datamin,
      max     = o.max !== null ? o.max : axis.datamax,
      margin  = o.autoscaleMargin;

    if (o.scaling == 'logarithmic') {
      if (min <= 0) min = axis.datamin;

      // Let it widen later on
      if (max <= 0) max = min;
    }

    if (max == min) {
      var widen = max ? 0.01 : 1.00;
      min -= widen;
      max += widen;
    }

    if (o.scaling === 'logarithmic') {
      if (min < 0) min = max / o.base;  // Could be the result of widening

      var maxexp = Math.log(max);
      if (o.base != Math.E) maxexp /= Math.log(o.base);
      maxexp = Math.ceil(maxexp);

      var minexp = Math.log(min);
      if (o.base != Math.E) minexp /= Math.log(o.base);
      minexp = Math.ceil(minexp);

      axis.tickSize = Flotr.getTickSize(o.noTicks, minexp, maxexp, o.tickDecimals === null ? 0 : o.tickDecimals);

      // Try to determine a suitable amount of miniticks based on the length of a decade
      if (o.minorTickFreq === null) {
        if (maxexp - minexp > 10)
          o.minorTickFreq = 0;
        else if (maxexp - minexp > 5)
          o.minorTickFreq = 2;
        else
          o.minorTickFreq = 5;
      }
    } else {
      axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals);
    }

    axis.min = min;
    axis.max = max; //extendRange may use axis.min or axis.max, so it should be set before it is caled

    // Autoscaling. @todo This probably fails with log scale. Find a testcase and fix it
    if(o.min === null && o.autoscale){
      axis.min -= axis.tickSize * margin;
      // Make sure we don't go below zero if all values are positive.
      if(axis.min < 0 && axis.datamin >= 0) axis.min = 0;
      axis.min = axis.tickSize * Math.floor(axis.min / axis.tickSize);
    }

    if(o.max === null && o.autoscale){
      axis.max += axis.tickSize * margin;
      if(axis.max > 0 && axis.datamax <= 0 && axis.datamax != axis.datamin) axis.max = 0;
      axis.max = axis.tickSize * Math.ceil(axis.max / axis.tickSize);
    }

    if (axis.min == axis.max) axis.max = axis.min + 1;
  },

  calculateTextDimensions : function (T, options) {

    var maxLabel = '',
      length,
      i;

    if (this.options.showLabels) {
      for (i = 0; i < this.ticks.length; ++i) {
        length = this.ticks[i].label.length;
        if (length > maxLabel.length){
          maxLabel = this.ticks[i].label;
        }
      }
    }

    this.maxLabel = T.dimensions(
      maxLabel,
      {size:options.fontSize, angle: Flotr.toRad(this.options.labelsAngle)},
      'font-size:smaller;',
      'flotr-grid-label'
    );

    this.titleSize = T.dimensions(
      this.options.title,
      {size:options.fontSize*1.2, angle: Flotr.toRad(this.options.titleAngle)},
      'font-weight:bold;',
      'flotr-axis-title'
    );
  },

  _cleanUserTicks : function (ticks, axisTicks) {

    var axis = this, options = this.options,
      v, i, label, tick;

    if(_.isFunction(ticks)) ticks = ticks({min : axis.min, max : axis.max});

    for(i = 0; i < ticks.length; ++i){
      tick = ticks[i];
      if(typeof(tick) === 'object'){
        v = tick[0];
        label = (tick.length > 1) ? tick[1] : options.tickFormatter(v, {min : axis.min, max : axis.max});
      } else {
        v = tick;
        label = options.tickFormatter(v, {min : this.min, max : this.max});
      }
      axisTicks[i] = { v: v, label: label };
    }
  },

  _calculateTimeTicks : function () {
    var axis = this,
        tu = Flotr.Date.timeUnits,
        spec = Flotr.Date.spec,
        delta = (axis.max - axis.min) / axis.options.noTicks,
        size, unit, i;

    for (i = 0; i < spec.length - 1; ++i) {
      var d = spec[i][0] * tu[spec[i][1]];
      if (delta < (d + spec[i+1][0] * tu[spec[i+1][1]]) / 2 && d >= axis.tickSize)
        break;
    }
    size = spec[i][0];
    unit = spec[i][1];

    // special-case the possibility of several years
    if (unit == "year") {
      size = Flotr.getTickSize(axis.options.noTicks*tu.year, axis.min, axis.max, 0);
    }

    axis.tickSize = size;
    axis.tickUnit = unit;
    axis.ticks = Flotr.Date.generator(axis);
  },

  _calculateLogTicks : function () {

    var axis = this,
      o = axis.options,
      v,
      decadeStart;

    var max = Math.log(axis.max);
    if (o.base != Math.E) max /= Math.log(o.base);
    max = Math.ceil(max);

    var min = Math.log(axis.min);
    if (o.base != Math.E) min /= Math.log(o.base);
    min = Math.ceil(min);

    for (i = min; i < max; i += axis.tickSize) {
      decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
      // Next decade begins here:
      var decadeEnd = decadeStart * ((o.base == Math.E) ? Math.exp(axis.tickSize) : Math.pow(o.base, axis.tickSize));
      var stepSize = (decadeEnd - decadeStart) / o.minorTickFreq;

      axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})});
      for (v = decadeStart + stepSize; v < decadeEnd; v += stepSize)
        axis.minorTicks.push({v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max})});
    }

    // Always show the value at the would-be start of next decade (end of this decade)
    decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
    axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})});
  },

  _calculateTicks : function () {

    var axis      = this,
        o         = axis.options,
        tickSize  = axis.tickSize,
        min       = axis.min,
        max       = axis.max,
        start     = tickSize * Math.ceil(min / tickSize), // Round to nearest multiple of tick size.
        decimals,
        minorTickSize,
        v, v2,
        i, j;

    if (o.minorTickFreq)
      minorTickSize = tickSize / o.minorTickFreq;

    // Then store all possible ticks.
    for (i = 0; (v = v2 = start + i * tickSize) <= max; ++i){

      // Round (this is always needed to fix numerical instability).
      decimals = o.tickDecimals;
      if (decimals === null) decimals = 1 - Math.floor(Math.log(tickSize) / Math.LN10);
      if (decimals < 0) decimals = 0;

      v = v.toFixed(decimals);
      axis.ticks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) });

      if (o.minorTickFreq) {
        for (j = 0; j < o.minorTickFreq && (i * tickSize + j * minorTickSize) < max; ++j) {
          v = (v2 + j * minorTickSize).toFixed(decimals);
          axis.minorTicks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) });
        }
      }
    }

  },

  _setTranslations : function (logarithmic) {
    this.d2p = (logarithmic ? d2pLog : d2p);
    this.p2d = (logarithmic ? p2dLog : p2d);
  }
};

// Static Methods
_.extend(Axis, {
  getAxes : function (options) {
    return {
      x:  new Axis({options: options.xaxis,  n: 1, length: this.plotWidth}),
      x2: new Axis({options: options.x2axis, n: 2, length: this.plotWidth}),
      y:  new Axis({options: options.yaxis,  n: 1, length: this.plotHeight, offset: this.plotHeight, orientation: -1}),
      y2: new Axis({options: options.y2axis, n: 2, length: this.plotHeight, offset: this.plotHeight, orientation: -1})
    };
  }
});

// Helper Methods

function d2p (dataValue) {
  return this.offset + this.orientation * (dataValue - this.min) * this.scale;
}

function p2d (pointValue) {
  return (this.offset + this.orientation * pointValue) / this.scale + this.min;
}

function d2pLog (dataValue) {
  return this.offset + this.orientation * (log(dataValue, this.options.base) - log(this.min, this.options.base)) * this.scale;
}

function p2dLog (pointValue) {
  return exp((this.offset + this.orientation * pointValue) / this.scale + log(this.min, this.options.base), this.options.base);
}

function log (value, base) {
  value = Math.log(Math.max(value, Number.MIN_VALUE));
  if (base !== Math.E)
    value /= Math.log(o.base);
  return value;
}

function exp (value, base) {
  return (base === Math.E) ? Math.exp(value) : Math.pow(base, value);
}

Flotr.Axis = Axis;

})();
<commit_msg>Fixed log function.<commit_after>/**
 * Flotr Axis Library
 */

(function () {

var
  _ = Flotr._,
  LOGARITHMIC = 'logarithmic';

function Axis (o) {

  this.orientation = 1;
  this.offset = 0;
  this.datamin = Number.MAX_VALUE;
  this.datamax = -Number.MAX_VALUE;

  _.extend(this, o);

  this._setTranslations();
}

// Prototype
Axis.prototype = {

  setScale : function () {
    var length = this.length;
    if (this.options.scaling == LOGARITHMIC) {
      this.scale = length / (log(this.max, this.options.base) - log(this.min, this.options.base));
    } else {
      this.scale = length / (this.max - this.min);
    }
  },

  calculateTicks : function () {
    var options = this.options;

    this.ticks = [];
    this.minorTicks = [];

    // User Ticks
    if(options.ticks){
      this._cleanUserTicks(options.ticks, this.ticks);
      this._cleanUserTicks(options.minorTicks || [], this.minorTicks);
    }
    else {
      if (options.mode == 'time') {
        this._calculateTimeTicks();
      } else if (options.scaling === 'logarithmic') {
        this._calculateLogTicks();
      } else {
        this._calculateTicks();
      }
    }
  },

  /**
   * Calculates the range of an axis to apply autoscaling.
   */
  calculateRange: function () {

    if (!this.used) return;

    var axis  = this,
      o       = axis.options,
      min     = o.min !== null ? o.min : axis.datamin,
      max     = o.max !== null ? o.max : axis.datamax,
      margin  = o.autoscaleMargin;

    if (o.scaling == 'logarithmic') {
      if (min <= 0) min = axis.datamin;

      // Let it widen later on
      if (max <= 0) max = min;
    }

    if (max == min) {
      var widen = max ? 0.01 : 1.00;
      min -= widen;
      max += widen;
    }

    if (o.scaling === 'logarithmic') {
      if (min < 0) min = max / o.base;  // Could be the result of widening

      var maxexp = Math.log(max);
      if (o.base != Math.E) maxexp /= Math.log(o.base);
      maxexp = Math.ceil(maxexp);

      var minexp = Math.log(min);
      if (o.base != Math.E) minexp /= Math.log(o.base);
      minexp = Math.ceil(minexp);

      axis.tickSize = Flotr.getTickSize(o.noTicks, minexp, maxexp, o.tickDecimals === null ? 0 : o.tickDecimals);

      // Try to determine a suitable amount of miniticks based on the length of a decade
      if (o.minorTickFreq === null) {
        if (maxexp - minexp > 10)
          o.minorTickFreq = 0;
        else if (maxexp - minexp > 5)
          o.minorTickFreq = 2;
        else
          o.minorTickFreq = 5;
      }
    } else {
      axis.tickSize = Flotr.getTickSize(o.noTicks, min, max, o.tickDecimals);
    }

    axis.min = min;
    axis.max = max; //extendRange may use axis.min or axis.max, so it should be set before it is caled

    // Autoscaling. @todo This probably fails with log scale. Find a testcase and fix it
    if(o.min === null && o.autoscale){
      axis.min -= axis.tickSize * margin;
      // Make sure we don't go below zero if all values are positive.
      if(axis.min < 0 && axis.datamin >= 0) axis.min = 0;
      axis.min = axis.tickSize * Math.floor(axis.min / axis.tickSize);
    }

    if(o.max === null && o.autoscale){
      axis.max += axis.tickSize * margin;
      if(axis.max > 0 && axis.datamax <= 0 && axis.datamax != axis.datamin) axis.max = 0;
      axis.max = axis.tickSize * Math.ceil(axis.max / axis.tickSize);
    }

    if (axis.min == axis.max) axis.max = axis.min + 1;
  },

  calculateTextDimensions : function (T, options) {

    var maxLabel = '',
      length,
      i;

    if (this.options.showLabels) {
      for (i = 0; i < this.ticks.length; ++i) {
        length = this.ticks[i].label.length;
        if (length > maxLabel.length){
          maxLabel = this.ticks[i].label;
        }
      }
    }

    this.maxLabel = T.dimensions(
      maxLabel,
      {size:options.fontSize, angle: Flotr.toRad(this.options.labelsAngle)},
      'font-size:smaller;',
      'flotr-grid-label'
    );

    this.titleSize = T.dimensions(
      this.options.title,
      {size:options.fontSize*1.2, angle: Flotr.toRad(this.options.titleAngle)},
      'font-weight:bold;',
      'flotr-axis-title'
    );
  },

  _cleanUserTicks : function (ticks, axisTicks) {

    var axis = this, options = this.options,
      v, i, label, tick;

    if(_.isFunction(ticks)) ticks = ticks({min : axis.min, max : axis.max});

    for(i = 0; i < ticks.length; ++i){
      tick = ticks[i];
      if(typeof(tick) === 'object'){
        v = tick[0];
        label = (tick.length > 1) ? tick[1] : options.tickFormatter(v, {min : axis.min, max : axis.max});
      } else {
        v = tick;
        label = options.tickFormatter(v, {min : this.min, max : this.max});
      }
      axisTicks[i] = { v: v, label: label };
    }
  },

  _calculateTimeTicks : function () {
    var axis = this,
        tu = Flotr.Date.timeUnits,
        spec = Flotr.Date.spec,
        delta = (axis.max - axis.min) / axis.options.noTicks,
        size, unit, i;

    for (i = 0; i < spec.length - 1; ++i) {
      var d = spec[i][0] * tu[spec[i][1]];
      if (delta < (d + spec[i+1][0] * tu[spec[i+1][1]]) / 2 && d >= axis.tickSize)
        break;
    }
    size = spec[i][0];
    unit = spec[i][1];

    // special-case the possibility of several years
    if (unit == "year") {
      size = Flotr.getTickSize(axis.options.noTicks*tu.year, axis.min, axis.max, 0);
    }

    axis.tickSize = size;
    axis.tickUnit = unit;
    axis.ticks = Flotr.Date.generator(axis);
  },

  _calculateLogTicks : function () {

    var axis = this,
      o = axis.options,
      v,
      decadeStart;

    var max = Math.log(axis.max);
    if (o.base != Math.E) max /= Math.log(o.base);
    max = Math.ceil(max);

    var min = Math.log(axis.min);
    if (o.base != Math.E) min /= Math.log(o.base);
    min = Math.ceil(min);

    for (i = min; i < max; i += axis.tickSize) {
      decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
      // Next decade begins here:
      var decadeEnd = decadeStart * ((o.base == Math.E) ? Math.exp(axis.tickSize) : Math.pow(o.base, axis.tickSize));
      var stepSize = (decadeEnd - decadeStart) / o.minorTickFreq;

      axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})});
      for (v = decadeStart + stepSize; v < decadeEnd; v += stepSize)
        axis.minorTicks.push({v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max})});
    }

    // Always show the value at the would-be start of next decade (end of this decade)
    decadeStart = (o.base == Math.E) ? Math.exp(i) : Math.pow(o.base, i);
    axis.ticks.push({v: decadeStart, label: o.tickFormatter(decadeStart, {min : axis.min, max : axis.max})});
  },

  _calculateTicks : function () {

    var axis      = this,
        o         = axis.options,
        tickSize  = axis.tickSize,
        min       = axis.min,
        max       = axis.max,
        start     = tickSize * Math.ceil(min / tickSize), // Round to nearest multiple of tick size.
        decimals,
        minorTickSize,
        v, v2,
        i, j;

    if (o.minorTickFreq)
      minorTickSize = tickSize / o.minorTickFreq;

    // Then store all possible ticks.
    for (i = 0; (v = v2 = start + i * tickSize) <= max; ++i){

      // Round (this is always needed to fix numerical instability).
      decimals = o.tickDecimals;
      if (decimals === null) decimals = 1 - Math.floor(Math.log(tickSize) / Math.LN10);
      if (decimals < 0) decimals = 0;

      v = v.toFixed(decimals);
      axis.ticks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) });

      if (o.minorTickFreq) {
        for (j = 0; j < o.minorTickFreq && (i * tickSize + j * minorTickSize) < max; ++j) {
          v = (v2 + j * minorTickSize).toFixed(decimals);
          axis.minorTicks.push({ v: v, label: o.tickFormatter(v, {min : axis.min, max : axis.max}) });
        }
      }
    }

  },

  _setTranslations : function (logarithmic) {
    this.d2p = (logarithmic ? d2pLog : d2p);
    this.p2d = (logarithmic ? p2dLog : p2d);
  }
};

// Static Methods
_.extend(Axis, {
  getAxes : function (options) {
    return {
      x:  new Axis({options: options.xaxis,  n: 1, length: this.plotWidth}),
      x2: new Axis({options: options.x2axis, n: 2, length: this.plotWidth}),
      y:  new Axis({options: options.yaxis,  n: 1, length: this.plotHeight, offset: this.plotHeight, orientation: -1}),
      y2: new Axis({options: options.y2axis, n: 2, length: this.plotHeight, offset: this.plotHeight, orientation: -1})
    };
  }
});

// Helper Methods

function d2p (dataValue) {
  return this.offset + this.orientation * (dataValue - this.min) * this.scale;
}

function p2d (pointValue) {
  return (this.offset + this.orientation * pointValue) / this.scale + this.min;
}

function d2pLog (dataValue) {
  return this.offset + this.orientation * (log(dataValue, this.options.base) - log(this.min, this.options.base)) * this.scale;
}

function p2dLog (pointValue) {
  return exp((this.offset + this.orientation * pointValue) / this.scale + log(this.min, this.options.base), this.options.base);
}

function log (value, base) {
  value = Math.log(Math.max(value, Number.MIN_VALUE));
  if (base !== Math.E)
    value /= Math.log(base);
  return value;
}

function exp (value, base) {
  return (base === Math.E) ? Math.exp(value) : Math.pow(base, value);
}

Flotr.Axis = Axis;

})();
<|endoftext|>


<commit_before><commit_msg>added conditional requirement to fields<commit_after><|endoftext|>


<commit_before>define(function(require, exports, module) {
  'use strict';
  var TSCORE = require("tscore");
  console.log("Loading: ext.api.js");

  window.addEventListener("message", handleMessage , false);

  function handleMessage(msg) {
    var data = JSON.parse(msg.data);
    var command = data.command;

    switch (command) {
      case "hideAllMenus":
        TSCORE.hideAllDropDownMenus();
        $('#searchOptions').hide();
        $('#fileExtensionMenu').hide();
        break;
      case "playbackEnded":
        openNextFile();
        break;
      case "openLinkExternally":
        if (data.link) {
          openLinkExternally(data.link);
        }
        break;
      case "contentChangedInEditor":
        TSCORE.FileOpener.setFileChanged(true);
        break;
      default:
        console.log("Not recognized messaging command: " + msg);
        break;
    }
  }

  function openNextFile() {
    //if(TSCORE.selectedFiles.length > 0) {
      // TODO open next selected file
    //} else {
    TSCORE.FileOpener.openFile(TSCORE.PerspectiveManager.getNextFile(TSCORE.FileOpener.getOpenedFilePath()));
    //}
  }

  function openLinkExternally(uri) {
    uri = decodeURIComponent(uri);
    if (
        uri.indexOf("http://") === 0 ||
        uri.indexOf("https://") === 0 ||
        uri.indexOf("file://") === 0
    ) {
      TSCORE.IO.openFile(uri);
    } else {
      console.log("Not supported URL format: " + uri);
    }
  }

});<commit_msg>adding additional dropdown dialogs for hiding<commit_after>define(function(require, exports, module) {
  'use strict';
  var TSCORE = require("tscore");
  console.log("Loading: ext.api.js");

  window.addEventListener("message", handleMessage , false);

  function handleMessage(msg) {
    var data = JSON.parse(msg.data);
    var command = data.command;

    switch (command) {
      case "hideAllMenus":
        TSCORE.hideAllDropDownMenus();
        $('#searchOptions').hide();
        $('#fileExtensionMenu').parent().removeClass('open');
        $('#perspectiveSwitcher').parent().removeClass('open');
        $('#locationsList').parent().removeClass('open');
        $('#tagSuggestionsMenu').parent().removeClass('open');
        break;
      case "playbackEnded":
        openNextFile();
        break;
      case "openLinkExternally":
        if (data.link) {
          openLinkExternally(data.link);
        }
        break;
      case "contentChangedInEditor":
        TSCORE.FileOpener.setFileChanged(true);
        break;
      default:
        console.log("Not recognized messaging command: " + msg);
        break;
    }
  }

  function openNextFile() {
    //if(TSCORE.selectedFiles.length > 0) {
      // TODO open next selected file
    //} else {
    TSCORE.FileOpener.openFile(TSCORE.PerspectiveManager.getNextFile(TSCORE.FileOpener.getOpenedFilePath()));
    //}
  }

  function openLinkExternally(uri) {
    uri = decodeURIComponent(uri);
    if (
        uri.indexOf("http://") === 0 ||
        uri.indexOf("https://") === 0 ||
        uri.indexOf("file://") === 0
    ) {
      TSCORE.IO.openFile(uri);
    } else {
      console.log("Not supported URL format: " + uri);
    }
  }

});<|endoftext|>


<commit_before>(function () {
   var util = YAHOO.util, lang = YAHOO.lang, Event = YAHOO.util.Event, inputEx = YAHOO.inputEx, Dom = util.Dom;

/**
 * Create a group of fields within a FORM tag and adds buttons
 * @class inputEx.Form
 * @extends inputEx.Group
 * @constructor
 * @param {Object} options The following options are added for Forms:
 *

 *
buttons: list of button definition objects {value: 'Click Me', type: 'submit'}

 *
ajax: send the form through an ajax request (submit button should be present): {method: 'POST', uri: 'myScript.php', callback: same as YAHOO.util.Connect.asyncRequest callback}

 *
showMask: adds a mask over the form while the request is running (default is false)

 *

 */
inputEx.Form = function(options) {
   inputEx.Form.superclass.constructor.call(this, options);
};

lang.extend(inputEx.Form, inputEx.Group, {

   /**
    * Adds buttons and set ajax default parameters
    * @param {Object} options Options object (inputEx inputParams) as passed to the constructor
    */
   setOptions: function(options) {
      inputEx.Form.superclass.setOptions.call(this, options);

      this.buttons = [];

      this.options.buttons = options.buttons || [];

      this.options.action = options.action;
   	this.options.method = options.method;

      if(options.ajax) {
         this.options.ajax = {};
         this.options.ajax.method = options.ajax.method || 'POST';
         this.options.ajax.uri = options.ajax.uri || 'default.php';
         this.options.ajax.callback = options.ajax.callback || {};
         this.options.ajax.callback.scope = options.ajax.callback.scope || this;
         this.options.ajax.showMask = lang.isUndefined(options.ajax.showMask) ? false : options.ajax.showMask;
      }

      if (lang.isFunction(options.onSubmit)) {
         this.options.onSubmit = options.onSubmit;
      }
   },

   /**
    * Render the group
    */
   render: function() {
      // Create the div wrapper for this group
  	   this.divEl = inputEx.cn('div', {className: this.options.className});
	   if(this.options.id) {
   	   this.divEl.id = this.options.id;
   	}

  	   // Create the FORM element
      this.form = inputEx.cn('form', {method: this.options.method || 'POST', action: this.options.action || '', className: this.options.className || 'inputEx-Form'});
      this.divEl.appendChild(this.form);

	   // Set the autocomplete attribute to off to disable firefox autocompletion
	   this.form.setAttribute('autocomplete','off');

      // Set the name of the form
      if(this.options.formName) { this.form.name = this.options.formName; }

  	   this.renderFields(this.form);

      this.renderButtons();

      if(this.options.disabled) {
  	      this.disable();
  	   }
   },

   /**
    * Render the buttons
    */
   renderButtons: function() {

      this.buttonDiv = inputEx.cn('div', {className: 'inputEx-Form-buttonBar'});

	   var button, buttonEl;
	   for(var i = 0 ; i < this.options.buttons.length ; i++ ) {
	      button = this.options.buttons[i];
	      buttonEl = inputEx.cn('input', {type: button.type, value: button.value});
	      if( button.onClick ) { buttonEl.onclick = button.onClick; }
	      this.buttons.push(buttonEl);
	      this.buttonDiv.appendChild(buttonEl);
	   }

	   this.form.appendChild(this.buttonDiv);
   },

   /**
    * Init the events
    */
   initEvents: function() {
      inputEx.Form.superclass.initEvents.call(this);

      // Handle the submit event
      Event.addListener(this.form, 'submit', this.options.onSubmit || this.onSubmit,this,true);
   },

   /**
    * Intercept the 'onsubmit' event and stop it if !validate
    * If the ajax option object is set, use YUI async Request to send the form
    * @param {Event} e The original onSubmit event
    */
   onSubmit: function(e) {

      // do nothing if does not validate
	   if ( !this.validate() ) {
		   Event.stopEvent(e); // no submit
		   return; // no ajax submit
	   }

	   if(this.options.ajax) {
		   Event.stopEvent(e);
	      this.asyncRequest();
	   }
   },

   /**
    * Send the form value in JSON through an ajax request
    */
   asyncRequest: function() {

      if(this.options.ajax.showMask) { this.showMask(); }
	   var postData = "value="+lang.JSON.stringify(this.getValue());
      util.Connect.asyncRequest(this.options.ajax.method, this.options.ajax.uri, {
         success: function(o) {
            if(this.options.ajax.showMask) { this.hideMask(); }
            if( lang.isFunction(this.options.ajax.callback.success) ) {
               this.options.ajax.callback.success.call(this.options.ajax.callback.scope,o);
            }
         },

         failure: function(o) {
            if(this.options.ajax.showMask) { this.hideMask(); }
            if( lang.isFunction(this.options.ajax.callback.failure) ) {
               this.options.ajax.callback.failure.call(this.options.ajax.callback.scope,o);
            }
         },

         scope:this
      }, postData);
   },

   /**
    * Create a Mask over the form
    */
   renderMask: function() {
      if(this.maskRendered) return;

      // position as "relative" to position formMask inside as "absolute"
      Dom.setStyle(this.divEl, "position", "relative");

      // set zoom = 1 to fix hasLayout issue with IE6/7
      if (YAHOO.env.ua.ie) { Dom.setStyle(this.divEl, "zoom", 1); }

      // Render mask over the divEl
      this.formMask = inputEx.cn('div', {className: 'inputEx-Form-Mask'},
         {
            display: 'none',
            // Use offsetWidth instead of Dom.getStyle(this.divEl,"width") because
            // would return "auto" with IE instead of size in px
            width: this.divEl.offsetWidth+"px",
            height: this.divEl.offsetHeight+"px"
         },
         "

"+inputEx.messages.ajaxWait+"
");
      this.divEl.appendChild(this.formMask);
      this.maskRendered = true;
   },

   /**
    * Show the form mask
    */
   showMask: function() {
      this.renderMask();

      // Hide selects in IE 6
      this.toggleSelectsInIE(false);

      this.formMask.style.display = '';
   },

   /**
    * Hide the form mask
    */
   hideMask: function() {

      // Show selects back in IE 6
      this.toggleSelectsInIE(true);

      this.formMask.style.display = 'none';
   },

   /*
   * Method to hide selects in IE 6 when masking the form (else they would appear over the mask)
   */
   toggleSelectsInIE: function(show) {
      // IE 6 only
      if (!!YAHOO.env.ua.ie && YAHOO.env.ua.ie < 7) {
         var method = !!show ? YAHOO.util.Dom.removeClass : YAHOO.util.Dom.addClass;
         var that = this;
         YAHOO.util.Dom.getElementsBy(
            function() {return true;},
            "select",
            this.divEl,
            function(el) {method.call(that,el,"inputEx-hidden");}
         );
      }
   },

   /**
    * Enable all fields and buttons in the form
    */
   enable: function() {
      inputEx.Form.superclass.enable.call(this);
      for (var i = 0 ; i < this.buttons.length ; i++) {
 	      this.buttons[i].disabled = false;
      }
   },

   /**
    * Disable all fields and buttons in the form
    */
   disable: function() {
      inputEx.Form.superclass.disable.call(this);
      for (var i = 0 ; i < this.buttons.length ; i++) {
 	      this.buttons[i].disabled = true;
      }
   }

});

// Specific waiting message in ajax submit
inputEx.messages.ajaxWait = "Please wait...";;

// Register this class as "form" type
inputEx.registerType("form", inputEx.Form);

})();
<commit_msg>Ajax Form support of x-www-form-urlencoded<commit_after>(function () {
   var util = YAHOO.util, lang = YAHOO.lang, Event = YAHOO.util.Event, inputEx = YAHOO.inputEx, Dom = util.Dom;

/**
 * Create a group of fields within a FORM tag and adds buttons
 * @class inputEx.Form
 * @extends inputEx.Group
 * @constructor
 * @param {Object} options The following options are added for Forms:
 *

 *
buttons: list of button definition objects {value: 'Click Me', type: 'submit'}

 *
ajax: send the form through an ajax request (submit button should be present): {method: 'POST', uri: 'myScript.php', callback: same as YAHOO.util.Connect.asyncRequest callback}

 *
showMask: adds a mask over the form while the request is running (default is false)

 *

 */
inputEx.Form = function(options) {
   inputEx.Form.superclass.constructor.call(this, options);
};

lang.extend(inputEx.Form, inputEx.Group, {

   /**
    * Adds buttons and set ajax default parameters
    * @param {Object} options Options object (inputEx inputParams) as passed to the constructor
    */
   setOptions: function(options) {
      inputEx.Form.superclass.setOptions.call(this, options);

      this.buttons = [];

      this.options.buttons = options.buttons || [];

      this.options.action = options.action;
   	this.options.method = options.method;

      if(options.ajax) {
         this.options.ajax = {};
         this.options.ajax.method = options.ajax.method || 'POST';
         this.options.ajax.uri = options.ajax.uri || 'default.php';
         this.options.ajax.callback = options.ajax.callback || {};
         this.options.ajax.callback.scope = options.ajax.callback.scope || this;
         this.options.ajax.showMask = lang.isUndefined(options.ajax.showMask) ? false : options.ajax.showMask;

			this.options.ajax.contentType = options.ajax.contentType || "application/json";
      }

      if (lang.isFunction(options.onSubmit)) {
         this.options.onSubmit = options.onSubmit;
      }
   },

   /**
    * Render the group
    */
   render: function() {
      // Create the div wrapper for this group
  	   this.divEl = inputEx.cn('div', {className: this.options.className});
	   if(this.options.id) {
   	   this.divEl.id = this.options.id;
   	}

  	   // Create the FORM element
      this.form = inputEx.cn('form', {method: this.options.method || 'POST', action: this.options.action || '', className: this.options.className || 'inputEx-Form'});
      this.divEl.appendChild(this.form);

	   // Set the autocomplete attribute to off to disable firefox autocompletion
	   this.form.setAttribute('autocomplete','off');

      // Set the name of the form
      if(this.options.formName) { this.form.name = this.options.formName; }

  	   this.renderFields(this.form);

      this.renderButtons();

      if(this.options.disabled) {
  	      this.disable();
  	   }
   },

   /**
    * Render the buttons
    */
   renderButtons: function() {

      this.buttonDiv = inputEx.cn('div', {className: 'inputEx-Form-buttonBar'});

	   var button, buttonEl;
	   for(var i = 0 ; i < this.options.buttons.length ; i++ ) {
	      button = this.options.buttons[i];
	      buttonEl = inputEx.cn('input', {type: button.type, value: button.value});
	      if( button.onClick ) { buttonEl.onclick = button.onClick; }
	      this.buttons.push(buttonEl);
	      this.buttonDiv.appendChild(buttonEl);
	   }

	   this.form.appendChild(this.buttonDiv);
   },

   /**
    * Init the events
    */
   initEvents: function() {
      inputEx.Form.superclass.initEvents.call(this);

      // Handle the submit event
      Event.addListener(this.form, 'submit', this.options.onSubmit || this.onSubmit,this,true);
   },

   /**
    * Intercept the 'onsubmit' event and stop it if !validate
    * If the ajax option object is set, use YUI async Request to send the form
    * @param {Event} e The original onSubmit event
    */
   onSubmit: function(e) {

      // do nothing if does not validate
	   if ( !this.validate() ) {
		   Event.stopEvent(e); // no submit
		   return; // no ajax submit
	   }

	   if(this.options.ajax) {
		   Event.stopEvent(e);
	      this.asyncRequest();
	   }
   },

   /**
    * Send the form value in JSON through an ajax request
    */
   asyncRequest: function() {

      if(this.options.ajax.showMask) { this.showMask(); }

		var formValue = this.getValue();

		// options.ajax.uri and options.ajax.method can also be functions that return a the uri/method depending of the value of the form
		var uri = lang.isFunction(this.options.ajax.uri) ? this.options.ajax.uri(formValue) : this.options.ajax.uri;
		var method = lang.isFunction(this.options.ajax.method) ? this.options.ajax.method(formValue) : this.options.ajax.method;

		var postData = null;

		// method PUT don't send as x-www-form-urlencoded but in JSON
		if(method == "PUT") {
			YAHOO.util.Connect.initHeader("Content-Type" , "application/json" , false);
			postData = lang.JSON.stringify(this.getValue());
		}
		else {

			if(this.options.ajax.contentType == "application/x-www-form-urlencoded") {
				var params = [];
				for(var key in formValue) {
					if(formValue.hasOwnProperty(key)) {
						params.push(window.encodeURIComponent(key)+"="+window.encodeURIComponent(formValue[key]));
					}
				}
				postData = params.join('&');
			}
			else {
				YAHOO.util.Connect.initHeader("Content-Type" , "application/json" , false);
				postData = "value="+lang.JSON.stringify(this.getValue());
			}

		}

      util.Connect.asyncRequest( method, uri, {
         success: function(o) {
            if(this.options.ajax.showMask) { this.hideMask(); }
            if( lang.isFunction(this.options.ajax.callback.success) ) {
               this.options.ajax.callback.success.call(this.options.ajax.callback.scope,o);
            }
         },

         failure: function(o) {
            if(this.options.ajax.showMask) { this.hideMask(); }
            if( lang.isFunction(this.options.ajax.callback.failure) ) {
               this.options.ajax.callback.failure.call(this.options.ajax.callback.scope,o);
            }
         },

         scope:this
      }, postData);
   },

   /**
    * Create a Mask over the form
    */
   renderMask: function() {
      if(this.maskRendered) return;

      // position as "relative" to position formMask inside as "absolute"
      Dom.setStyle(this.divEl, "position", "relative");

      // set zoom = 1 to fix hasLayout issue with IE6/7
      if (YAHOO.env.ua.ie) { Dom.setStyle(this.divEl, "zoom", 1); }

      // Render mask over the divEl
      this.formMask = inputEx.cn('div', {className: 'inputEx-Form-Mask'},
         {
            display: 'none',
            // Use offsetWidth instead of Dom.getStyle(this.divEl,"width") because
            // would return "auto" with IE instead of size in px
            width: this.divEl.offsetWidth+"px",
            height: this.divEl.offsetHeight+"px"
         },
         "

"+inputEx.messages.ajaxWait+"
");
      this.divEl.appendChild(this.formMask);
      this.maskRendered = true;
   },

   /**
    * Show the form mask
    */
   showMask: function() {
      this.renderMask();

      // Hide selects in IE 6
      this.toggleSelectsInIE(false);

      this.formMask.style.display = '';
   },

   /**
    * Hide the form mask
    */
   hideMask: function() {

      // Show selects back in IE 6
      this.toggleSelectsInIE(true);

      this.formMask.style.display = 'none';
   },

   /*
   * Method to hide selects in IE 6 when masking the form (else they would appear over the mask)
   */
   toggleSelectsInIE: function(show) {
      // IE 6 only
      if (!!YAHOO.env.ua.ie && YAHOO.env.ua.ie < 7) {
         var method = !!show ? YAHOO.util.Dom.removeClass : YAHOO.util.Dom.addClass;
         var that = this;
         YAHOO.util.Dom.getElementsBy(
            function() {return true;},
            "select",
            this.divEl,
            function(el) {method.call(that,el,"inputEx-hidden");}
         );
      }
   },

   /**
    * Enable all fields and buttons in the form
    */
   enable: function() {
      inputEx.Form.superclass.enable.call(this);
      for (var i = 0 ; i < this.buttons.length ; i++) {
 	      this.buttons[i].disabled = false;
      }
   },

   /**
    * Disable all fields and buttons in the form
    */
   disable: function() {
      inputEx.Form.superclass.disable.call(this);
      for (var i = 0 ; i < this.buttons.length ; i++) {
 	      this.buttons[i].disabled = true;
      }
   }

});

// Specific waiting message in ajax submit
inputEx.messages.ajaxWait = "Please wait...";;

// Register this class as "form" type
inputEx.registerType("form", inputEx.Form);

})();
<|endoftext|>


<commit_before>// Generic field triggers
$('#registration-form :input').each(function() {
  $(this).on({
    blur: function(){ // Add a blur (leave field) event handler to each field to trigger a validation

      var valid = validate_input($(this), $(this).attr('type'));
      if(!valid) {
        add_error($(this), $(this).attr('data-error'));
      }

    },
    keyup: function(){ // Add a keyup event handler to each field to clear its error state

      remove_error($(this));

    },
    focus: function(){ // Add a focus event handler to each field to clear its error state

      remove_error($(this));

    }
  });
});

// Specific field triggers
$('#username, #email').on({
  blur: function(){
    if($(this).val().length > 0) {
      check_availability($(this), $(this).attr('type'));
    }
  }
});

// Control AJAX request to availability checker script
function check_availability(field, as) {
  field = $(field);
  var value = field.val();

  $.ajax({
    url: '/availability_checker.php',
    type: 'post',
    data: {'value': value, 'as': as},
    success: function(data, status) {

      if(data == "available") {
        console.log('a');
        remove_error(field);
      }

      if(data == "unavailable") {
        console.log('u');
        add_error(field, 'Unfortunately, ' + value + ' is not available :(');
      }

      console.log(data);

    }
  });
}

function validate_form(form)
{

  // Check if any of the unique (user/email) fields are already taken in the DB
  var any_unavailable = $('.invalid_field').length > 0;
  if(any_unavailable) {
    return false;
  }

  // Regardless of errors, check the user filled in the reCAPTCHA
  if(grecaptcha.getResponse() == '') {
    // ask the user to do reCPATCHA
    return false;
  }

  var fail_count = 0;

  var field_is_valid;
  var value;
  var type;

  $(form).find(':input').each(function() {

    value = $(this).val();
    type = $(this).attr('type');

    // Types of field that can be validated
    var valid_type = (type == 'username' || type == 'email' || type == 'password' || type == 'number' || type == 'text');
    var field_needs_validating = $(this).attr('required'); // Field designated as required
    if(field_needs_validating && valid_type) { // Only validate fields that make sense

      remove_error($(this));

      field_is_valid = validate_input($(this), type);
      if(!field_is_valid) {
        fail_count++;
        add_error($(this), $(this).attr('data-error'));
      }
    }

  });

  return fail_count == 0; // return form valid if no fails occurred
}

function validate_input(field, as)
{
  field = $(field);

  var value = field.val();

  // username
  if(as == 'username') {
    return value.length >= 6;
  }

  // email address
  if(as == 'email') {
    var email_regex = /^[a-z0-9._+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i;
    return email_regex.test(value);
  }

  // Password
  if(as == 'password') {
    var matching_rules = 0;

    if(value.length < 8) {
      return false; // Password absolutely cannot be less than 8 chars long
    }

    /[a-z]/.test(value) ? matching_rules++ : null; // Password contains lower case
    /[A-Z]/.test(value) ? matching_rules++ : null; // Password contains upper case
       /\d/.test(value) ? matching_rules++ : null; // Password contains number
       /\W/.test(value) ? matching_rules++ : null; // Password contains special character

    return matching_rules >= 2; // Password must match at least 2 rules
  }

  // Numerical value
  if(as == 'number') {
    return !isNaN(value);
  }

  // All other cases test value as string
  return "" + value.length > 0;
}

function add_error(field, data)
{
  field = $(field); // Ensure it is a jQuery object

  field.parent().addClass('has-error');
  field.addClass('invalid_field');

  if(field.attr('data-error') != '') {
    field.parent().append('
' + data + '
');
  } else {
    field.parent().append('
' + 'Field cannot be empty' + '
');
  }
}

function remove_error(field)
{
  field = $(field); // Ensure it is a jQuery object

  field.removeClass('invalid_field');

  if(field.parent().hasClass('has-error')) {
    field.parent().removeClass('has-error');
  }

  field.siblings('p').each(function(){
    $(this).remove();
  });
}
<commit_msg>debugging<commit_after>// Generic field triggers
$('#registration-form :input').each(function() {
  $(this).on({
    blur: function(){ // Add a blur (leave field) event handler to each field to trigger a validation

      var valid = validate_input($(this), $(this).attr('type'));
      if(!valid) {
        add_error($(this), $(this).attr('data-error'));
      }

    },
    keyup: function(){ // Add a keyup event handler to each field to clear its error state

      remove_error($(this));

    },
    focus: function(){ // Add a focus event handler to each field to clear its error state

      remove_error($(this));

    }
  });
});

// Specific field triggers
$('#username, #email').on({
  blur: function(){
    if($(this).val().length > 0) {
      check_availability($(this), $(this).attr('type'));
    }
  }
});

// Control AJAX request to availability checker script
function check_availability(field, as) {
  field = $(field);
  var value = field.val();

  $.ajax({
    url: '/availability_checker.php',
    type: 'post',
    data: {'value': value, 'as': as},
    success: function(data, status) {

      if(data == 'available') {
        console.log('available');
        remove_error(field);
      }

      if(data == 'unavailable') {
        console.log('unavailable');
        add_error(field, 'Unfortunately, ' + value + ' is not available :(');
      }

      console.log(data);

    }
  });
}

function validate_form(form)
{

  // Check if any of the unique (user/email) fields are already taken in the DB
  var any_unavailable = $('.invalid_field').length > 0;
  if(any_unavailable) {
    return false;
  }

  // Regardless of errors, check the user filled in the reCAPTCHA
  if(grecaptcha.getResponse() == '') {
    // ask the user to do reCPATCHA
    return false;
  }

  var fail_count = 0;

  var field_is_valid;
  var value;
  var type;

  $(form).find(':input').each(function() {

    value = $(this).val();
    type = $(this).attr('type');

    // Types of field that can be validated
    var valid_type = (type == 'username' || type == 'email' || type == 'password' || type == 'number' || type == 'text');
    var field_needs_validating = $(this).attr('required'); // Field designated as required
    if(field_needs_validating && valid_type) { // Only validate fields that make sense

      remove_error($(this));

      field_is_valid = validate_input($(this), type);
      if(!field_is_valid) {
        fail_count++;
        add_error($(this), $(this).attr('data-error'));
      }
    }

  });

  return fail_count == 0; // return form valid if no fails occurred
}

function validate_input(field, as)
{
  field = $(field);

  var value = field.val();

  // username
  if(as == 'username') {
    return value.length >= 6;
  }

  // email address
  if(as == 'email') {
    var email_regex = /^[a-z0-9._+-]+@[a-z0-9.-]+\.[a-z]{2,4}$/i;
    return email_regex.test(value);
  }

  // Password
  if(as == 'password') {
    var matching_rules = 0;

    if(value.length < 8) {
      return false; // Password absolutely cannot be less than 8 chars long
    }

    /[a-z]/.test(value) ? matching_rules++ : null; // Password contains lower case
    /[A-Z]/.test(value) ? matching_rules++ : null; // Password contains upper case
       /\d/.test(value) ? matching_rules++ : null; // Password contains number
       /\W/.test(value) ? matching_rules++ : null; // Password contains special character

    return matching_rules >= 2; // Password must match at least 2 rules
  }

  // Numerical value
  if(as == 'number') {
    return !isNaN(value);
  }

  // All other cases test value as string
  return "" + value.length > 0;
}

function add_error(field, data)
{
  field = $(field); // Ensure it is a jQuery object

  field.parent().addClass('has-error');
  field.addClass('invalid_field');

  if(field.attr('data-error') != '') {
    field.parent().append('
' + data + '
');
  } else {
    field.parent().append('
' + 'Field cannot be empty' + '
');
  }
}

function remove_error(field)
{
  field = $(field); // Ensure it is a jQuery object

  field.removeClass('invalid_field');

  if(field.parent().hasClass('has-error')) {
    field.parent().removeClass('has-error');
  }

  field.siblings('p').each(function(){
    $(this).remove();
  });
}
<|endoftext|>