<commit_before>/*!
 * jQuery UI Selectmenu @VERSION
 * http://jqueryui.com
 *
 * Copyright 2012 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/selectmenu
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *	jquery.ui.position.js
 *	jquery.ui.menu.js
 */
(function( $, undefined ) {

$.widget( "ui.selectmenu", {
	version: "@VERSION",
	defaultElement: "<select>",
	options: {
		appendTo: "body",
		dropdown: true,
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},

		// callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		select: null
	},

	_create: function() {
		var selectmenuId = this.element.uniqueId().attr( "id" );
		this.ids = { id: selectmenuId, button: selectmenuId + "-button", menu: selectmenuId + "-menu" };

		this._drawButton();
		this._drawMenu();

		this._on( document, this._documentClick );

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

	_drawButton: function() {
		var tabindex = this.element.attr( "tabindex" );

		// fix existing label
		this.label = $( "label[for='" + this.ids.id + "']" ).attr( "for", this.ids.button );
		this._on( this.label, {
			"click":  function( event ) {
				this.button.focus();
				event.preventDefault();
			}
		});

		// hide original select tag
		this.element.hide();

		// create button
		this.button = $( "<a>", {
			"class": "ui-button ui-widget ui-state-default ui-corner-all",
			href: "#" + this.ids.id,
			tabindex: ( tabindex ? tabindex : this.options.disabled ? -1 : 0 ),
			id: this.ids.button,
			width: this.element.outerWidth(),
			role: "combobox",
			"aria-expanded": false,
			"aria-autocomplete": "list",
			"aria-owns": this.ids.menu,
			"aria-haspopup": true
		});

		this.button.prepend( $( "<span>", {
			"class": "ui-icon " + ( ( this.options.dropdown ) ? "ui-icon-triangle-1-s" : "ui-icon-triangle-2-n-s" )
		}));

		this.buttonText = $( "<span>", {
				"class": "ui-selectmenu-text" ,
				html: this.element.find( "option:selected" ).text() || " "
			})
			.appendTo( this.button );

		// wrap and insert new button
		this.buttonWrap = $( "<span>", {
				"class": "ui-selectmenu-button"
			})
			.append( this.button )
			.insertAfter( this.element );

		this._on( this.button, this._buttonEvents );
		this._hoverable( this.button );
		this._focusable( this.button );
	},

	_drawMenu: function() {
		var menuInstance,
			that = this;

		// create menu portion, append to body
		this.menu = $( "<ul>", {
			"aria-hidden": true,
			"aria-labelledby": this.ids.button,
			id: this.ids.menu
		});

		// wrap menu
		this.menuWrap = $( "<div>", {
				"class": "ui-selectmenu-menu",
				width: ( this.options.dropdown ) ? this.button.outerWidth() : this.buttonText.width() + parseFloat( this.buttonText.css( "padding-left" ) ) || 0 + parseFloat( this.buttonText.css( "margin-left") ) || 0
			})
			.append( this.menu )
			.appendTo( this.options.appendTo );

		// init menu widget
		menuInstance = this.menu.menu({
			select: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );

				that._select( item, event );

				if ( that.isOpen ) {
					event.preventDefault();
					that.close( event );
				}
			},
			focus: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );

				if ( that.focus !== undefined ) {
					if ( item.index !== that.focus ) {
						that._trigger( "focus", event, { item: item } );
						if ( !that.isOpen ) {
							that._select( item, event );
						}
					}
				}
				that.focus = item.index;

				// Set ARIA active descendant
				that.button.attr( "aria-activedescendant", that.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
			},
			// set ARIA role
			role: "listbox"
		})
		.data( "ui-menu" );

		// dropdown style needs border on bottom only
		if ( this.options.dropdown ) {
			this.menu.addClass( "ui-corner-bottom" ).removeClass( "ui-corner-all" );
		}

		// make sure focus stays on selected item
		menuInstance.delay = 999999999;
		// unbind uneeded Menu events
		menuInstance._off( this.menu, "mouseleave" );
	},

	refresh: function() {
		this.menu.empty();

		var item,
			options = this.element.find( "option" );
		if ( options.length ) {
			this._readOptions( options );
			this._renderMenu( this.menu, this.items );

			this.menu.menu( "refresh" );
			this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );

			// select current item
			item = this._getSelectedItem();
			this.menu.menu( "focus", null, item );
			this._setSelected( item.data( "ui-selectmenu-item" ) );

			// set disabled state
			this._setOption( "disabled", this._getCreateOptions().disabled );
		}
	},

	open: function( event ) {
		if ( this.options.disabled ) {
			return;
		}

		var _position = {
			of: this.button
		};

		// make sure menu is refreshed on first init (needed at least for IE9)
		if ( this.isOpen === undefined ) {
			this.button.trigger( "focus" );
		}

		this.isOpen = true;
		this._toggleAttr();
		this.menu.menu( "focus", event, this._getSelectedItem() );

		// do not change position if non default position options are set (needed for custom positioned popup menus)
		if ( this.items && !this.options.dropdown && this.options.position.my == "left top" && this.options.position.at == "left bottom" ) {
			var currentItem = this._getSelectedItem();
			// center current item
			if ( this.menu.outerHeight() < this.menu.prop( "scrollHeight" ) ) {
				this.menuWrap.css( "left" , -10000 );
				this.menu.scrollTop( this.menu.scrollTop() + currentItem.position().top - this.menu.outerHeight() / 2 + currentItem.outerHeight() / 2 );
				this.menuWrap.css( "left" , "auto" );
			}
			_position.my = "left top" + ( this.menu.offset().top  - currentItem.offset().top + ( this.button.outerHeight() - currentItem.outerHeight() ) / 2 );
			_position.at = "left top";
		}

		this.menuWrap
			.zIndex( this.element.zIndex() + 1 )
			.position( $.extend( {}, this.options.position, _position ) );

		this._trigger( "open", event );
	},

	close: function( event ) {
		if ( !this.isOpen ) {
			return;
		}

		var id = this._getSelectedItem().find( "a" ).attr( "id" );
		this.isOpen = false;
		this._toggleAttr();
		this.button.attr( "aria-activedescendant", id );
		this.menu.attr( "aria-activedescendant", id );
		this._trigger( "close", event );
	},

	widget: function() {
		return this.button;
	},

	menuWidget: function() {
		return this.menu;
	},

	_renderMenu: function( ul, items ) {
		var that = this,
			currentOptgroup = "";

		$.each( items, function( index, item ) {
			if ( item.optgroup !== currentOptgroup ) {
				$( "<li />", {
					"class": "ui-selectmenu-optgroup" + ( item.element.parent( "optgroup" ).attr( "disabled" ) ? " ui-state-disabled" : "" ),
					text: item.optgroup
				}).appendTo( ul );
				currentOptgroup = item.optgroup;
			}
			that._renderItem( ul, item );
		});
	},

	_renderItem: function( ul, item ) {
		var li = $( "<li />" ).data( "ui-selectmenu-item", item );
		if ( item.disabled ) {
			li.addClass( "ui-state-disabled" );
		}
		li.append( $( "<a />", {
				text: item.label,
				href: "#"
			})
		);

		return li.appendTo( ul );
	},

	_move: function( direction, event ) {
		if ( direction === "first" || direction === "last" ) {
			// set focus manually for first or last item
			this.menu.menu( "focus", event, this.menuItems[ direction ]() );
		} else {
			// move to and focus next or prev item
			this.menu.menu( direction, event );
		}
	},

	_getSelectedItem: function() {
		return this.menuItems.eq( this.element[ 0 ].selectedIndex );
	},

	_toggle: function( event ) {
		if ( this.isOpen ) {
			this.close( event );
		} else {
			this.open( event );
		}
	},

	_documentClick: {
		click: function( event ) {
			if ( this.isOpen && !$( event.target ).closest( "li.ui-state-disabled, li.ui-selectmenu-optgroup, #" + this.ids.button ).length ) {
				this.close( event );
			}
		}
	},

	_buttonEvents: {
		focus: function() {
			// init Menu on first focus
			this.refresh();
			// reset focus class as its removed by ui.widget._setOption
			this.button.addClass( "ui-state-focus" );
			this._off( this.button, "focus" );
		},
		click: function( event ) {
			this._toggle( event );
			event.preventDefault();
		},
		keydown: function( event ) {
			var prevDef = true;
			switch ( event.keyCode ) {
				case $.ui.keyCode.TAB:
				case $.ui.keyCode.ESCAPE:
					if ( this.isOpen ) {
						this.close( event );
					}
					prevDef = false;
					break;
				case $.ui.keyCode.ENTER:
					if ( this.isOpen ) {
						this.menu.menu( "select", event );
					}
					break;
				case $.ui.keyCode.UP:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "previous", event );
					}
					break;
				case $.ui.keyCode.DOWN:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "next", event );
					}
					break;
				case $.ui.keyCode.SPACE:
					if ( this.isOpen ) {
						this.menu.menu( "select", event );
					} else {
						this._toggle( event );
					}
					break;
				case $.ui.keyCode.LEFT:
					this._move( "previous", event );
					break;
				case $.ui.keyCode.RIGHT:
					this._move( "next", event );
					break;
				case $.ui.keyCode.HOME:
				case $.ui.keyCode.PAGE_UP:
					this._move( "first", event );
					break;
				case $.ui.keyCode.END:
				case $.ui.keyCode.PAGE_DOWN:
					this._move( "last", event );
					break;
				default:
					this.menu.trigger( event );
					prevDef = false;
			}
			if ( prevDef ) {
				event.preventDefault();
			}
		}
	},

	_select: function( item, event ) {
		var oldIndex = this.element[ 0 ].selectedIndex;
		// change native select element
		this.element[ 0 ].selectedIndex = item.index;
		this._setSelected( item );
		this._trigger( "select", event, { item: item } );

		if ( item.index !== oldIndex ) {
			this._trigger( "change", event, { item: item } );
		}
	},

	_setSelected: function( item ) {
		// update button text
		this.buttonText.html( item.label );
		// change ARIA attr
		this.menuItems.find( "a" ).attr( "aria-selected", false );
		this.menuItems.eq( item.index ).find( "a" ).attr( "aria-selected", true );
		this.button.attr( "aria-labelledby", this.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
	},

	_setOption: function( key, value ) {
		this._super( key, value );

		if ( key === "appendTo" ) {
			this.menuWrap.appendTo( this.document.find( value || "body" )[0] );
		}
		if ( key === "disabled" ) {
			this.menu.menu( "option", "disabled", value );
			if ( value ) {
				this.element.attr( "disabled", "disabled" );
				this.button.attr( "tabindex", -1 );
				this.close();
			} else {
				this.element.removeAttr( "disabled" );
				this.button.attr( "tabindex", 0 );
			}
		}
	},

	_toggleAttr: function(){
		if ( this.options.dropdown ) {
			this.button.toggleClass( "ui-corner-top", this.isOpen ).toggleClass( "ui-corner-all", !this.isOpen );
		}
		this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
		this.menu.attr( "aria-hidden", !this.isOpen);
		this.button.attr( "aria-expanded", this.isOpen);
	},

	_getCreateOptions: function() {
		return { disabled: !!this.element.attr( "disabled" ) };
	},

	_readOptions: function( options ) {
		var data = [];
		options.each( function( index, item ) {
			var option = $( item ),
				optgroup = option.parent( "optgroup" );
			data.push({
				element: option,
				index: index,
				value: option.attr( "value" ),
				label: option.text() || " ",
				optgroup: optgroup.attr( "label" ) || "",
				disabled: optgroup.attr( "disabled" ) || option.attr( "disabled" )
			});
		});
		this.items = data;
	},

	_destroy: function() {
		this.menuWrap.remove();
		this.buttonWrap.remove();
		this.element.show();
		this.element.removeUniqueId();
		this.label.attr( "for", this.ids.id );
	}
});

}( jQuery ));
<commit_msg>Selectmenu: merge and explain if statements in Menu focus event, remove unneeded Menu focus method call in open<commit_after>/*!
 * jQuery UI Selectmenu @VERSION
 * http://jqueryui.com
 *
 * Copyright 2012 jQuery Foundation and other contributors
 * Released under the MIT license.
 * http://jquery.org/license
 *
 * http://api.jqueryui.com/selectmenu
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 *	jquery.ui.position.js
 *	jquery.ui.menu.js
 */
(function( $, undefined ) {

$.widget( "ui.selectmenu", {
	version: "@VERSION",
	defaultElement: "<select>",
	options: {
		appendTo: "body",
		dropdown: true,
		position: {
			my: "left top",
			at: "left bottom",
			collision: "none"
		},

		// callbacks
		change: null,
		close: null,
		focus: null,
		open: null,
		select: null
	},

	_create: function() {
		var selectmenuId = this.element.uniqueId().attr( "id" );
		this.ids = { id: selectmenuId, button: selectmenuId + "-button", menu: selectmenuId + "-menu" };

		this._drawButton();
		this._drawMenu();

		this._on( document, this._documentClick );

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

	_drawButton: function() {
		var tabindex = this.element.attr( "tabindex" );

		// fix existing label
		this.label = $( "label[for='" + this.ids.id + "']" ).attr( "for", this.ids.button );
		this._on( this.label, {
			"click":  function( event ) {
				this.button.focus();
				event.preventDefault();
			}
		});

		// hide original select tag
		this.element.hide();

		// create button
		this.button = $( "<a>", {
			"class": "ui-button ui-widget ui-state-default ui-corner-all",
			href: "#" + this.ids.id,
			tabindex: ( tabindex ? tabindex : this.options.disabled ? -1 : 0 ),
			id: this.ids.button,
			width: this.element.outerWidth(),
			role: "combobox",
			"aria-expanded": false,
			"aria-autocomplete": "list",
			"aria-owns": this.ids.menu,
			"aria-haspopup": true
		});

		this.button.prepend( $( "<span>", {
			"class": "ui-icon " + ( ( this.options.dropdown ) ? "ui-icon-triangle-1-s" : "ui-icon-triangle-2-n-s" )
		}));

		this.buttonText = $( "<span>", {
				"class": "ui-selectmenu-text" ,
				html: this.element.find( "option:selected" ).text() || " "
			})
			.appendTo( this.button );

		// wrap and insert new button
		this.buttonWrap = $( "<span>", {
				"class": "ui-selectmenu-button"
			})
			.append( this.button )
			.insertAfter( this.element );

		this._on( this.button, this._buttonEvents );
		this._hoverable( this.button );
		this._focusable( this.button );
	},

	_drawMenu: function() {
		var menuInstance,
			that = this;

		// create menu portion, append to body
		this.menu = $( "<ul>", {
			"aria-hidden": true,
			"aria-labelledby": this.ids.button,
			id: this.ids.menu
		});

		// wrap menu
		this.menuWrap = $( "<div>", {
				"class": "ui-selectmenu-menu",
				width: ( this.options.dropdown ) ? this.button.outerWidth() : this.buttonText.width() + parseFloat( this.buttonText.css( "padding-left" ) ) || 0 + parseFloat( this.buttonText.css( "margin-left") ) || 0
			})
			.append( this.menu )
			.appendTo( this.options.appendTo );

		// init menu widget
		menuInstance = this.menu.menu({
			select: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );

				that._select( item, event );

				if ( that.isOpen ) {
					event.preventDefault();
					that.close( event );
				}
			},
			focus: function( event, ui ) {
				var item = ui.item.data( "ui-selectmenu-item" );
				// prevent inital focus from firing and checks if its a newly focused item
				if ( that.focus !== undefined && item.index !== that.focus ) {
					that._trigger( "focus", event, { item: item } );
					if ( !that.isOpen ) {
						that._select( item, event );
					}
				}
				that.focus = item.index;

				// Set ARIA active descendant
				that.button.attr( "aria-activedescendant", that.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
			},
			// set ARIA role
			role: "listbox"
		})
		.data( "ui-menu" );

		// dropdown style needs border on bottom only
		if ( this.options.dropdown ) {
			this.menu.addClass( "ui-corner-bottom" ).removeClass( "ui-corner-all" );
		}

		// make sure focus stays on selected item
		menuInstance.delay = 999999999;
		// unbind uneeded Menu events
		menuInstance._off( this.menu, "mouseleave" );
	},

	refresh: function() {
		this.menu.empty();

		var item,
			options = this.element.find( "option" );
		if ( options.length ) {
			this._readOptions( options );
			this._renderMenu( this.menu, this.items );

			this.menu.menu( "refresh" );
			this.menuItems = this.menu.find( "li" ).not( ".ui-selectmenu-optgroup" );

			// select current item
			item = this._getSelectedItem();
			// make sure menu is selected item aware
			this.menu.menu( "focus", null, item );
			this._setSelected( item.data( "ui-selectmenu-item" ) );

			// set disabled state
			this._setOption( "disabled", this._getCreateOptions().disabled );
		}
	},

	open: function( event ) {
		if ( this.options.disabled ) {
			return;
		}

		var _position = {
			of: this.button
		};

		// make sure menu is refreshed on first init (needed at least for IE9)
		if ( this.isOpen === undefined ) {
			this.button.trigger( "focus" );
		}

		this.isOpen = true;
		this._toggleAttr();

		// do not change position if non default position options are set (needed for custom positioned popup menus)
		if ( this.items && !this.options.dropdown && this.options.position.my == "left top" && this.options.position.at == "left bottom" ) {
			var currentItem = this._getSelectedItem();
			// center current item
			if ( this.menu.outerHeight() < this.menu.prop( "scrollHeight" ) ) {
				this.menuWrap.css( "left" , -10000 );
				this.menu.scrollTop( this.menu.scrollTop() + currentItem.position().top - this.menu.outerHeight() / 2 + currentItem.outerHeight() / 2 );
				this.menuWrap.css( "left" , "auto" );
			}
			_position.my = "left top" + ( this.menu.offset().top  - currentItem.offset().top + ( this.button.outerHeight() - currentItem.outerHeight() ) / 2 );
			_position.at = "left top";
		}

		this.menuWrap
			.zIndex( this.element.zIndex() + 1 )
			.position( $.extend( {}, this.options.position, _position ) );

		this._trigger( "open", event );
	},

	close: function( event ) {
		if ( !this.isOpen ) {
			return;
		}

		var id = this._getSelectedItem().find( "a" ).attr( "id" );
		this.isOpen = false;
		this._toggleAttr();
		this.button.attr( "aria-activedescendant", id );
		this.menu.attr( "aria-activedescendant", id );
		this._trigger( "close", event );
	},

	widget: function() {
		return this.button;
	},

	menuWidget: function() {
		return this.menu;
	},

	_renderMenu: function( ul, items ) {
		var that = this,
			currentOptgroup = "";

		$.each( items, function( index, item ) {
			if ( item.optgroup !== currentOptgroup ) {
				$( "<li />", {
					"class": "ui-selectmenu-optgroup" + ( item.element.parent( "optgroup" ).attr( "disabled" ) ? " ui-state-disabled" : "" ),
					text: item.optgroup
				}).appendTo( ul );
				currentOptgroup = item.optgroup;
			}
			that._renderItem( ul, item );
		});
	},

	_renderItem: function( ul, item ) {
		var li = $( "<li />" ).data( "ui-selectmenu-item", item );
		if ( item.disabled ) {
			li.addClass( "ui-state-disabled" );
		}
		li.append( $( "<a />", {
				text: item.label,
				href: "#"
			})
		);

		return li.appendTo( ul );
	},

	_move: function( direction, event ) {
		if ( direction === "first" || direction === "last" ) {
			// set focus manually for first or last item
			this.menu.menu( "focus", event, this.menuItems[ direction ]() );
		} else {
			// move to and focus next or prev item
			this.menu.menu( direction, event );
		}
	},

	_getSelectedItem: function() {
		return this.menuItems.eq( this.element[ 0 ].selectedIndex );
	},

	_toggle: function( event ) {
		if ( this.isOpen ) {
			this.close( event );
		} else {
			this.open( event );
		}
	},

	_documentClick: {
		click: function( event ) {
			if ( this.isOpen && !$( event.target ).closest( "li.ui-state-disabled, li.ui-selectmenu-optgroup, #" + this.ids.button ).length ) {
				this.close( event );
			}
		}
	},

	_buttonEvents: {
		focus: function() {
			// init Menu on first focus
			this.refresh();
			// reset focus class as its removed by ui.widget._setOption
			this.button.addClass( "ui-state-focus" );
			this._off( this.button, "focus" );
		},
		click: function( event ) {
			this._toggle( event );
			event.preventDefault();
		},
		keydown: function( event ) {
			var prevDef = true;
			switch ( event.keyCode ) {
				case $.ui.keyCode.TAB:
				case $.ui.keyCode.ESCAPE:
					if ( this.isOpen ) {
						this.close( event );
					}
					prevDef = false;
					break;
				case $.ui.keyCode.ENTER:
					if ( this.isOpen ) {
						this.menu.menu( "select", event );
					}
					break;
				case $.ui.keyCode.UP:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "previous", event );
					}
					break;
				case $.ui.keyCode.DOWN:
					if ( event.altKey ) {
						this._toggle( event );
					} else {
						this._move( "next", event );
					}
					break;
				case $.ui.keyCode.SPACE:
					if ( this.isOpen ) {
						this.menu.menu( "select", event );
					} else {
						this._toggle( event );
					}
					break;
				case $.ui.keyCode.LEFT:
					this._move( "previous", event );
					break;
				case $.ui.keyCode.RIGHT:
					this._move( "next", event );
					break;
				case $.ui.keyCode.HOME:
				case $.ui.keyCode.PAGE_UP:
					this._move( "first", event );
					break;
				case $.ui.keyCode.END:
				case $.ui.keyCode.PAGE_DOWN:
					this._move( "last", event );
					break;
				default:
					this.menu.trigger( event );
					prevDef = false;
			}
			if ( prevDef ) {
				event.preventDefault();
			}
		}
	},

	_select: function( item, event ) {
		var oldIndex = this.element[ 0 ].selectedIndex;
		// change native select element
		this.element[ 0 ].selectedIndex = item.index;
		this._setSelected( item );
		this._trigger( "select", event, { item: item } );

		if ( item.index !== oldIndex ) {
			this._trigger( "change", event, { item: item } );
		}
	},

	_setSelected: function( item ) {
		// update button text
		this.buttonText.html( item.label );
		// change ARIA attr
		this.menuItems.find( "a" ).attr( "aria-selected", false );
		this.menuItems.eq( item.index ).find( "a" ).attr( "aria-selected", true );
		this.button.attr( "aria-labelledby", this.menuItems.eq( item.index ).find( "a" ).attr( "id" ) );
	},

	_setOption: function( key, value ) {
		this._super( key, value );

		if ( key === "appendTo" ) {
			this.menuWrap.appendTo( this.document.find( value || "body" )[0] );
		}
		if ( key === "disabled" ) {
			this.menu.menu( "option", "disabled", value );
			if ( value ) {
				this.element.attr( "disabled", "disabled" );
				this.button.attr( "tabindex", -1 );
				this.close();
			} else {
				this.element.removeAttr( "disabled" );
				this.button.attr( "tabindex", 0 );
			}
		}
	},

	_toggleAttr: function(){
		if ( this.options.dropdown ) {
			this.button.toggleClass( "ui-corner-top", this.isOpen ).toggleClass( "ui-corner-all", !this.isOpen );
		}
		this.menuWrap.toggleClass( "ui-selectmenu-open", this.isOpen );
		this.menu.attr( "aria-hidden", !this.isOpen);
		this.button.attr( "aria-expanded", this.isOpen);
	},

	_getCreateOptions: function() {
		return { disabled: !!this.element.attr( "disabled" ) };
	},

	_readOptions: function( options ) {
		var data = [];
		options.each( function( index, item ) {
			var option = $( item ),
				optgroup = option.parent( "optgroup" );
			data.push({
				element: option,
				index: index,
				value: option.attr( "value" ),
				label: option.text() || " ",
				optgroup: optgroup.attr( "label" ) || "",
				disabled: optgroup.attr( "disabled" ) || option.attr( "disabled" )
			});
		});
		this.items = data;
	},

	_destroy: function() {
		this.menuWrap.remove();
		this.buttonWrap.remove();
		this.element.show();
		this.element.removeUniqueId();
		this.label.attr( "for", this.ids.id );
	}
});

}( jQuery ));
<|endoftext|>


<commit_before>export const PARSE_FILE_ERROR = 'PARSE_FILE_ERROR';
function parseFileError(detailedError) {
    return {
        type: PARSE_FILE_ERROR,
        error: 'Error parsing metadata.xml, see the console for detailed error message.',
        detailedError,
    };
}

function arrayLike(fnName, arr, ...args) {
    return Array.prototype[fnName].call(arr, ...args);
}
function getAttributeValue(element, attrName) {
    const attr = element.attributes.getNamedItem(attrName);
    return attr ? attr.value : null;
}

function decodeMetadata(doc) {
    const schema = doc.getElementsByTagName('Schema')[0];
    if (!schema) {
        throw parseFileError('Schema element was not found in the document.');
    }

    const entities = arrayLike('map', schema.getElementsByTagName('EntityType'),
        (entity) => {
            // get the key names
            const keyElement = entity.getElementsByTagName('Key')[0];
            const keyRefs = arrayLike('map', keyElement.getElementsByTagName('PropertyRef'),
                k => getAttributeValue(k, 'Name'));

            // get the properties
            const properties = arrayLike('map', entity.getElementsByTagName('Property'),
                (p) => {
                    const name = getAttributeValue(p, 'Name');
                    return {
                        name,
                        type: getAttributeValue(p, 'Type'),
                        nullable: getAttributeValue(p, 'Nullable'),
                        // check if the property belogs to the entity's key
                        isKey: keyRefs.filter(k => k === name).length > 0,
                    };
                });

            // get the navigation properties
            const navProperties = arrayLike('map', entity.getElementsByTagName('NavigationProperty'),
                p => ({
                    name: getAttributeValue(p, 'Name'),
                    type: 'Navigation',
                    association: getAttributeValue(p, 'Relationship'),
                }));

            // return the structured data
            return {
                name: getAttributeValue(entity, 'Name'),
                properties: properties.concat(navProperties),
            };
        });

    window.xx = {
        schema,
        entities,
    };
}

// dispatched when the user selects a new metadata file
export const READ_FILE = 'READ_FILE';
export const PARSE_FILE = 'PARSE_FILE';
export const readFile = file => (dispatch) => {
    if (!file) {
        return dispatch({
            type: PARSE_FILE_ERROR,
            error: 'Not a valid file',
        });
    }

    // let the store know we're loading
    dispatch({
        type: READ_FILE,
    });

    return new Promise((resolve) => {
        // read the file
        const reader = new FileReader();
        reader.onload = () => {
            // parse the XML
            let detailedError;
            const parser = new DOMParser();
            let doc;
            try {
                doc = parser.parseFromString(reader.result, 'text/xml');
            } catch (e) {
                detailedError = e;
            }

            // check for error
            const parseError = doc.getElementsByTagName('parsererror')[0];
            if (parseError) {
                detailedError = parseError.innerHTML.trim();
                resolve(dispatch(parseFileError(detailedError)));
            } else {
                // convert the document into a more managable form
                try {
                    const decodedDoc = decodeMetadata(doc);

                    // resolve by dispatching a PARSE_FILE action
                    resolve(dispatch({
                        type: PARSE_FILE,
                        doc: decodedDoc,
                    }));
                } catch (e) {
                    if (e instanceof Error) {
                        resolve(dispatch(parseFileError(e)));
                    } else {
                        resolve(dispatch(e));
                    }
                }
            }
        };
        reader.readAsText(file);
    });
};
<commit_msg>added association parsing<commit_after>export const PARSE_FILE_ERROR = 'PARSE_FILE_ERROR';
function parseFileError(detailedError) {
    return {
        type: PARSE_FILE_ERROR,
        error: 'Error parsing metadata.xml, see the console for detailed error message.',
        detailedError,
    };
}

function arrayLike(fnName, arr, ...args) {
    return Array.prototype[fnName].call(arr, ...args);
}
function getAttributeValue(element, attrName) {
    const attr = element.attributes.getNamedItem(attrName);
    return attr ? attr.value : null;
}

function decodeMetadata(doc) {
    const schema = doc.getElementsByTagName('Schema')[0];
    if (!schema) {
        throw parseFileError('Schema element was not found in the document.');
    }

    const namespace = `${getAttributeValue(schema, 'Namespace')}.`;

    // grab the entities
    const entities = arrayLike('map', schema.getElementsByTagName('EntityType'),
        (entity) => {
            // get the key names
            const keyElement = entity.getElementsByTagName('Key')[0];
            const keyRefs = arrayLike('map', keyElement.getElementsByTagName('PropertyRef'),
                k => getAttributeValue(k, 'Name'));

            // get the properties
            const properties = arrayLike('map', entity.getElementsByTagName('Property'),
                (p) => {
                    const name = getAttributeValue(p, 'Name');
                    return {
                        name,
                        type: getAttributeValue(p, 'Type'),
                        nullable: getAttributeValue(p, 'Nullable'),
                        // check if the property belogs to the entity's key
                        isKey: keyRefs.filter(k => k === name).length > 0,
                    };
                });

            // get the navigation properties
            const navProperties = arrayLike('map', entity.getElementsByTagName('NavigationProperty'),
                p => ({
                    name: getAttributeValue(p, 'Name'),
                    type: 'Navigation',
                    // grab the association key and de-namespace it
                    association: getAttributeValue(p, 'Relationship').replace(namespace, ''),
                }));

            // return the structured data
            return {
                name: getAttributeValue(entity, 'Name'),
                properties: properties.concat(navProperties),
            };
        });

    // get the associations
    const associations = arrayLike('map', schema.getElementsByTagName('Association'),
        (ass) => {
            // there should be two ends listed - the entities which are joined by the association
            const ends = arrayLike('map', ass.getElementsByTagName('End'),
                end => ({
                    // grab the entity name and de-namespace it
                    name: getAttributeValue(end, 'Type').replace(namespace, ''),
                    multiplicity: getAttributeValue(end, 'Multiplicity'),
                }));

            return {
                name: getAttributeValue(ass, 'Name'),
                entities: ends,
            };
        });

    return {
        entities,
        associations,
    };
}

// dispatched when the user selects a new metadata file
export const READ_FILE = 'READ_FILE';
export const PARSE_FILE = 'PARSE_FILE';
export const readFile = file => (dispatch) => {
    if (!file) {
        return dispatch({
            type: PARSE_FILE_ERROR,
            error: 'Not a valid file',
        });
    }

    // let the store know we're loading
    dispatch({
        type: READ_FILE,
    });

    return new Promise((resolve) => {
        // read the file
        const reader = new FileReader();
        reader.onload = () => {
            // parse the XML
            let detailedError;
            const parser = new DOMParser();
            let doc;
            try {
                doc = parser.parseFromString(reader.result, 'text/xml');
            } catch (e) {
                detailedError = e;
            }

            // check for error
            const parseError = doc.getElementsByTagName('parsererror')[0];
            if (parseError) {
                detailedError = parseError.innerHTML.trim();
                resolve(dispatch(parseFileError(detailedError)));
            } else {
                // convert the document into a more managable form
                try {
                    const decodedDoc = decodeMetadata(doc);

                    // resolve by dispatching a PARSE_FILE action
                    resolve(dispatch({
                        type: PARSE_FILE,
                        doc: decodedDoc,
                    }));
                } catch (e) {
                    if (e instanceof Error) {
                        resolve(dispatch(parseFileError(e)));
                    } else {
                        resolve(dispatch(e));
                    }
                }
            }
        };
        reader.readAsText(file);
    });
};
<|endoftext|>


<commit_before>var m = require('mithril');
var defined = require('common').defined;
var normalizeEval = require('chess').renderEval;
var dropThrottle = require('common').dropThrottle;
var treePath = require('tree').path;

var scrollThrottle = dropThrottle(150);

function autoScroll(ctrl, el) {
  scrollThrottle(function() {
    var cont = el.parentNode;
    var target = el.querySelector('.active');
    if (!target) {
      cont.scrollTop = ctrl.vm.path === treePath.root ? 0 : 99999;
      return;
    }
    cont.scrollTop = target.offsetTop - cont.offsetHeight / 2 + target.offsetHeight;
  });
}

function pathContains(ctx, path) {
  return treePath.contains(ctx.ctrl.vm.path, path);
}

function plyToTurn(ply) {
  return Math.floor((ply - 1) / 2) + 1;
}

function renderIndex(ply, withDots) {
  return {
    tag: 'index',
    children: [
      plyToTurn(ply) + (withDots ? (ply % 2 === 1 ? '.' : '...') : '')
    ]
  };
}

function renderChildrenOf(ctx, node, opts) {
  var cs = node.children;
  var main = cs[0];
  if (!main) return;
  if (opts.isMainline) {
    var isWhite = main.ply % 2 === 1;
    if (!cs[1]) return [
      isWhite ? renderIndex(main.ply, false) : null,
      renderMoveAndChildrenOf(ctx, main, {
        parentPath: opts.parentPath,
        isMainline: true
      })
    ];
    var mainChildren = renderChildrenOf(ctx, main, {
      parentPath: opts.parentPath + main.id,
      isMainline: true
    });
    var passOpts = {
      parentPath: opts.parentPath,
      isMainline: true
    };
    return [
      isWhite ? renderIndex(main.ply, false) : null,
      renderMoveOf(ctx, main, passOpts),
      isWhite ? emptyMove() : null,
      m('interrupt', [
        renderLines(ctx, cs.slice(1), {
          parentPath: opts.parentPath,
          isMainline: true
        })
      ]),
      isWhite && mainChildren ? [
        renderIndex(main.ply, false),
        emptyMove()
      ] : null,
      mainChildren
    ];
  }
  if (!cs[1]) return renderMoveAndChildrenOf(ctx, main, opts);
  return renderLines(ctx, cs, opts);
}

function renderLines(ctx, nodes, opts) {
  return {
    tag: 'lines',
    attrs: {
      class: nodes[1] ? '' : 'single'
    },
    children: nodes.map(function(n) {
      return lineTag(renderMoveAndChildrenOf(ctx, n, {
        parentPath: opts.parentPath,
        isMainline: false,
        withIndex: true
      }));
    })
  };
}

function lineTag(content) {
  return {
    tag: 'line',
    children: content
  };
}

function renderMoveOf(ctx, node, opts) {
  return opts.isMainline ? renderMainlineMoveOf(ctx, node, opts) : renderVariationMoveOf(ctx, node, opts);
}

function renderMainlineMoveOf(ctx, node, opts) {
  var path = opts.parentPath + node.id;
  var attrs = {
    p: path
  };
  var classes = [];
  if (path === ctx.ctrl.vm.path) classes.push('active');
  if (path === ctx.ctrl.vm.initialPath) classes.push('current');
  else if (node.ply < ctx.ctrl.vm.initialNode.ply) classes.push('hist');
  if (node.puzzle) {
    classes.push(node.puzzle);
  }
  if (classes.length) attrs.class = classes.join(' ');
  return moveTag(attrs, renderMove(ctx, node));
}

function renderGlyph(glyph) {
  return {
    tag: 'glyph',
    attrs: {
      title: glyph.name
    },
    children: [glyph.symbol]
  };
}

function puzzleGlyph(ctx, node) {
  switch (node.puzzle) {
    case 'good':
    case 'win':
      return renderGlyph({
        name: ctx.ctrl.trans.noarg('bestMove'),
        symbol: '✓'
      });
    case 'fail':
      return renderGlyph({
        name: ctx.ctrl.trans.noarg('puzzleFailed'),
        symbol: '✗'
      });
    case 'retry':
      return renderGlyph({
        name: ctx.ctrl.trans.noarg('goodMove'),
        symbol: '?!'
      });
  }
}

function renderMove(ctx, node) {
  var eval = node.eval || node.ceval || {};
  return [
    node.san,
    defined(eval.cp) ? renderEval(normalizeEval(eval.cp)) : (
      defined(eval.mate) ? renderEval('#' + eval.mate) : null
    ),
    puzzleGlyph(ctx, node)
  ];
}

function renderVariationMoveOf(ctx, node, opts) {
  var withIndex = opts.withIndex || node.ply % 2 === 1;
  var path = opts.parentPath + node.id;
  var attrs = {
    p: path
  };
  var classes = [];
  if (path === ctx.ctrl.vm.path) classes.push('active');
  else if (pathContains(ctx, path)) classes.push('parent');
  if (node.puzzle) classes.push(node.puzzle);
  if (classes.length) attrs.class = classes.join(' ');
  return moveTag(attrs, [
    withIndex ? renderIndex(node.ply, true) : null,
    node.san,
    puzzleGlyph(ctx, node)
  ]);
}

function renderMoveAndChildrenOf(ctx, node, opts) {
  var path = opts.parentPath + node.id;
  return [
    renderMoveOf(ctx, node, opts),
    renderChildrenOf(ctx, node, {
      parentPath: path,
      isMainline: opts.isMainline
    })
  ];
}

function moveTag(attrs, content) {
  return {
    tag: 'move',
    attrs: attrs,
    children: content
  };
}

function emptyMove() {
  return moveTag({
    class: 'empty'
  }, '...');
}

function renderEval(e) {
  return {
    tag: 'eval',
    children: [e]
  };
}

function eventPath(e, ctrl) {
  return e.target.getAttribute('p') || e.target.parentNode.getAttribute('p');
}

module.exports = {
  render: function(ctrl) {
    var root = ctrl.getTree().root;
    var ctx = {
      ctrl: ctrl,
      showComputer: false
    };
    return m('div.tview2', {
      config: function(el, isUpdate) {
        if (ctrl.vm.autoScrollNow) {
          autoScrollNow(ctrl, el);
          ctrl.vm.autoScrollNow = false;
          ctrl.vm.autoScrollRequested = false;
        }
        else if (ctrl.vm.autoScrollRequested || !isUpdate) {
          if (isUpdate || ctrl.vm.path !== treePath.root) autoScroll(ctrl, el);
          ctrl.vm.autoScrollRequested = false;
        }
        if (isUpdate) return;
        el.addEventListener('mousedown', function(e) {
          if (defined(e.button) && e.button !== 0) return; // only touch or left click
          var path = eventPath(e, ctrl);
          if (path) ctrl.userJump(path);
          m.redraw();
        });
      },
    }, [
      root.ply % 2 === 1 ? [
        renderIndex(root.ply, false),
        emptyMove()
      ] : null,
      renderChildrenOf(ctx, root, {
        parentPath: '',
        isMainline: true
      })
    ]);
  },
  renderIndex: renderIndex,
  renderMove: renderMove
};
<commit_msg>fix puzzle autoscroll<commit_after>var m = require('mithril');
var defined = require('common').defined;
var normalizeEval = require('chess').renderEval;
var dropThrottle = require('common').dropThrottle;
var treePath = require('tree').path;

var scrollThrottle = dropThrottle(150);

function autoScroll(ctrl, el) {
  scrollThrottle(function() {
    var cont = el.parentNode;
    var target = el.querySelector('.active');
    if (!target) {
      cont.scrollTop = ctrl.vm.path === treePath.root ? 0 : 99999;
      return;
    }
    cont.scrollTop = target.offsetTop - cont.offsetHeight / 2 + target.offsetHeight;
  });
}

function pathContains(ctx, path) {
  return treePath.contains(ctx.ctrl.vm.path, path);
}

function plyToTurn(ply) {
  return Math.floor((ply - 1) / 2) + 1;
}

function renderIndex(ply, withDots) {
  return {
    tag: 'index',
    children: [
      plyToTurn(ply) + (withDots ? (ply % 2 === 1 ? '.' : '...') : '')
    ]
  };
}

function renderChildrenOf(ctx, node, opts) {
  var cs = node.children;
  var main = cs[0];
  if (!main) return;
  if (opts.isMainline) {
    var isWhite = main.ply % 2 === 1;
    if (!cs[1]) return [
      isWhite ? renderIndex(main.ply, false) : null,
      renderMoveAndChildrenOf(ctx, main, {
        parentPath: opts.parentPath,
        isMainline: true
      })
    ];
    var mainChildren = renderChildrenOf(ctx, main, {
      parentPath: opts.parentPath + main.id,
      isMainline: true
    });
    var passOpts = {
      parentPath: opts.parentPath,
      isMainline: true
    };
    return [
      isWhite ? renderIndex(main.ply, false) : null,
      renderMoveOf(ctx, main, passOpts),
      isWhite ? emptyMove() : null,
      m('interrupt', [
        renderLines(ctx, cs.slice(1), {
          parentPath: opts.parentPath,
          isMainline: true
        })
      ]),
      isWhite && mainChildren ? [
        renderIndex(main.ply, false),
        emptyMove()
      ] : null,
      mainChildren
    ];
  }
  if (!cs[1]) return renderMoveAndChildrenOf(ctx, main, opts);
  return renderLines(ctx, cs, opts);
}

function renderLines(ctx, nodes, opts) {
  return {
    tag: 'lines',
    attrs: {
      class: nodes[1] ? '' : 'single'
    },
    children: nodes.map(function(n) {
      return lineTag(renderMoveAndChildrenOf(ctx, n, {
        parentPath: opts.parentPath,
        isMainline: false,
        withIndex: true
      }));
    })
  };
}

function lineTag(content) {
  return {
    tag: 'line',
    children: content
  };
}

function renderMoveOf(ctx, node, opts) {
  return opts.isMainline ? renderMainlineMoveOf(ctx, node, opts) : renderVariationMoveOf(ctx, node, opts);
}

function renderMainlineMoveOf(ctx, node, opts) {
  var path = opts.parentPath + node.id;
  var attrs = {
    p: path
  };
  var classes = [];
  if (path === ctx.ctrl.vm.path) classes.push('active');
  if (path === ctx.ctrl.vm.initialPath) classes.push('current');
  else if (node.ply < ctx.ctrl.vm.initialNode.ply) classes.push('hist');
  if (node.puzzle) {
    classes.push(node.puzzle);
  }
  if (classes.length) attrs.class = classes.join(' ');
  return moveTag(attrs, renderMove(ctx, node));
}

function renderGlyph(glyph) {
  return {
    tag: 'glyph',
    attrs: {
      title: glyph.name
    },
    children: [glyph.symbol]
  };
}

function puzzleGlyph(ctx, node) {
  switch (node.puzzle) {
    case 'good':
    case 'win':
      return renderGlyph({
        name: ctx.ctrl.trans.noarg('bestMove'),
        symbol: '✓'
      });
    case 'fail':
      return renderGlyph({
        name: ctx.ctrl.trans.noarg('puzzleFailed'),
        symbol: '✗'
      });
    case 'retry':
      return renderGlyph({
        name: ctx.ctrl.trans.noarg('goodMove'),
        symbol: '?!'
      });
  }
}

function renderMove(ctx, node) {
  var eval = node.eval || node.ceval || {};
  return [
    node.san,
    defined(eval.cp) ? renderEval(normalizeEval(eval.cp)) : (
      defined(eval.mate) ? renderEval('#' + eval.mate) : null
    ),
    puzzleGlyph(ctx, node)
  ];
}

function renderVariationMoveOf(ctx, node, opts) {
  var withIndex = opts.withIndex || node.ply % 2 === 1;
  var path = opts.parentPath + node.id;
  var attrs = {
    p: path
  };
  var classes = [];
  if (path === ctx.ctrl.vm.path) classes.push('active');
  else if (pathContains(ctx, path)) classes.push('parent');
  if (node.puzzle) classes.push(node.puzzle);
  if (classes.length) attrs.class = classes.join(' ');
  return moveTag(attrs, [
    withIndex ? renderIndex(node.ply, true) : null,
    node.san,
    puzzleGlyph(ctx, node)
  ]);
}

function renderMoveAndChildrenOf(ctx, node, opts) {
  var path = opts.parentPath + node.id;
  return [
    renderMoveOf(ctx, node, opts),
    renderChildrenOf(ctx, node, {
      parentPath: path,
      isMainline: opts.isMainline
    })
  ];
}

function moveTag(attrs, content) {
  return {
    tag: 'move',
    attrs: attrs,
    children: content
  };
}

function emptyMove() {
  return moveTag({
    class: 'empty'
  }, '...');
}

function renderEval(e) {
  return {
    tag: 'eval',
    children: [e]
  };
}

function eventPath(e, ctrl) {
  return e.target.getAttribute('p') || e.target.parentNode.getAttribute('p');
}

module.exports = {
  render: function(ctrl) {
    var root = ctrl.getTree().root;
    var ctx = {
      ctrl: ctrl,
      showComputer: false
    };
    return m('div.tview2', {
      config: function(el, isUpdate) {
        if (ctrl.vm.autoScrollNow) {
          autoScroll(ctrl, el);
          ctrl.vm.autoScrollNow = false;
          ctrl.vm.autoScrollRequested = false;
        }
        else if (ctrl.vm.autoScrollRequested || !isUpdate) {
          if (isUpdate || ctrl.vm.path !== treePath.root) autoScroll(ctrl, el);
          ctrl.vm.autoScrollRequested = false;
        }
        if (isUpdate) return;
        el.addEventListener('mousedown', function(e) {
          if (defined(e.button) && e.button !== 0) return; // only touch or left click
          var path = eventPath(e, ctrl);
          if (path) ctrl.userJump(path);
          m.redraw();
        });
      },
    }, [
      root.ply % 2 === 1 ? [
        renderIndex(root.ply, false),
        emptyMove()
      ] : null,
      renderChildrenOf(ctx, root, {
        parentPath: '',
        isMainline: true
      })
    ]);
  },
  renderIndex: renderIndex,
  renderMove: renderMove
};
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.dao',
  name: 'FixedSizeDAO',
  extends: 'foam.dao.ProxyDAO',

  documentation: `
    DAO that stores a fixed number of objects. Does not limit its delegate's
    storage. Rather, it is intended to be used in situations where the delegate
    does not store any data due to the amount of data being stored being
    prohibitively large. Instead, this DAO will store some of that data in
    memory, but it will start to replace old data after a certain point to
    prevent infinite growth.
  `,

  javaImports: [
    'foam.dao.Sink',
    'java.util.concurrent.locks.ReentrantLock'
  ],

  properties: [
    {
      class: 'Int',
      name: 'nextIndex'
    },
    {
      class: 'Int',
      name: 'fixedDAOSize',
      value: 10000,
      documentation: `Desired size of the fixedSizeDAO`
    },
    {
      class: 'Int',
      name: 'internalArraySize',
      javaFactory: `return ((int)  (1.1 *  (double) getFixedDAOSize() )); `,
      documentation: `array larger than FixedDAOSize, to allow for a point in
                      time view without blocking write access.
      `
    },
    {
      class: 'Array',
      of: 'foam.core.FObject',
      name: 'fixedSizeArray',
      javaFactory: `return new foam.core.FObject[ getInternalArraySize() ];`
    },
    {
      class: 'Object',
      name: 'lock',
      javaType: 'java.util.concurrent.locks.ReentrantLock',
      javaFactory: `return new java.util.concurrent.locks.ReentrantLock();`
    }
  ],

  methods: [
    {
      name: 'put_',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        }
      ],
      javaCode: `
  Integer insertAt;
  foam.core.FObject delegatedObject = getDelegate().put_(x, obj);
  getLock().lock();
  try {
    insertAt = getNextIndex();
    if ( insertAt == getInternalArraySize() ) {
      insertAt = 0;
    }
    setNextIndex( insertAt + 1 );
  } finally {
    getLock().unlock();
  }
  foam.core.FObject discard = getFixedSizeArray()[insertAt];
  getFixedSizeArray()[insertAt] = delegatedObject;
  if ( discard != null ) {
    getDelegate().remove_(x, discard);
  }
  return delegatedObject;
  `
    },
    {
      name: 'select_',
      javaCode: `
  if ( sink == null ) sink = new ArraySink();
  sink = prepareSink(sink);
  Sink decorated = decorateSink_(sink, skip, limit, order, predicate);

  Integer backCounter;

  if ( getNextIndex() <= 0 ) {
    backCounter = ( getInternalArraySize() - 1 );
  } else {
    backCounter = ( getNextIndex() - 1 );
  }

  for ( int i = 0; i < getFixedDAOSize() ; i++ ) {
    try {
      if ( getFixedSizeArray()[backCounter] == null ) {
        break;
      }
      decorated.put(getFixedSizeArray()[backCounter], null);
      if ( backCounter == 0 ) {
        backCounter = getInternalArraySize();
      }
      backCounter--;
    } catch (Exception e) {
      e.printStackTrace();
      break;
    }
  }
  decorated.eof();
  return sink;
`
    },
    {
      name: 'find_',
      javaCode: `
  try {
    Integer arrID = Integer.parseInt(id.toString());
    return getFixedSizeArray()[ (arrID - 1) % getFixedSizeArray().length ];
  } catch (Exception e ){
    return getDelegate().find_(x,id);
  }
  `
    }

  ]
});
<commit_msg>Add property to control removing from delegate - defaults to true<commit_after>/**
 * @license
 * Copyright 2018 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */

foam.CLASS({
  package: 'foam.dao',
  name: 'FixedSizeDAO',
  extends: 'foam.dao.ProxyDAO',

  documentation: `
    DAO that stores a fixed number of objects. Does not limit its delegate's
    storage. Rather, it is intended to be used in situations where the delegate
    does not store any data due to the amount of data being stored being
    prohibitively large. Instead, this DAO will store some of that data in
    memory, but it will start to replace old data after a certain point to
    prevent infinite growth.
    NOTE: Install via EasyDAO. It is important that when removeFromDelegate is true (the default) that this DAO is placed between the JDAO and it's delegate which is typically a MDOA or NullDAO.
  `,

  javaImports: [
    'foam.dao.Sink',
    'java.util.concurrent.locks.ReentrantLock'
  ],

  properties: [
    {
      documentation: 'when removing from internal circular buffer also remove from delegate DAO.',
      class: 'Boolean',
      name: 'removeFromDelegate',
      value: true
    },
    {
      class: 'Int',
      name: 'fixedDAOSize',
      value: 10000,
      documentation: `Desired size of the fixedSizeDAO`
    },
    {
      class: 'Int',
      name: 'nextIndex',
      hidden: true,
    },
    {
      class: 'Int',
      name: 'internalArraySize',
      javaFactory: `return ((int)  (1.1 *  (double) getFixedDAOSize() )); `,
      documentation: `array larger than FixedDAOSize, to allow for a point in
                      time view without blocking write access.
      `,
      hidden: true
    },
    {
      class: 'Array',
      of: 'foam.core.FObject',
      name: 'fixedSizeArray',
      javaFactory: `return new foam.core.FObject[ getInternalArraySize() ];`,
      hidden: true
    },
    {
      class: 'Object',
      name: 'lock',
      javaType: 'java.util.concurrent.locks.ReentrantLock',
      javaFactory: `return new java.util.concurrent.locks.ReentrantLock();`,
      hidden: true
    }
  ],

  methods: [
    {
      name: 'put_',
      args: [
        {
          name: 'x',
          type: 'Context'
        },
        {
          name: 'obj',
          type: 'FObject'
        }
      ],
      javaCode: `
  Integer insertAt;
  foam.core.FObject delegatedObject = getDelegate().put_(x, obj);
  getLock().lock();
  try {
    insertAt = getNextIndex();
    if ( insertAt == getInternalArraySize() ) {
      insertAt = 0;
    }
    setNextIndex( insertAt + 1 );
  } finally {
    getLock().unlock();
  }
  foam.core.FObject discard = getFixedSizeArray()[insertAt];
  getFixedSizeArray()[insertAt] = delegatedObject;
  if ( getRemoveFromDelegate() &&
       discard != null ) {
    getDelegate().remove_(x, discard);
  }
  return delegatedObject;
  `
    },
    {
      name: 'select_',
      javaCode: `
  if ( sink == null ) sink = new ArraySink();
  sink = prepareSink(sink);
  Sink decorated = decorateSink_(sink, skip, limit, order, predicate);

  Integer backCounter;

  if ( getNextIndex() <= 0 ) {
    backCounter = ( getInternalArraySize() - 1 );
  } else {
    backCounter = ( getNextIndex() - 1 );
  }

  for ( int i = 0; i < getFixedDAOSize() ; i++ ) {
    try {
      if ( getFixedSizeArray()[backCounter] == null ) {
        break;
      }
      decorated.put(getFixedSizeArray()[backCounter], null);
      if ( backCounter == 0 ) {
        backCounter = getInternalArraySize();
      }
      backCounter--;
    } catch (Exception e) {
      e.printStackTrace();
      break;
    }
  }
  decorated.eof();
  return sink;
`
    },
    {
      name: 'find_',
      javaCode: `
  try {
    Integer arrID = Integer.parseInt(id.toString());
    return getFixedSizeArray()[ (arrID - 1) % getFixedSizeArray().length ];
  } catch (Exception e ){
    return getDelegate().find_(x,id);
  }
  `
    }

  ]
});
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// TODO: have a way customize installed properties.
foam.CLASS({
  package: 'foam.dao',
  name: 'Relationship',
  implements: [ 'foam.mlang.Expressions' ],

  properties: [
    {
      name: 'id',
      hidden: true,
      transient: true,
      getter: function() {
        return this.package ? this.package + '.' + this.name : this.name;
      }
    },
    {
      name: 'package',
      // Default to sourceModel's package if not specified.
      factory: function() {
        return this.lookup(this.sourceModel).package;
      }
    },
    {
      name: 'name',
      transient: true,
      hidden: true,
      getter: function() {
        return this.lookup(this.sourceModel).name +
          foam.String.capitalize(this.forwardName) + 'Relationship';
      }
    },
    'forwardName',
    'inverseName',
    {
      // TODO: Support many to many relationships (cardinality of '*:*')
      name: 'cardinality',
      assertValue: function(value) {
        foam.assert(value == '1:1' || value == '1:*' || value == '*:1',
          'Current supported cardinalities are 1:1 1:* and *:1');
      },
      value: '1:*'
    },
    {
      name: 'sourceModel'
    },
    {
      class: 'FObjectArray',
      name: 'sourceProperties',
      of: 'Property',
      adaptArrayElement: foam.core.Model.PROPERTIES.adaptArrayElement
    },
    {
      name: 'targetModel'
    },
    {
      name: 'targetDAOKey',
      expression: function(targetModel) {
        return foam.String.daoize(foam.lookup(targetModel).name);
      }
    },
    {
      name: 'sourceDAOKey',
      expression: function(sourceModel) {
        return foam.String.daoize(foam.lookup(sourceModel).name);
      }
    },
    {
      class: 'FObjectArray',
      name: 'targetProperties',
      of: 'Property',
      adaptArrayElement: foam.core.Model.PROPERTIES.adaptArrayElement
    },
    {
      class: 'Boolean',
      name: 'oneWay'
    }
    /* FUTURE:
    {
      name: 'deleteStrategy'
      // prevent, cascade, orphan
    }
    */
  ],

  methods: [
    function init() {
      var sourceProps  = this.sourceProperties || [];
      var targetProps  = this.targetProperties || [];
      var cardinality  = this.cardinality.split(":");
      var forwardName  = this.forwardName;
      var inverseName  = this.inverseName;
      var relationship = this;

      if ( ! sourceProps.length ) {
        if ( cardinality[1] == '*' ) {
          sourceProps = [
            foam.core.Property.create({
              name: forwardName,
              transient: true,
              setter: function() {},
              getter: function() {
                return this.instance_[forwardName] ?
                  this.instance_[forwardName] :
                  this.instance_[forwardName] = foam.dao.RelationshipDAO.create({
                    obj: this,
                    relationship: relationship
                  }, this)
              }
            })
          ];
        } else {
          sourceProps = [
            foam.core.Reference.create({
              name: forwardName,
              of: this.targetModel,
              targetDAOKey: this.targetDAOKey
            })
          ];
        }
      }

      if ( ! targetProps.length ) {
        if ( cardinality[0] == '*' ) {
          targetProps = [
            foam.core.Property.create({
              name: forwardName,
              transient: true,
              setter: function() {},
              getter: function() {
                return this.instance_[forwardName] ?
                  this.instance_[forwardName] :
                  this.instance_[forwardName] = foam.dao.RelationshipDAO.create({
                    obj: this,
                    forward: false,
                    relationship: relationship
                  }, this)
              }
            })
          ];
        } else {
          targetProps = [
            foam.core.Reference.create({
              name: inverseName,
              of: this.sourceModel,
              targetDAOKey: this.sourceDAOKey
            })
          ];
        }
      }

      foam.assert(
          sourceProps.length === targetProps.length,
          'Relationship source/target property list length mismatch.');

      var source = this.lookup(this.sourceModel);
      var target = this.lookup(this.targetModel);

      foam.assert(source, 'Unknown sourceModel: ', this.sourceModel);
      foam.assert(target, 'Unknown targetModel: ', this.targetModel);

      for ( var i = 0 ; i < sourceProps.length ; i++ ) {
        var sp = sourceProps[i];
        var tp = targetProps[i];

        if ( ! source.getAxiomByName(sp.name) ) {
          source.installAxiom(sp);
        }

        if ( ! this.oneWay && ! target.getAxiomByName(tp.name) ) {
          target.installAxiom(tp);
        }
      }

      /*
      if ( ! this.oneWay ) {
        sourceProperty.preSet = function(_, newValue) {
          if ( newValue ) {
            for ( var i = 0 ; i < sourceProps.length ; i++ ) {
              newValue[targetProps[i].name] = this[sourceProps[i]];
            }
          }
          return newValue;
        };
      }
      */
    },

    function targetQueryFromSource(obj, forward) {
      var targetClass = this.lookup(forward ? this.targetModel : this.sourceModel);
      var name        = forward ? this.inverseName : this.forwardName;
      var targetProp  = targetClass[foam.String.constantize(name)];
      return this.EQ(targetProp, obj.id);
    },

    function adaptTarget(source, target, forward) {
      if ( forward ) {
        target[this.inverseName] = source.id;
      } else {
        source[this.forwardName] = target.id;
      }
    }
  ]
});

foam.LIB({
  name: 'foam',
  methods: [
    function RELATIONSHIP(m) {
      var r = foam.dao.Relationship.create(m);

      r.validate && r.validate();
      foam.package.registerClass(r);

      return r;
    }
  ]
});
<commit_msg>Fixes #228, ability to hide relationships.<commit_after>/**
 * @license
 * Copyright 2016 Google Inc. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

foam.CLASS({
  package: 'foam.dao',
  name: 'Relationship',
  implements: [ 'foam.mlang.Expressions' ],

  properties: [
    {
      name: 'id',
      hidden: true,
      transient: true,
      getter: function() {
        return this.package ? this.package + '.' + this.name : this.name;
      }
    },
    {
      name: 'package',
      // Default to sourceModel's package if not specified.
      factory: function() {
        return this.lookup(this.sourceModel).package;
      }
    },
    {
      name: 'name',
      transient: true,
      hidden: true,
      getter: function() {
        return this.lookup(this.sourceModel).name +
          foam.String.capitalize(this.forwardName) + 'Relationship';
      }
    },
    'forwardName',
    'inverseName',
    {
      // TODO: Support many to many relationships (cardinality of '*:*')
      name: 'cardinality',
      assertValue: function(value) {
        foam.assert(value == '1:1' || value == '1:*' || value == '*:1',
          'Current supported cardinalities are 1:1 1:* and *:1');
      },
      value: '1:*'
    },
    {
      name: 'sourceModel'
    },
    {
      class: 'FObjectArray',
      name: 'sourceProperties',
      of: 'Property',
      adaptArrayElement: foam.core.Model.PROPERTIES.adaptArrayElement
    },
    {
      name: 'targetModel'
    },
    {
      name: 'targetDAOKey',
      expression: function(targetModel) {
        return foam.String.daoize(foam.lookup(targetModel).name);
      }
    },
    {
      name: 'sourceDAOKey',
      expression: function(sourceModel) {
        return foam.String.daoize(foam.lookup(sourceModel).name);
      }
    },
    {
      class: 'FObjectArray',
      name: 'targetProperties',
      of: 'Property',
      adaptArrayElement: foam.core.Model.PROPERTIES.adaptArrayElement
    },
    {
      class: 'Boolean',
      name: 'oneWay'
    },
    {
      class: 'FObjectProperty',
      of: 'Property',
      name: 'sourcePropertyConfig'
    },
    {
      class: 'FObjectProperty',
      of: 'Property',
      name: 'targetPropertyConfig'
    },
    /* FUTURE:
    {
      name: 'deleteStrategy'
      // prevent, cascade, orphan
    }
    */
  ],

  methods: [
    function init() {
      var sourceProps  = this.sourceProperties || [];
      var targetProps  = this.targetProperties || [];
      var cardinality  = this.cardinality.split(':');
      var forwardName  = this.forwardName;
      var inverseName  = this.inverseName;
      var relationship = this;

      if ( ! sourceProps.length ) {
        if ( cardinality[1] === '*' ) {
          sourceProps = [
            foam.core.Property.create({
              name: forwardName,
              transient: true,
              setter: function() {},
              getter: function() {
                return this.instance_[forwardName] ?
                  this.instance_[forwardName] :
                  this.instance_[forwardName] = foam.dao.RelationshipDAO.create({
                    obj: this,
                    relationship: relationship
                  }, this)
              }
            }).copyFrom(this.sourceProperty)
          ];
        } else {
          sourceProps = [
            foam.core.Reference.create({
              name: forwardName,
              of: this.targetModel,
              targetDAOKey: this.targetDAOKey
            }).copyFrom(this.sourceProperty)
          ];
        }
      }

      if ( ! targetProps.length ) {
        if ( cardinality[0] == '*' ) {
          targetProps = [
            foam.core.Property.create({
              name: forwardName,
              transient: true,
              setter: function() {},
              getter: function() {
                return this.instance_[forwardName] ?
                  this.instance_[forwardName] :
                  this.instance_[forwardName] = foam.dao.RelationshipDAO.create({
                    obj: this,
                    forward: false,
                    relationship: relationship
                  }, this)
              }
            }).copyFrom(this.targetProperty)
          ];
        } else {
          targetProps = [
            foam.core.Reference.create({
              name: inverseName,
              of: this.sourceModel,
              targetDAOKey: this.sourceDAOKey
            }).copyFrom(this.targetProperty)
          ];
        }
      }

      foam.assert(
          sourceProps.length === targetProps.length,
          'Relationship source/target property list length mismatch.');

      var source = this.lookup(this.sourceModel);
      var target = this.lookup(this.targetModel);

      foam.assert(source, 'Unknown sourceModel: ', this.sourceModel);
      foam.assert(target, 'Unknown targetModel: ', this.targetModel);

      for ( var i = 0 ; i < sourceProps.length ; i++ ) {
        var sp = sourceProps[i];
        var tp = targetProps[i];

        if ( ! source.getAxiomByName(sp.name) ) {
          source.installAxiom(sp);
        }

        if ( ! this.oneWay && ! target.getAxiomByName(tp.name) ) {
          target.installAxiom(tp);
        }
      }

      /*
      if ( ! this.oneWay ) {
        sourceProperty.preSet = function(_, newValue) {
          if ( newValue ) {
            for ( var i = 0 ; i < sourceProps.length ; i++ ) {
              newValue[targetProps[i].name] = this[sourceProps[i]];
            }
          }
          return newValue;
        };
      }
      */
    },

    function targetQueryFromSource(obj, forward) {
      var targetClass = this.lookup(forward ? this.targetModel : this.sourceModel);
      var name        = forward ? this.inverseName : this.forwardName;
      var targetProp  = targetClass[foam.String.constantize(name)];
      return this.EQ(targetProp, obj.id);
    },

    function adaptTarget(source, target, forward) {
      if ( forward ) {
        target[this.inverseName] = source.id;
      } else {
        source[this.forwardName] = target.id;
      }
    }
  ]
});

foam.LIB({
  name: 'foam',
  methods: [
    function RELATIONSHIP(m) {
      var r = foam.dao.Relationship.create(m);

      r.validate && r.validate();
      foam.package.registerClass(r);

      return r;
    }
  ]
});
<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
(function($, cloudStack) {
    cloudStack.sections.vmsnapshots = {
        title: 'label.vmsnapshot',
        id: 'vmsnapshots',
        listView: {
            id: 'vmsnapshots',
            isMaximized: true,
            fields: {
                displayname: {
                    label: 'label.name'
                },
                state: {
                    label: 'label.state',
                    indicator: {
                        'Ready': 'on',
                        'Error': 'off'
                    }
                },
                type: {
                    label: 'label.vmsnapshot.type'
                },
                current: {
                    label: 'label.vmsnapshot.current',
                    converter: cloudStack.converters.toBooleanText
                },
                parentName: {
                    label: 'label.vmsnapshot.parentname'
                },
                created: {
                    label: 'label.date',
                    converter: cloudStack.converters.toLocalDate
                }
            },

            dataProvider: function(args) {
                var apiCmd = "listVMSnapshot&listAll=true";
                if (args.context != null) {
                    if ("instances" in args.context) {
                        apiCmd += "&virtualmachineid=" + args.context.instances[0].id;
                    }
                }
                $.ajax({
                    url: createURL(apiCmd),
                    dataType: "json",
                    async: true,
                    success: function(json) {
                        var jsonObj;
                        jsonObj = json.listvmsnapshotresponse.vmSnapshot;
                        args.response.success({
                            data: jsonObj
                        });
                    }
                });
            },
            //dataProvider end
            detailView: {
                tabs: {
                    details: {
                        title: 'label.details',
                        fields: {
                            id: {
                                label: 'label.id'
                            },
                            name: {
                                label: 'label.name'
                            },
                            displayname: {
                                label: 'label.display.name',
                            },
                            type: {
                                label: 'label.vmsnapshot.type',
                            },
                            description: {
                                label: 'label.description',
                            },
                            state: {
                                label: 'label.state',
                                indicator: {
                                    'Ready': 'on',
                                    'Error': 'off'
                                }
                            },
                            current: {
                                label: 'label.vmsnapshot.current',
                                converter: cloudStack.converters.toBooleanText
                            },
                            parentName: {
                                label: 'label.vmsnapshot.parentname'
                            },
                            created: {
                                label: 'label.date',
                                converter: cloudStack.converters.toLocalDate
                            },

                        },
                        dataProvider: function(args) {
                            $.ajax({
                                url: createURL("listVMSnapshot&listAll=true&id=" + args.context.vmsnapshots[0].id),
                                dataType: "json",
                                async: true,
                                success: function(json) {
                                    var jsonObj;
                                    jsonObj = json.listvmsnapshotresponse.vmSnapshot[0];
                                    args.response.success({
                                        //actionFilter: vmActionfilter,
                                        data: jsonObj
                                    });
                                }
                            });
                        },
                        tags: cloudStack.api.tags({
                            resourceType: 'VMSnapshot',
                            contextId: 'vmsnapshots'
                        })
                    }
                },
                actions: {
                    //delete a snapshot
                    remove: {
                        label: 'label.action.vmsnapshot.delete',
                        messages: {
                            confirm: function(args) {
                                return 'message.action.vmsnapshot.delete';
                            },
                            notification: function(args) {
                                return 'label.action.vmsnapshot.delete';
                            }
                        },
                        action: function(args) {
                            $.ajax({
                                url: createURL("deleteVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
                                dataType: "json",
                                async: true,
                                success: function(json) {
                                    var jid = json.deletevmsnapshotresponse.jobid;
                                    args.response.success({
                                        _custom: {
                                            jobId: jid
                                        }
                                    });
                                }
                            });
                        },
                        notification: {
                            poll: pollAsyncJobResult
                        }
                    },
                    restart: {
                        label: 'label.action.vmsnapshot.revert',
                        messages: {
                            confirm: function(args) {
                                return 'label.action.vmsnapshot.revert';
                            },
                            notification: function(args) {
                                return 'message.action.vmsnapshot.revert';
                            }
                        },
                        action: function(args) {
                            $.ajax({
                                url: createURL("revertToVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
                                dataType: "json",
                                async: true,
                                success: function(json) {
                                    var jid = json.reverttovmsnapshotresponse.jobid;
                                    args.response.success({
                                        _custom: {
                                            jobId: jid
                                        }
                                    });
                                }
                            });

                        },
                        notification: {
                            poll: pollAsyncJobResult
                        }
                    }
                }
            }
            //detailview end
        }
    }
})(jQuery, cloudStack);
<commit_msg>fix UI display bug for vmsnapshot, detailView of vmsnapshot always show the same one<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License.  You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
(function($, cloudStack) {
    cloudStack.sections.vmsnapshots = {
        title: 'label.vmsnapshot',
        id: 'vmsnapshots',
        listView: {
            id: 'vmsnapshots',
            isMaximized: true,
            fields: {
                displayname: {
                    label: 'label.name'
                },
                state: {
                    label: 'label.state',
                    indicator: {
                        'Ready': 'on',
                        'Error': 'off'
                    }
                },
                type: {
                    label: 'label.vmsnapshot.type'
                },
                current: {
                    label: 'label.vmsnapshot.current',
                    converter: cloudStack.converters.toBooleanText
                },
                parentName: {
                    label: 'label.vmsnapshot.parentname'
                },
                created: {
                    label: 'label.date',
                    converter: cloudStack.converters.toLocalDate
                }
            },

            dataProvider: function(args) {
                var apiCmd = "listVMSnapshot&listAll=true";
                if (args.context != null) {
                    if ("instances" in args.context) {
                        apiCmd += "&virtualmachineid=" + args.context.instances[0].id;
                    }
                }
                $.ajax({
                    url: createURL(apiCmd),
                    dataType: "json",
                    async: true,
                    success: function(json) {
                        var jsonObj;
                        jsonObj = json.listvmsnapshotresponse.vmSnapshot;
                        args.response.success({
                            data: jsonObj
                        });
                    }
                });
            },
            //dataProvider end
            detailView: {
                tabs: {
                    details: {
                        title: 'label.details',
                        fields: {
                            id: {
                                label: 'label.id'
                            },
                            name: {
                                label: 'label.name'
                            },
                            displayname: {
                                label: 'label.display.name',
                            },
                            type: {
                                label: 'label.vmsnapshot.type',
                            },
                            description: {
                                label: 'label.description',
                            },
                            state: {
                                label: 'label.state',
                                indicator: {
                                    'Ready': 'on',
                                    'Error': 'off'
                                }
                            },
                            current: {
                                label: 'label.vmsnapshot.current',
                                converter: cloudStack.converters.toBooleanText
                            },
                            parentName: {
                                label: 'label.vmsnapshot.parentname'
                            },
                            created: {
                                label: 'label.date',
                                converter: cloudStack.converters.toLocalDate
                            },

                        },
                        dataProvider: function(args) {
                            $.ajax({
                                url: createURL("listVMSnapshot&listAll=true&vmsnapshotid=" + args.context.vmsnapshots[0].id),
                                dataType: "json",
                                async: true,
                                success: function(json) {
                                    var jsonObj;
                                    jsonObj = json.listvmsnapshotresponse.vmSnapshot[0];
                                    args.response.success({
                                        //actionFilter: vmActionfilter,
                                        data: jsonObj
                                    });
                                }
                            });
                        },
                        tags: cloudStack.api.tags({
                            resourceType: 'VMSnapshot',
                            contextId: 'vmsnapshots'
                        })
                    }
                },
                actions: {
                    //delete a snapshot
                    remove: {
                        label: 'label.action.vmsnapshot.delete',
                        messages: {
                            confirm: function(args) {
                                return 'message.action.vmsnapshot.delete';
                            },
                            notification: function(args) {
                                return 'label.action.vmsnapshot.delete';
                            }
                        },
                        action: function(args) {
                            $.ajax({
                                url: createURL("deleteVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
                                dataType: "json",
                                async: true,
                                success: function(json) {
                                    var jid = json.deletevmsnapshotresponse.jobid;
                                    args.response.success({
                                        _custom: {
                                            jobId: jid
                                        }
                                    });
                                }
                            });
                        },
                        notification: {
                            poll: pollAsyncJobResult
                        }
                    },
                    restart: {
                        label: 'label.action.vmsnapshot.revert',
                        messages: {
                            confirm: function(args) {
                                return 'label.action.vmsnapshot.revert';
                            },
                            notification: function(args) {
                                return 'message.action.vmsnapshot.revert';
                            }
                        },
                        action: function(args) {
                            $.ajax({
                                url: createURL("revertToVMSnapshot&vmsnapshotid=" + args.context.vmsnapshots[0].id),
                                dataType: "json",
                                async: true,
                                success: function(json) {
                                    var jid = json.reverttovmsnapshotresponse.jobid;
                                    args.response.success({
                                        _custom: {
                                            jobId: jid
                                        }
                                    });
                                }
                            });

                        },
                        notification: {
                            poll: pollAsyncJobResult
                        }
                    }
                }
            }
            //detailview end
        }
    }
})(jQuery, cloudStack);
<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */
foam.CLASS({
  package: 'foam.nanos.auth',
  name: 'Phone',

  documentation: 'Phone number information.',

  constants: [
    {
      name: 'PHONE_NUMBER_REGEX',
      factory: () => /^(?:\+?)(999|998|997|996|995|994|993|992|991|990|979|978|977|976|975|974|973|972|971|970|969|968|967|966|965|964|963|962|961|960|899|898|897|896|895|894|893|892|891|890|889|888|887|886|885|884|883|882|881|880|879|878|877|876|875|874|873|872|871|870|859|858|857|856|855|854|853|852|851|850|839|838|837|836|835|834|833|832|831|830|809|808|807|806|805|804|803|802|801|800|699|698|697|696|695|694|693|692|691|690|689|688|687|686|685|684|683|682|681|680|679|678|677|676|675|674|673|672|671|670|599|598|597|596|595|594|593|592|591|590|509|508|507|506|505|504|503|502|501|500|429|428|427|426|425|424|423|422|421|420|389|388|387|386|385|384|383|382|381|380|379|378|377|376|375|374|373|372|371|370|359|358|357|356|355|354|353|352|351|350|299|298|297|296|295|294|293|292|291|290|289|288|287|286|285|284|283|282|281|280|269|268|267|266|265|264|263|262|261|260|259|258|257|256|255|254|253|252|251|250|249|248|247|246|245|244|243|242|241|240|239|238|237|236|235|234|233|232|231|230|229|228|227|226|225|224|223|222|221|220|219|218|217|216|215|214|213|212|211|210|98|95|94|93|92|91|90|86|84|82|81|66|65|64|63|62|61|60|58|57|56|55|54|53|52|51|49|48|47|46|45|44|43|41|40|39|36|34|33|32|31|30|27|20|7|1){1}[0-9]{4,11}$/,
    }
  ],

  properties: [
    {
      class: 'PhoneNumber',
      name: 'number',
      label: 'Phone Number',
      validationPredicates: [
        {
          args: ['number'],
          predicateFactory: function(e) {
            return e.REG_EXP(
              foam.nanos.auth.Phone.NUMBER,
              /^(?:\+?)(999|998|997|996|995|994|993|992|991|990|979|978|977|976|975|974|973|972|971|970|969|968|967|966|965|964|963|962|961|960|899|898|897|896|895|894|893|892|891|890|889|888|887|886|885|884|883|882|881|880|879|878|877|876|875|874|873|872|871|870|859|858|857|856|855|854|853|852|851|850|839|838|837|836|835|834|833|832|831|830|809|808|807|806|805|804|803|802|801|800|699|698|697|696|695|694|693|692|691|690|689|688|687|686|685|684|683|682|681|680|679|678|677|676|675|674|673|672|671|670|599|598|597|596|595|594|593|592|591|590|509|508|507|506|505|504|503|502|501|500|429|428|427|426|425|424|423|422|421|420|389|388|387|386|385|384|383|382|381|380|379|378|377|376|375|374|373|372|371|370|359|358|357|356|355|354|353|352|351|350|299|298|297|296|295|294|293|292|291|290|289|288|287|286|285|284|283|282|281|280|269|268|267|266|265|264|263|262|261|260|259|258|257|256|255|254|253|252|251|250|249|248|247|246|245|244|243|242|241|240|239|238|237|236|235|234|233|232|231|230|229|228|227|226|225|224|223|222|221|220|219|218|217|216|215|214|213|212|211|210|98|95|94|93|92|91|90|86|84|82|81|66|65|64|63|62|61|60|58|57|56|55|54|53|52|51|49|48|47|46|45|44|43|41|40|39|36|34|33|32|31|30|27|20|7|1){1}[0-9]{4,11}$/);
          },
          errorString: 'Please enter phone number'
        }
      ]
    },
    {
      class: 'Boolean',
      name: 'verified',
      writePermissionRequired: true,
      readPermissionRequired: true,
      createVisibility: 'HIDDEN',
    }
  ]
});
<commit_msg>Switch Phone regex back to constant.<commit_after>/**
 * @license
 * Copyright 2017 The FOAM Authors. All Rights Reserved.
 * http://www.apache.org/licenses/LICENSE-2.0
 */
foam.CLASS({
  package: 'foam.nanos.auth',
  name: 'Phone',

  documentation: 'Phone number information.',

  constants: [
    {
      name: 'PHONE_NUMBER_REGEX',
      factory: () => /^(?:\+?)(999|998|997|996|995|994|993|992|991|990|979|978|977|976|975|974|973|972|971|970|969|968|967|966|965|964|963|962|961|960|899|898|897|896|895|894|893|892|891|890|889|888|887|886|885|884|883|882|881|880|879|878|877|876|875|874|873|872|871|870|859|858|857|856|855|854|853|852|851|850|839|838|837|836|835|834|833|832|831|830|809|808|807|806|805|804|803|802|801|800|699|698|697|696|695|694|693|692|691|690|689|688|687|686|685|684|683|682|681|680|679|678|677|676|675|674|673|672|671|670|599|598|597|596|595|594|593|592|591|590|509|508|507|506|505|504|503|502|501|500|429|428|427|426|425|424|423|422|421|420|389|388|387|386|385|384|383|382|381|380|379|378|377|376|375|374|373|372|371|370|359|358|357|356|355|354|353|352|351|350|299|298|297|296|295|294|293|292|291|290|289|288|287|286|285|284|283|282|281|280|269|268|267|266|265|264|263|262|261|260|259|258|257|256|255|254|253|252|251|250|249|248|247|246|245|244|243|242|241|240|239|238|237|236|235|234|233|232|231|230|229|228|227|226|225|224|223|222|221|220|219|218|217|216|215|214|213|212|211|210|98|95|94|93|92|91|90|86|84|82|81|66|65|64|63|62|61|60|58|57|56|55|54|53|52|51|49|48|47|46|45|44|43|41|40|39|36|34|33|32|31|30|27|20|7|1){1}[0-9]{4,11}$/,
    }
  ],

  properties: [
    {
      class: 'PhoneNumber',
      name: 'number',
      label: 'Phone Number',
      validationPredicates: [
        {
          args: ['number'],
          predicateFactory: function(e) {
            return e.REG_EXP(
              foam.nanos.auth.Phone.NUMBER, foam.nanos.auth.Phone.PHONE_NUMBER_REGEX);
          },
          errorString: 'Please enter phone number'
        }
      ]
    },
    {
      class: 'Boolean',
      name: 'verified',
      writePermissionRequired: true,
      readPermissionRequired: true,
      createVisibility: 'HIDDEN'
    }
  ]
});
<|endoftext|>