<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Applies button styling to links
//>>label: Buttons: Link-based
//>>group: Forms
//>>css.structure: ../css/structure/jquery.mobile.button.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "./jquery.mobile.core", "./jquery.mobile.registry" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");

(function( $, undefined ) {
"use strict";

// General policy: Do not access data-* attributes except during enhancement.
// In all other cases we determine the state of the button exclusively from its
// className. That's why optionsToClassName expects a full complement of
// options, and the jQuery plugin completes the set of options from the default
// values.

// Map classes to buttonMarkup boolean options - used in classNameToOptions()
var reverseBoolOptionMap = {
	"ui-shadow" : "shadow",
	"ui-corner-all" : "corners",
	"ui-btn-inline" : "inline",
	"ui-shadow-icon" : "iconshadow",
	"ui-mini" : "mini"
};

// optionsToClassName:
// @options: A complete set of options to convert to class names.
// @existingClasses: extra classes to add to the result
//
// Converts @options to buttonMarkup classes and returns the result as a string
// that can be used as an element's className. All possible options must be set
// inside @options. Use $.fn.buttonMarkup.defaults to get a complete set and use
// $.extend to override your choice of options from that set.
function optionsToClassName( options, existingClasses ) {
	var classes = existingClasses ? existingClasses : [];

	// Add classes to the array - first ui-btn
	classes.push( "ui-btn" );

	// If there is a theme
	if ( options.theme ) {
		classes.push( "ui-btn-" + options.theme );
	}

	// If there's an icon, add the icon-related classes
	if ( options.icon ) {
		classes = classes.concat([
			"ui-icon-" + options.icon,
			"ui-btn-icon-" + options.iconpos
		]);
		if ( options.iconshadow ) {
			classes.push( "ui-shadow-icon" );
		}
	}

	// Add the appropriate class for each boolean option
	if ( options.inline ) {
		classes.push( "ui-btn-inline" );
	}
	if ( options.shadow ) {
		classes.push( "ui-shadow" );
	}
	if ( options.corners ) {
		classes.push( "ui-corner-all" );
	}
	if ( options.mini ) {
		classes.push( "ui-mini" );
	}

	// Create a string from the array and return it
	return classes.join( " " );
}

// classNameToOptions:
// @classes: A string containing a .className-style space-separated class list
//
// Loops over @classes and calculates an options object based on the
// buttonMarkup-related classes it finds. It records unrecognized classes in an
// array.
//
// Returns: An object containing the following items:
//
// "options": buttonMarkup options found to be present because of the
// presence/absence of corresponding classes
//
// "unknownClasses": a string containing all the non-buttonMarkup-related
// classes found in @classes
//
// "alreadyEnhanced": A boolean indicating whether the ui-btn class was among
// those found to be present
function classNameToOptions( classes ) {
	var idx, map, unknownClass,
		alreadyEnhanced = false,
		noIcon = true,
		o = {
			icon: "",
			inline: false,
			shadow: false,
			corners: false,
			iconshadow: false,
			mini: false
		},
		unknownClasses = [];

	classes = classes.split( " " );

	// Loop over the classes
	for ( idx = 0 ; idx < classes.length ; idx++ ) {

		// Assume it's an unrecognized class
		unknownClass = true;

		// Recognize boolean options from the presence of classes
		map = reverseBoolOptionMap[ classes[ idx ] ];
		if ( map !== undefined ) {
			unknownClass = false;
			o[ map ] = true;

		// Recognize the presence of an icon and establish the icon position
		} else if ( classes[ idx ].indexOf( "ui-btn-icon-" ) === 0 ) {
			unknownClass = false;
			noIcon = false;
			o.iconpos = classes[ idx ].substring( 12 );

		// Establish which icon is present
		} else if ( classes[ idx ].indexOf( "ui-icon-" ) === 0 ) {
			unknownClass = false;
			o.icon = classes[ idx ].substring( 8 );

		// Establish the theme - this recognizes one-letter theme swatch names
		} else if ( classes[ idx ].indexOf( "ui-btn-" ) === 0 && classes[ idx ].length === 8 ) {
			unknownClass = false;
			o.theme = classes[ idx ].substring( 7 );

		// Recognize that this element has already been buttonMarkup-enhanced
		} else if ( classes[ idx ] === "ui-btn" ) {
			unknownClass = false;
			alreadyEnhanced = true;
		}

		// If this class has not been recognized, add it to the list
		if ( unknownClass ) {
			unknownClasses.push( classes[ idx ] );
		}
	}

	// If a "ui-btn-icon-*" icon position class is absent there cannot be an icon
	if ( noIcon ) {
		o.icon = "";
	}

	return {
		options: o,
		unknownClasses: unknownClasses,
		alreadyEnhanced: alreadyEnhanced
	};
}

// $.fn.buttonMarkup:
// DOM: gets/sets .className
//
// @options: options to apply to the elements in the jQuery object
// @overwriteClasses: boolean indicating whether to honour existing classes
//
// Calculates the classes to apply to the elements in the jQuery object based on
// the options passed in. If @overwriteClasses is true, it sets the className
// property of each element in the jQuery object to the buttonMarkup classes
// it calculates based on the options passed in.
//
// If you wish to preserve any classes that are already present on the elements
// inside the jQuery object, including buttonMarkup-related classes that were
// added by a previous call to $.fn.buttonMarkup() or during page enhancement
// then you should omit @overwriteClasses or set it to false.
$.fn.buttonMarkup = function( options, overwriteClasses ) {
	var idx, data, el;

	for ( idx = 0 ; idx < this.length ; idx++ ) {
		el = this[ idx ];
		data = overwriteClasses ?

			// Assume this element is not enhanced and ignore its classes
			{ alreadyEnhanced: false, unknownClasses: [] } :

			// Analyze existing classes to establish existing options and classes
			classNameToOptions( el.className );

		el.className = optionsToClassName(

			// Merge all the options and apply them as classes
			$.extend( {},

				// The defaults form the basis
				$.fn.buttonMarkup.defaults,

				// If the element already has the class ui-btn, then we assume that
				// it has passed through buttonMarkup before - otherwise, the options
				// returned by classNameToOptions do not correctly reflect the state of
				// the element
				( data.alreadyEnhanced ? data.options : {} ),

				// Finally, apply the options passed in
				options ),

			// ... and re-apply any unrecognized classes that were found
			data.unknownClasses );
	}

	return this;
};

// buttonMarkup defaults. This must be a complete set, i.e., a value must be
// given here for all recognized options
$.fn.buttonMarkup.defaults = {
	icon: "",
	iconpos: "right",
	theme: null,
	inline: false,
	shadow: true,
	corners: true,
	iconshadow: true,
	mini: false
};

// enhanceWithButtonMarkup:
// DOM: gets/sets .className
//
// this: Element to enhance
//
// Harvest an element's buttonMarkup-related data attributes from the DOM and
// use their value to override defaults. Use optionsToClassName() to establish a
// new className for the element from the calculated options and any existing
// classes.
//
// This function is only defined so that it can be called from the enhancer
// without having to write it inline and may be moved into the enhancer in the
// future.
function enhanceWithButtonMarkup( idx, el ) {
	var getAttrFixed = $.mobile.getAttribute;

	el.className = optionsToClassName( $.extend( {},
		$.fn.buttonMarkup.defaults, {
			icon      : getAttrFixed( el, "icon",       true ),
			iconpos   : getAttrFixed( el, "iconpos",    true ),
			theme     : getAttrFixed( el, "theme",      true ),
			inline    : getAttrFixed( el, "inline",     true ),
			shadow    : getAttrFixed( el, "shadow",     true ),
			corners   : getAttrFixed( el, "corners",    true ),
			iconshadow: getAttrFixed( el, "iconshadow", true ),
			mini      : getAttrFixed( el, "mini",       true )
		}), el.className.split( " " ) );
}

//links in bars, or those with data-role become buttons
//auto self-init widgets
$.mobile._enhancer.add( "mobile.buttonmarkup", undefined, function( target ) {
	$( "a:jqmData(role='button'), .ui-bar > a, .ui-bar > :jqmData(role='controlgroup') > a", target ).each( enhanceWithButtonMarkup );
});

})( jQuery );

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>buttonMarkup: Make classes unique during enhancement to avoid adding the same class twice.<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Applies button styling to links
//>>label: Buttons: Link-based
//>>group: Forms
//>>css.structure: ../css/structure/jquery.mobile.button.css
//>>css.theme: ../css/themes/default/jquery.mobile.theme.css

define( [ "jquery", "./jquery.mobile.core", "./jquery.mobile.registry" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");

(function( $, undefined ) {
"use strict";

// General policy: Do not access data-* attributes except during enhancement.
// In all other cases we determine the state of the button exclusively from its
// className. That's why optionsToClasses expects a full complement of options,
// and the jQuery plugin completes the set of options from the default values.

// Map classes to buttonMarkup boolean options - used in classNameToOptions()
var reverseBoolOptionMap = {
	"ui-shadow" : "shadow",
	"ui-corner-all" : "corners",
	"ui-btn-inline" : "inline",
	"ui-shadow-icon" : "iconshadow",
	"ui-mini" : "mini"
};

// optionsToClasses:
// @options: A complete set of options to convert to class names.
// @existingClasses: extra classes to add to the result
//
// Converts @options to buttonMarkup classes and returns the result as an array
// that can be converted to an element's className with .join( " " ). All
// possible options must be set inside @options. Use $.fn.buttonMarkup.defaults
// to get a complete set and use $.extend to override your choice of options
// from that set.
function optionsToClasses( options, existingClasses ) {
	var classes = existingClasses ? existingClasses : [];

	// Add classes to the array - first ui-btn
	classes.push( "ui-btn" );

	// If there is a theme
	if ( options.theme ) {
		classes.push( "ui-btn-" + options.theme );
	}

	// If there's an icon, add the icon-related classes
	if ( options.icon ) {
		classes = classes.concat([
			"ui-icon-" + options.icon,
			"ui-btn-icon-" + options.iconpos
		]);
		if ( options.iconshadow ) {
			classes.push( "ui-shadow-icon" );
		}
	}

	// Add the appropriate class for each boolean option
	if ( options.inline ) {
		classes.push( "ui-btn-inline" );
	}
	if ( options.shadow ) {
		classes.push( "ui-shadow" );
	}
	if ( options.corners ) {
		classes.push( "ui-corner-all" );
	}
	if ( options.mini ) {
		classes.push( "ui-mini" );
	}

	// Create a string from the array and return it
	return classes;
}

// classNameToOptions:
// @classes: A string containing a .className-style space-separated class list
//
// Loops over @classes and calculates an options object based on the
// buttonMarkup-related classes it finds. It records unrecognized classes in an
// array.
//
// Returns: An object containing the following items:
//
// "options": buttonMarkup options found to be present because of the
// presence/absence of corresponding classes
//
// "unknownClasses": a string containing all the non-buttonMarkup-related
// classes found in @classes
//
// "alreadyEnhanced": A boolean indicating whether the ui-btn class was among
// those found to be present
function classNameToOptions( classes ) {
	var idx, map, unknownClass,
		alreadyEnhanced = false,
		noIcon = true,
		o = {
			icon: "",
			inline: false,
			shadow: false,
			corners: false,
			iconshadow: false,
			mini: false
		},
		unknownClasses = [];

	classes = classes.split( " " );

	// Loop over the classes
	for ( idx = 0 ; idx < classes.length ; idx++ ) {

		// Assume it's an unrecognized class
		unknownClass = true;

		// Recognize boolean options from the presence of classes
		map = reverseBoolOptionMap[ classes[ idx ] ];
		if ( map !== undefined ) {
			unknownClass = false;
			o[ map ] = true;

		// Recognize the presence of an icon and establish the icon position
		} else if ( classes[ idx ].indexOf( "ui-btn-icon-" ) === 0 ) {
			unknownClass = false;
			noIcon = false;
			o.iconpos = classes[ idx ].substring( 12 );

		// Establish which icon is present
		} else if ( classes[ idx ].indexOf( "ui-icon-" ) === 0 ) {
			unknownClass = false;
			o.icon = classes[ idx ].substring( 8 );

		// Establish the theme - this recognizes one-letter theme swatch names
		} else if ( classes[ idx ].indexOf( "ui-btn-" ) === 0 && classes[ idx ].length === 8 ) {
			unknownClass = false;
			o.theme = classes[ idx ].substring( 7 );

		// Recognize that this element has already been buttonMarkup-enhanced
		} else if ( classes[ idx ] === "ui-btn" ) {
			unknownClass = false;
			alreadyEnhanced = true;
		}

		// If this class has not been recognized, add it to the list
		if ( unknownClass ) {
			unknownClasses.push( classes[ idx ] );
		}
	}

	// If a "ui-btn-icon-*" icon position class is absent there cannot be an icon
	if ( noIcon ) {
		o.icon = "";
	}

	return {
		options: o,
		unknownClasses: unknownClasses,
		alreadyEnhanced: alreadyEnhanced
	};
}

// $.fn.buttonMarkup:
// DOM: gets/sets .className
//
// @options: options to apply to the elements in the jQuery object
// @overwriteClasses: boolean indicating whether to honour existing classes
//
// Calculates the classes to apply to the elements in the jQuery object based on
// the options passed in. If @overwriteClasses is true, it sets the className
// property of each element in the jQuery object to the buttonMarkup classes
// it calculates based on the options passed in.
//
// If you wish to preserve any classes that are already present on the elements
// inside the jQuery object, including buttonMarkup-related classes that were
// added by a previous call to $.fn.buttonMarkup() or during page enhancement
// then you should omit @overwriteClasses or set it to false.
$.fn.buttonMarkup = function( options, overwriteClasses ) {
	var idx, data, el;

	for ( idx = 0 ; idx < this.length ; idx++ ) {
		el = this[ idx ];
		data = overwriteClasses ?

			// Assume this element is not enhanced and ignore its classes
			{ alreadyEnhanced: false, unknownClasses: [] } :

			// Analyze existing classes to establish existing options and classes
			classNameToOptions( el.className );

		el.className = optionsToClasses(

			// Merge all the options and apply them as classes
			$.extend( {},

				// The defaults form the basis
				$.fn.buttonMarkup.defaults,

				// If the element already has the class ui-btn, then we assume that
				// it has passed through buttonMarkup before - otherwise, the options
				// returned by classNameToOptions do not correctly reflect the state of
				// the element
				( data.alreadyEnhanced ? data.options : {} ),

				// Finally, apply the options passed in
				options ),

			// ... and re-apply any unrecognized classes that were found
			data.unknownClasses ).join( " " );
	}

	return this;
};

// buttonMarkup defaults. This must be a complete set, i.e., a value must be
// given here for all recognized options
$.fn.buttonMarkup.defaults = {
	icon: "",
	iconpos: "right",
	theme: null,
	inline: false,
	shadow: true,
	corners: true,
	iconshadow: true,
	mini: false
};

// enhanceWithButtonMarkup:
// DOM: gets/sets .className
//
// this: Element to enhance
//
// Harvest an element's buttonMarkup-related data attributes from the DOM and
// use their value to override defaults. Use optionsToClasses() to establish a
// new className for the element from the calculated options and any existing
// classes.
//
// This function is only defined so that it can be called from the enhancer
// without having to write it inline and may be moved into the enhancer in the
// future.
function enhanceWithButtonMarkup( idx, el ) {
	var classes,
		getAttrFixed = $.mobile.getAttribute;

	classes = optionsToClasses( $.extend( {},
		$.fn.buttonMarkup.defaults, {
			icon      : getAttrFixed( el, "icon",       true ),
			iconpos   : getAttrFixed( el, "iconpos",    true ),
			theme     : getAttrFixed( el, "theme",      true ),
			inline    : getAttrFixed( el, "inline",     true ),
			shadow    : getAttrFixed( el, "shadow",     true ),
			corners   : getAttrFixed( el, "corners",    true ),
			iconshadow: getAttrFixed( el, "iconshadow", true ),
			mini      : getAttrFixed( el, "mini",       true )
		}), el.className.split( " " ) ).sort();

	el.className = $.grep( classes, function( el, idx ) {
			return !( idx > 0 && classes[ idx - 1 ] === el );
		}).join( " " );
}

//links in bars, or those with data-role become buttons
//auto self-init widgets
$.mobile._enhancer.add( "mobile.buttonmarkup", undefined, function( target ) {
	$( "a:jqmData(role='button'), .ui-bar > a, .ui-bar > :jqmData(role='controlgroup') > a", target ).each( enhanceWithButtonMarkup );
});

})( jQuery );

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>


<commit_before>
define([
    'flight/lib/component',
    'tpl!./overlay',
    'util/formatters'
], function(defineComponent, template, formatters) {
    'use strict';

    var LAST_SAVED_UPDATE_FREQUENCY_SECONDS = 30;
    var MENUBAR_WIDTH = 30;

    return defineComponent(WorkspaceOverlay);

    function WorkspaceOverlay() {

        this.defaultAttrs({
            nameSelector: '.name',
            subtitleSelector: '.subtitle'
        });

        this.after('initialize', function() {
            this.$node.html(template({}));

            this.on(document, 'workspaceSaving', this.onWorkspaceSaving);
            this.on(document, 'workspaceSaved', this.onWorkspaceSaved);
            this.on(document, 'workspaceLoaded', this.onWorkspaceLoaded);
            this.on(document, 'graphPaddingUpdated', this.onGraphPaddingUpdated);
        });

        this.onGraphPaddingUpdated = function(event, data) {
            this.$node.css('left', data.padding.l + MENUBAR_WIDTH);
        };

        this.setContent = function(title, isEditable, subtitle) {
            this.select('nameSelector').text(title);
            this.select('subtitleSelector').html(isEditable === false ? 'read only' : subtitle);
        };

        this.onWorkspaceLoaded = function(event, data) {
            this.setContent(data.title, data.isEditable, 'no changes');
            clearTimeout(this.updateTimer);
        };

        this.onWorkspaceSaving = function(event, data) {
            this.select('subtitleSelector').text('saving...');
            clearTimeout(this.updateTimer);
        };

        this.onWorkspaceSaved = function(event, data) {
            clearTimeout(this.updateTimer);
            this.lastSaved = Date.now();

            if (data.title) {
                this.select('nameSelector').text(data.title);
            }

            var prefix = 'last saved ',
                subtitle = this.select('subtitleSelector').text(prefix + 'moments ago'),
                setTimer = function() {
                    this.updateTimer = setTimeout(function () {

                        var time = formatters.date.relativeToNow(this.lastSaved);
                        subtitle.text(prefix + time + ' ago');

                        setTimer();
                    }.bind(this), LAST_SAVED_UPDATE_FREQUENCY_SECONDS * 1000);
                }.bind(this);

            setTimer();
        };
    }
});
<commit_msg>Fix workspace date math<commit_after>
define([
    'flight/lib/component',
    'tpl!./overlay',
    'util/formatters'
], function(defineComponent, template, formatters) {
    'use strict';

    var LAST_SAVED_UPDATE_FREQUENCY_SECONDS = 30;
    var MENUBAR_WIDTH = 30;

    return defineComponent(WorkspaceOverlay);

    function WorkspaceOverlay() {

        this.defaultAttrs({
            nameSelector: '.name',
            subtitleSelector: '.subtitle'
        });

        this.after('initialize', function() {
            this.$node.html(template({}));

            this.on(document, 'workspaceSaving', this.onWorkspaceSaving);
            this.on(document, 'workspaceSaved', this.onWorkspaceSaved);
            this.on(document, 'workspaceLoaded', this.onWorkspaceLoaded);
            this.on(document, 'graphPaddingUpdated', this.onGraphPaddingUpdated);
        });

        this.onGraphPaddingUpdated = function(event, data) {
            this.$node.css('left', data.padding.l + MENUBAR_WIDTH);
        };

        this.setContent = function(title, isEditable, subtitle) {
            this.select('nameSelector').text(title);
            this.select('subtitleSelector').html(isEditable === false ? 'read only' : subtitle);
        };

        this.onWorkspaceLoaded = function(event, data) {
            this.setContent(data.title, data.isEditable, 'no changes');
            clearTimeout(this.updateTimer);
        };

        this.onWorkspaceSaving = function(event, data) {
            this.select('subtitleSelector').text('saving...');
            clearTimeout(this.updateTimer);
        };

        this.onWorkspaceSaved = function(event, data) {
            clearTimeout(this.updateTimer);
            this.lastSaved = formatters.date.utc(Date.now());

            if (data.title) {
                this.select('nameSelector').text(data.title);
            }

            var prefix = 'last saved ',
                subtitle = this.select('subtitleSelector').text(prefix + 'moments ago'),
                setTimer = function() {
                    this.updateTimer = setTimeout(function () {

                        var time = formatters.date.relativeToNow(this.lastSaved);
                        subtitle.text(prefix + time);

                        setTimer();
                    }.bind(this), LAST_SAVED_UPDATE_FREQUENCY_SECONDS * 1000);
                }.bind(this);

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


<commit_before>module.exports = [
  {
    type: 'item',
    isHeader: true,
    name: 'MAIN NAVIGATION'
  },
  {
    type: 'tree',
    icon: 'fa fa-dashboard',
    name: 'Objects',
    items: [
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Services',
        router: {
          name: 'ShowServices'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Dependencies',
        router: {
          name: 'ShowDependencies'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Rules',
        router: {
          name: 'ShowRules'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Clusters',
        router: {
          name: 'ShowClusters'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Audit Log',
        router: {
          name: 'ShowAuditLog'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'User Roles',
        router: {
          name: 'ShowUserRoles'
        }
      }
    ]
  },
  {
    type: 'tree',
    icon: 'fa fa-dashboard',
    name: 'Debug',
    items: [
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Objects',
        router: {
          name: 'ShowObjects'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Browser',
        router: {
          name: 'BrowsePolicy'
        }
      }
    ]
  },
  {
    type: 'Help',
    icon: 'fa fa-book',
    name: 'Help',
    items: [
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Web Site',
        router: {
          name: 'Website'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Documentation',
        router: {
          name: 'Documentation'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Slack',
        router: {
          name: 'Slack'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Github',
        router: {
          name: 'Github'
        }
      }
    ]
  }

]
<commit_msg>added "Deployment"<commit_after>module.exports = [
  {
    type: 'item',
    isHeader: true,
    name: 'MAIN NAVIGATION'
  },
  {
    type: 'tree',
    icon: 'fa fa-dashboard',
    name: 'Objects',
    items: [
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Services',
        router: {
          name: 'ShowServices'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Contracts',
        router: {
          name: 'ShowContracts'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Dependencies',
        router: {
          name: 'ShowDependencies'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Rules',
        router: {
          name: 'ShowRules'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Clusters',
        router: {
          name: 'ShowClusters'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Users',
        router: {
          name: 'ShowUserRoles'
        }
      }
    ]
  },
  {
    type: 'tree',
    icon: 'fa fa-dashboard',
    name: 'Deployment',
    items: [
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Audit Log',
        router: {
          name: 'ShowAuditLog'
        }
      }
    ]
  },

  {
    type: 'tree',
    icon: 'fa fa-dashboard',
    name: 'Debug',
    items: [
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Objects',
        router: {
          name: 'ShowObjects'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Browser',
        router: {
          name: 'BrowsePolicy'
        }
      }
    ]
  },
  {
    type: 'Help',
    icon: 'fa fa-book',
    name: 'Help',
    items: [
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Web Site',
        router: {
          name: 'Website'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Documentation',
        router: {
          name: 'Documentation'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Slack',
        router: {
          name: 'Slack'
        }
      },
      {
        type: 'item',
        icon: 'fa fa-circle-o',
        name: 'Github',
        router: {
          name: 'Github'
        }
      }
    ]
  }

]
<|endoftext|>


<commit_before>/*global alertOK, require, TestSuite, unescape, $, JSON*/

// some helpers
function exit() {
    window.open('', '_self', '');
    window.close();
}

function prepareConfig() {
    // For closing the browser
    Config.askBeforeQuit = false;
    // for network tests
    Config.serverInvokedTest = true;
}

function alertForever(msg) {
    alert(msg, 99999);
}

function getURLParam(name) {
    if (Global.testRun && testRun.hasOwnProperty(name)) {
        return testRun[name];
    }
    var queryRegex = new RegExp(name + '=([^\\&]+)'),
        match = document.URL.split('?').last().match(queryRegex),
        // FIXME OMeta overwrite unescape
        unescape = window._unescape || window.unescape;
    return match && unescape(match[1]);
}

// some preparation
var testRunId = getURLParam("testRunId");

if (!testRunId) {
    var msg = 'no id for test run, cannot execute tests';
    alertForever(msg);
    throw msg;
}

// result processing
function postResult(message) {
    alertOK("Result: \n" + message);
    $.post('/test-result/' + testRunId, {testRunId: testRunId, testResults: message});
}

// running the actual tests
var baseTests = [
    // core
    "lively.tests.BaseTests",
    "lively.tests.ClassTests",
    "lively.tests.ModuleSystemTests",
    "lively.tests.NetworkTests",
    "lively.tests.ObjectTests",
    "lively.tests.PartsTestFrameworkTests",
    "lively.tests.TestFrameworkTests",
    "lively.tests.TracingTests",
    "lively.tests.TraitTests",

    // AST / OMeta
    "ometa.tests.OmetaTests",
    "lively.ast.tests.AstTests",

    // persistence
    "lively.persistence.tests.BuildSpec",
    "lively.persistence.tests.PersistenceTests",
    "lively.persistence.tests.TraitPersistenceTests",

    //bindings
    "lively.bindings.tests.BindingTests"
];

var browserTests = [
    // core
    'lively.tests.BootstrapTests',
    'lively.tests.CoreTests',
    "lively.tests.HelperTests",

    // network
    'lively.net.tests.SessionTracker',

    // lang support
    "lively.lang.tests.ExtensionTests",
    "lively.lang.tests.WorkerTests",

    // persistence
    "lively.persistence.tests.MassMorphCreation",

    // presentation
    "lively.presentation.tests.Builds",

    //bindings
    "lively.bindings.tests.FRPCoreTests",
    "lively.bindings.tests.FRPSerialization",
    "lively.bindings.tests.GeometryBindingTests",

    // ide / SCB
    "lively.ide.tests.ASTEditingSupport",
    "lively.ide.tests.CodeEditor",
    "lively.ide.tests.FileParserTests",
    "lively.ide.tests.ModuleLookup",
    'lively.ide.tests.SCBTests',
    "lively.ide.tests.SyntaxHighlighting",
    "lively.ide.tests.WindowNavigation",
    'lively.ide.tools.tests.CommandLine',

    // morphic
    "lively.morphic.tests.Connectors",
    "lively.morphic.tests.CoreToolsTests",
    "lively.morphic.tests.DataGridTests",
    "lively.morphic.tests.DiffMerge",
    "lively.morphic.tests.EventTests",
    "lively.morphic.tests.Graphics",
    'lively.morphic.tests.HTML',
    'lively.morphic.tests.HTMLText',
    "lively.morphic.tests.Layout",
    "lively.morphic.tests.Lists",
    "lively.morphic.tests.Morphic",
    "lively.morphic.tests.Morphic2",
    "lively.morphic.tests.MorphAddons",
    "lively.morphic.tests.PathTests",
    'lively.morphic.tests.Serialization',
    "lively.morphic.tests.ShapeTests",
    "lively.morphic.tests.StyleSheets",
    "lively.morphic.tests.StyleSheetsHTML",
    "lively.morphic.tests.TabTests",
    "lively.morphic.tests.Text",
    "lively.morphic.tests.TextUndoTests",

    // cop
    "cop.tests.LayerTests",

    // apps
    "apps.tests.Handlebars"
];

var testList = baseTests;
if (!Global.testRun || !testRun.isNodeJS) {
    testList.pushAll(browserTests);
}

var additionalModules = getURLParam('additionalModules');
if (additionalModules) {
    var moduleNames = additionalModules.split(',');
    testList.pushAll(moduleNames);
}

// filter is something like "lively.morphic.*|.*Origin.*|test03"
var filter = getURLParam('testFilter'), suiteFilter;
if (filter) {
    var parts = filter.split('|'),
        modulePart = parts[0],
        moduleFilterRegexp = new RegExp(modulePart, "i");
    testList = testList.select(function(name) {
        return moduleFilterRegexp.test(name) });
    suiteFilter = parts.slice(1).join('|'); // last 2
}

prepareConfig();

require(['lively.TestFramework'].concat(testList)).toRun(function() {
    var suite = TestSuite.forAllAvailableTests(suiteFilter);
    suite.runFinished = function() {
        if (Global.testRun) {
            testRun.onTestResult(suite.result.asJSON());
        } else {
            var result = suite.result.asJSONString();
            postResult(result);
            if (!getURLParam('stayOpen')) { exit.delay(0.5); }
        }
    };
    suite.runAll();
});
<commit_msg>run_tests.js: lively.data.tests.ODFImport<commit_after>/*global alertOK, require, TestSuite, unescape, $, JSON*/

// some helpers
function exit() {
    window.open('', '_self', '');
    window.close();
}

function prepareConfig() {
    // For closing the browser
    Config.askBeforeQuit = false;
    // for network tests
    Config.serverInvokedTest = true;
}

function alertForever(msg) {
    alert(msg, 99999);
}

function getURLParam(name) {
    if (Global.testRun && testRun.hasOwnProperty(name)) {
        return testRun[name];
    }
    var queryRegex = new RegExp(name + '=([^\\&]+)'),
        match = document.URL.split('?').last().match(queryRegex),
        // FIXME OMeta overwrite unescape
        unescape = window._unescape || window.unescape;
    return match && unescape(match[1]);
}

// some preparation
var testRunId = getURLParam("testRunId");

if (!testRunId) {
    var msg = 'no id for test run, cannot execute tests';
    alertForever(msg);
    throw msg;
}

// result processing
function postResult(message) {
    alertOK("Result: \n" + message);
    $.post('/test-result/' + testRunId, {testRunId: testRunId, testResults: message});
}

// running the actual tests
var baseTests = [
    // core
    "lively.tests.BaseTests",
    "lively.tests.ClassTests",
    "lively.tests.ModuleSystemTests",
    "lively.tests.NetworkTests",
    "lively.tests.ObjectTests",
    "lively.tests.PartsTestFrameworkTests",
    "lively.tests.TestFrameworkTests",
    "lively.tests.TracingTests",
    "lively.tests.TraitTests",

    // AST / OMeta
    "ometa.tests.OmetaTests",
    "lively.ast.tests.AstTests",

    // persistence
    "lively.persistence.tests.BuildSpec",
    "lively.persistence.tests.PersistenceTests",
    "lively.persistence.tests.TraitPersistenceTests",

    //bindings
    "lively.bindings.tests.BindingTests"
];

var browserTests = [
    // core
    'lively.tests.BootstrapTests',
    'lively.tests.CoreTests',
    "lively.tests.HelperTests",

    // network
    'lively.net.tests.SessionTracker',

    // lang support
    "lively.lang.tests.ExtensionTests",
    "lively.lang.tests.WorkerTests",

    // persistence
    "lively.persistence.tests.MassMorphCreation",

    // presentation
    "lively.presentation.tests.Builds",

    // data import/export
    'lively.data.tests.ODFImport',

    //bindings
    "lively.bindings.tests.FRPCoreTests",
    "lively.bindings.tests.FRPSerialization",
    "lively.bindings.tests.GeometryBindingTests",

    // ide / SCB
    "lively.ide.tests.ASTEditingSupport",
    "lively.ide.tests.CodeEditor",
    "lively.ide.tests.FileParserTests",
    "lively.ide.tests.ModuleLookup",
    'lively.ide.tests.SCBTests',
    "lively.ide.tests.SyntaxHighlighting",
    "lively.ide.tests.WindowNavigation",
    'lively.ide.tools.tests.CommandLine',

    // morphic
    "lively.morphic.tests.Connectors",
    "lively.morphic.tests.CoreToolsTests",
    "lively.morphic.tests.DataGridTests",
    "lively.morphic.tests.DiffMerge",
    "lively.morphic.tests.EventTests",
    "lively.morphic.tests.Graphics",
    'lively.morphic.tests.HTML',
    'lively.morphic.tests.HTMLText',
    "lively.morphic.tests.Layout",
    "lively.morphic.tests.Lists",
    "lively.morphic.tests.Morphic",
    "lively.morphic.tests.Morphic2",
    "lively.morphic.tests.MorphAddons",
    "lively.morphic.tests.PathTests",
    'lively.morphic.tests.Serialization',
    "lively.morphic.tests.ShapeTests",
    "lively.morphic.tests.StyleSheets",
    "lively.morphic.tests.StyleSheetsHTML",
    "lively.morphic.tests.TabTests",
    "lively.morphic.tests.Text",
    "lively.morphic.tests.TextUndoTests",

    // cop
    "cop.tests.LayerTests",

    // apps
    "apps.tests.Handlebars"
];

var testList = baseTests;
if (!Global.testRun || !testRun.isNodeJS) {
    testList.pushAll(browserTests);
}

var additionalModules = getURLParam('additionalModules');
if (additionalModules) {
    var moduleNames = additionalModules.split(',');
    testList.pushAll(moduleNames);
}

// filter is something like "lively.morphic.*|.*Origin.*|test03"
var filter = getURLParam('testFilter'), suiteFilter;
if (filter) {
    var parts = filter.split('|'),
        modulePart = parts[0],
        moduleFilterRegexp = new RegExp(modulePart, "i");
    testList = testList.select(function(name) {
        return moduleFilterRegexp.test(name) });
    suiteFilter = parts.slice(1).join('|'); // last 2
}

prepareConfig();

require(['lively.TestFramework'].concat(testList)).toRun(function() {
    var suite = TestSuite.forAllAvailableTests(suiteFilter);
    suite.runFinished = function() {
        if (Global.testRun) {
            testRun.onTestResult(suite.result.asJSON());
        } else {
            var result = suite.result.asJSONString();
            postResult(result);
            if (!getURLParam('stayOpen')) { exit.delay(0.5); }
        }
    };
    suite.runAll();
});
<|endoftext|>


<commit_before>/*! Copyright (c) 2016, Salesforce.com, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *      Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 *      Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *      Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
'use strict';

var controlsModule = angular.module('argusControls',[]);

controlsModule.directive('agDashboardResource', ['DashboardService','$sce','$compile','$rootScope','$timeout', function(DashboardService,$sce,$compile,$rootScope,$timeout){
    return{
        restrict:'E',
        scope:false,
        link: function(scope,element,attribute){

            var dashboardID;
            if(attribute.id && attribute.id>0) {
               dashboardID = attribute.id;
            }else{
                dashboardID=scope.dashboardId;
            }

            DashboardService.getDashboardById(dashboardID).success(function (data){

                element.html('
' + $sce.trustAsHtml(data.content) + '
');
                $compile(element.contents())(scope);
                //scope.$broadcast('submitButtonEvent', {});

            });

        }
    }
}]);

controlsModule.directive('agDashboard', ['$rootScope',function($rootScope){

    return{
        restrict:'E',
        scope:{
            name:'@'
        },
        transclude:true,
        template:'

',
        controller: function($scope){
            $scope.controls = [];
            this.updateControl = function(controlName, controlValue, controlType){
            	var controlExists = false;
            	for(var i in $scope.controls) {
            		if($scope.controls[i].name === controlName) {
            			$scope.controls[i].value = controlValue;
            			controlExists = true;
            			break;
            		}
            	}

            	if(!controlExists) {
            		var control = {
                			name: controlName,
                			value: controlValue,
                			type: controlType
                	};
                	$scope.controls.push(control);
            	}
            };

            this.getAllControls = function(){
            	return $scope.controls;
            };
            this.getSubmitBtnEventName = function(){
                return 'submitButtonEvent';
            };

            this.broadcastEvent = function(eventName, data){
            	console.log(eventName + ' was broadcast');
            	$scope.$broadcast(eventName, data);
            }

        },
        link:function(scope,element,attributes){
            if(!attributes.onload || attributes.onload == true) {
                scope.$broadcast('submitButtonEvent', scope.controls);
            }

        }
    }
}]);

controlsModule.directive('agText', ['CONFIG',function(CONFIG){

    return{
        restrict:'EA',
        scope:{
            controlName:'@name',
            labelName:'@label',
            controlValue:'@default'
        },
        require:'^agDashboard',
        //templateUrl:  CONFIG.templatePath + 'argus-text-control.html',
        template:'{{labelName}} :  <input type="text" ng-model="controlValue">',
        link: function(scope,element,attributes,dashboardCtrl){
            dashboardCtrl.updateControl(scope.controlName, scope.controlValue, "agText");
            scope.$watch('controlValue', function(newValue, oldValue){
                dashboardCtrl.updateControl(scope.controlName, newValue, "agText");
            });
        }
    }
}]);

controlsModule.directive('agDropdown', ['CONFIG', 'Tags', function(CONFIG, Tags){
    return{
        restrict:'E',
        scope:{
            controlName: '@name',
            labelName: '@label',
            controlValue: '@default',
        },
        controller: function($scope) {
        	$scope.selectizeOptions = [];
            $scope.selectizeConfig = {
            		delimiter: '|',
            	    create: function(input) {
            	        return {
            	            value: input,
            	            text: input
            	        }
            	    }
            };
        },
        require:'^agDashboard',
        template:'{{labelName}} :
<selectize config="selectizeConfig" options="selectizeOptions" ng-model="controlValue">
',
        //template:'{{labelName}} :
<input type="text" ng-model="controlValue">
',
        link: function(scope, element, attributes, dashboardCtrl){
        	var key = attributes.key;
        	if(key) {
        		var promise = Tags.getDropdownOptions(key);
            	promise.success(function(data, status, headers, config) {
            		if(data && data[key]) {
            	    	var options;
            	    	for(var i in data) {
            	    		options = data[i];
            	    	}

            	    	var selectize = element.find('selectize')[0].selectize;

            	    	for(var i in options) {
            	    		var option = options[i];
            	    		selectize.addOption({
            	    			text: option,
            	    			value: option
            	    		});
            	    	}

            	    	selectize.refreshOptions(false);
            		} else {

            		}
            	}).error(function(data, status, headers, config) {
            		console.log("Error in retrieving tags");
                });
        	}
        	dashboardCtrl.updateControl(scope.controlName, scope.controlValue, "agDropdown");
            scope.$watch('controlValue', function(newValue, oldValue){
                dashboardCtrl.updateControl(scope.controlName, newValue, "agDropdown");
            });
        }
    }

}]);

controlsModule.directive('agDate', ['CONFIG',function(CONFIG){

    return{
        restrict:'E',
        scope:{
            controlName:'@name',
            labelName:'@label',
            controlValue:'@default'
        },
        controller: function($scope, $filter) {
        	$scope.datetimepickerConfig = {
        			dropdownSelector: '.my-toggle-select',
        			minuteStep: 1
        	};

        	$scope.onSetTime = function(newDate, oldDate) {
        		$scope.controlValue = $filter('date')(newDate, "short");
        	}
        },
        require:'^agDashboard',
        template:'{{labelName}} :
<input type="text" class="input-medium" style="color:black;" ng-model="controlValue">
 <datetimepicker ng-model="data.date" on-set-time="onSetTime(newDate, oldDate)" data-datetimepicker-config="datetimepickerConfig"></datetimepicker>

',
        link: function(scope, element, attributes, dashboardCtrl){
            dashboardCtrl.updateControl(scope.controlName, scope.controlValue, "agDate");
            scope.$watch('controlValue', function(newValue, oldValue){
                dashboardCtrl.updateControl(scope.controlName, newValue, "agDate");
            });
        }
    }
}]);

controlsModule.directive('agSubmit', ['$rootScope','$http',function($rootScope,$http){

    return{
        restrict:'E',
        require:'^agDashboard',
        template:'',
        link: function(scope,element,attributes,dashboardCtrl){

            var buttonName = 'Submit';
            if(element.text() && element.text().length>0){
                buttonName=element.text();
            }
            element.html('<button class="btn btn-primary btn-md">' +  buttonName + '</button>');

            element.on('click', function(){
                $http.pendingRequests=[]; //This line should be deleted.
                dashboardCtrl.broadcastEvent(dashboardCtrl.getSubmitBtnEventName(), dashboardCtrl.getAllControls());
                //console.log('Submit button event emitted.');
            });
        }
    }

}]);

//TODO delete the following

controlsModule.directive('agTrans', function(){
    return{
        restrict:'E',
        transclude:true,
        template:'

'
    }
})
<commit_msg>W-3217978 - parameterized dashboard link with url params. (#105)<commit_after>/*! Copyright (c) 2016, Salesforce.com, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
 *
 *      Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
 *
 *      Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 *
 *      Neither the name of Salesforce.com nor the names of its contributors may be used to endorse or promote products derived from this software
 *      without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
'use strict';

var controlsModule = angular.module('argusControls',[]);

controlsModule.directive('agDashboardResource', ['DashboardService','$sce','$compile','$rootScope','$timeout', function(DashboardService,$sce,$compile,$rootScope,$timeout){
    return{
        restrict:'E',
        scope:false,
        link: function(scope,element,attribute){

            var dashboardID;
            if(attribute.id && attribute.id>0) {
               dashboardID = attribute.id;
            }else{
                dashboardID=scope.dashboardId;
            }

            DashboardService.getDashboardById(dashboardID).success(function (data){

                element.html('
' + $sce.trustAsHtml(data.content) + '
');
                $compile(element.contents())(scope);
                //scope.$broadcast('submitButtonEvent', {});

            });

        }
    }
}]);

controlsModule.directive('agDashboard', ['$routeParams', function($routeParams) {

    return{
        restrict:'E',
        scope:{
            name:'@'
        },
        transclude:true,
        template:'

',
        controller: function($scope){
            $scope.controls = [];
            this.updateControl = function(controlName, controlValue, controlType){
            	var controlExists = false;

                // check $routeParams to override controlValue
                for (var prop in $routeParams) {
                    if (prop == controlName) {
                        controlValue = $routeParams[prop];
                    }
                };

            	for(var i in $scope.controls) {
            		if($scope.controls[i].name === controlName) {
            			$scope.controls[i].value = controlValue;
            			controlExists = true;
            			break;
            		}
            	}

            	if(!controlExists) {
            		var control = {
                			name: controlName,
                			value: controlValue,
                			type: controlType
                	};
                	$scope.controls.push(control);
            	}
            };

            this.getAllControls = function(){
            	return $scope.controls;
            };
            this.getSubmitBtnEventName = function(){
                return 'submitButtonEvent';
            };

            this.broadcastEvent = function(eventName, data){
            	console.log(eventName + ' was broadcast');
            	$scope.$broadcast(eventName, data);
            }

        },
        link:function(scope,element,attributes){
            if(!attributes.onload || attributes.onload == true) {
                scope.$broadcast('submitButtonEvent', scope.controls);
            }

        }
    }
}]);

controlsModule.directive('agText', ['$routeParams', 'CONFIG', function($routeParams, CONFIG) {
    return{
        restrict:'EA',
        scope:{
            controlName:'@name',
            labelName:'@label',
            controlValue:'@default'
        },
        controller: function($scope) {
            $scope.ctrlVal = $scope.controlValue;

            // check $routeParams to override controlValue
            for (var prop in $routeParams) {
                if (prop == $scope.controlName) {
                    $scope.ctrlVal = $routeParams[prop];
                }
            };
        },
        require:'^agDashboard',
        template:'{{labelName}} :  <input type="text" ng-model="ctrlVal">',
        link: function(scope, element, attributes, dashboardCtrl) {
            dashboardCtrl.updateControl(scope.controlName, scope.controlValue, "agText");
            scope.$watch('controlValue', function(newValue, oldValue){
                dashboardCtrl.updateControl(scope.controlName, newValue, "agText");
            });
        }
    }
}]);

controlsModule.directive('agDropdown', ['CONFIG', 'Tags', function(CONFIG, Tags){
    return{
        restrict:'E',
        scope:{
            controlName: '@name',
            labelName: '@label',
            controlValue: '@default',
        },
        controller: function($scope) {
        	$scope.selectizeOptions = [];
            $scope.selectizeConfig = {
            		delimiter: '|',
            	    create: function(input) {
            	        return {
            	            value: input,
            	            text: input
            	        }
            	    }
            };
        },
        require:'^agDashboard',
        template:'{{labelName}} :
<selectize config="selectizeConfig" options="selectizeOptions" ng-model="controlValue">
',
        //template:'{{labelName}} :
<input type="text" ng-model="controlValue">
',
        link: function(scope, element, attributes, dashboardCtrl){
        	var key = attributes.key;
        	if(key) {
        		var promise = Tags.getDropdownOptions(key);
            	promise.success(function(data, status, headers, config) {
            		if(data && data[key]) {
            	    	var options;
            	    	for(var i in data) {
            	    		options = data[i];
            	    	}

            	    	var selectize = element.find('selectize')[0].selectize;

            	    	for(var i in options) {
            	    		var option = options[i];
            	    		selectize.addOption({
            	    			text: option,
            	    			value: option
            	    		});
            	    	}

            	    	selectize.refreshOptions(false);
            		} else {

            		}
            	}).error(function(data, status, headers, config) {
            		console.log("Error in retrieving tags");
                });
        	}
        	dashboardCtrl.updateControl(scope.controlName, scope.controlValue, "agDropdown");
            scope.$watch('controlValue', function(newValue, oldValue){
                dashboardCtrl.updateControl(scope.controlName, newValue, "agDropdown");
            });
        }
    }

}]);

controlsModule.directive('agDate', ['$routeParams', 'CONFIG', function($routeParams, CONFIG) {

    return{
        restrict:'E',
        scope:{
            controlName:'@name',
            labelName:'@label',
            controlValue:'@default'
        },
        controller: function($scope, $filter) {
            $scope.ctrlVal = $scope.controlValue;

            // check $routeParams to override controlValue
            for (var prop in $routeParams) {
                if (prop == $scope.controlName) {
                    $scope.ctrlVal = $routeParams[prop];
                }
            };

        	$scope.datetimepickerConfig = {
        			dropdownSelector: '.my-toggle-select',
        			minuteStep: 1
        	};

        	$scope.onSetTime = function(newDate, oldDate) {
        		$scope.controlValue = $filter('date')(newDate, "short");
        	};
        },
        require:'^agDashboard',
        template:'{{labelName}} :
<input type="text" class="input-medium" style="color:black;" ng-model="ctrlVal">
 <datetimepicker ng-model="data.date" on-set-time="onSetTime(newDate, oldDate)" data-datetimepicker-config="datetimepickerConfig"></datetimepicker>

',
        link: function(scope, element, attributes, dashboardCtrl){
            dashboardCtrl.updateControl(scope.controlName, scope.controlValue, "agDate");
            scope.$watch('controlValue', function(newValue, oldValue){
                dashboardCtrl.updateControl(scope.controlName, newValue, "agDate");
            });
        }
    }
}]);

controlsModule.directive('agSubmit', ['$rootScope','$http',function($rootScope,$http){

    return{
        restrict:'E',
        require:'^agDashboard',
        template:'',
        link: function(scope,element,attributes,dashboardCtrl){

            var buttonName = 'Submit';
            if(element.text() && element.text().length>0){
                buttonName=element.text();
            }
            element.html('<button class="btn btn-primary btn-md">' +  buttonName + '</button>');

            element.on('click', function(){
                $http.pendingRequests=[]; //This line should be deleted.
                dashboardCtrl.broadcastEvent(dashboardCtrl.getSubmitBtnEventName(), dashboardCtrl.getAllControls());
                //console.log('Submit button event emitted.');
            });
        }
    }

}]);

//TODO delete the following

controlsModule.directive('agTrans', function(){
    return{
        restrict:'E',
        transclude:true,
        template:'

'
    }
})
<|endoftext|>


<commit_before>(function(root) {

  'use strict';

  var availity = root.availity;

  availity.ui.provider('avDropdownConfig', function() {
    var config = {
      closeOnResize: true,
      dropdownAutoWidth: true,
      minimumResultsForSearch: 5
    };

    this.set = function(options) {
      angular.extend(config, options);
    };

    this.$get = function() {
      return angular.copy(config);
    };
  });

  availity.ui.constant('AV_DROPDOWN', {
    OPTIONS: [
      'width',
      'minimumInputLength',
      'maximumInputLength',
      'minimumResultsForSearch',
      'maximumSelectionSize',
      'placeholderOption',
      'separator',
      'allowClear',
      'multiple',
      'closeOnSelect',
      'openOnEnter',
      'id',
      'matcher',
      'sortResults',
      'formatSelection',
      'formatResult',
      'formatResultCssClass',
      'formatNoMatches',
      'formatSearching',
      'formatAjaxError',
      'formatInputTooShort',
      'formatInputTooLong',
      'formatSelectionTooBig',
      'formatLoadMore',
      'createSearchChoice',
      'createSearchChoicePosition',
      'initSelection',
      'tokenizer',
      'tokenSeparators',
      'query',
      'ajax',
      'data',
      'tags',
      'containerCss',
      'containerCssClass',
      'dropdownCss',
      'dropdownCssClass',
      'dropdownAutoWidth',
      'adaptContainerCssClass',
      'adaptDropdownCssClass',
      'escapeMarkup',
      'selectOnBlur',
      'loadMorePadding',
      'nextSearchTerm',
      'idSubstitute'
    ]
  });

  availity.ui.controller('AvDropdownController', function($element, $attrs, AV_UI, AV_DROPDOWN, avDropdownConfig, $log, $scope, $timeout, $parse) {

    var self = this;
    this.options = {};
    this.match = null;
    this.ngModel = null;

    this.init = function() {

      self.options = angular.extend({}, avDropdownConfig);

      _.forEach($attrs, function(value, key) {
        if(_.contains(AV_DROPDOWN.OPTIONS, key.replace('data-', ''))) {
          self.options[key] = $scope.$eval(value);
        }
      });

      if(angular.isDefined($attrs.multiple) && $element.get(0).tagName.toLowerCase() !== 'select') {

        self.options.multiple = angular.isDefined($attrs.multiple);

      }

      self.multiple = angular.isDefined($attrs.multiple);

      if(self.options.query) {

        self.queryFn = self.options.query;
        // Function used to query results for the search term.
        self.options.query = self.query;
        // Function used to get the id from the choice object or a string representing the key under which the id is stored.
        self.options.id = self.getId;
      }

    };

    this.setNgModel = function(ngModel) {
      this.ngModel = ngModel;
    };

    this.getSelected = function(model) {

      if(self.options.query) {
        return 0;
      }

      var items = this.collection($scope);

      var index = _.findIndex(items, function(item) {
        return angular.equals(item, model);
      });

      return index;

    };

    // Result:
    //
    // {
    //   "code": "252Y00000X",
    //   "value": "AGENCIES,EARLY INTERVENTION PROVIDER AGENCY,NOT APPLICABLE|Agency",
    //   "id": "252Y00000X"
    // }
    this.getId = function(result) {
      return result.id;
    };

    // Wrapper around the query function for Select2.  When the promise resolves
    // the callback
    this.query = function(options) {

      self.queryFn(options).then(function(response) {

        // Callback function that should be called with the result object. The result object:
        //
        // result.results (object) - Array of result objects. The default renderers
        //    expect objects with id and text keys. The id property is required,
        //    even if custom renderers are used. The object may also contain a children
        //    key if hierarchical data is displayed. The object may also contain a disabled
        //    boolean property indicating whether this result can be selected.
        //
        // result.more (boolean) - true if more results are available for the current
        //    search term.
        //
        // results.context (object) - A user-defined object that should be made available
        //    as the context parameter to the query function on subsequent queries to load
        //    more result pages for the same search term. See the description of
        //    options.context parameter.
        options.callback({more: response.more, results: response.results});
      });
    };

    this.setValue = function() {

      var viewValue = self.ngModel.$viewValue;
      var selected = null;
      if(viewValue) {
        selected = this.getSelected(viewValue);
      }

      // var apply = scope.$evalAsync || $timeout;
      $timeout(function() {
        $element
          .select2('val',  (selected === null || selected === 'undefined') ? '' : selected); // null === '' for Select2
      });
    };

    this.getMultiSelected = function(viewValue) {

      var indices = [];

      if($element.get(0).tagName.toLowerCase() !== 'input') {
        var options = this.collection($scope);

        _.each(viewValue, function(savedObject) {
          var index = _.findIndex(options, function(value) {
            var temp = angular.copy(savedObject); // remove hashkeys for comparison
            return _.matches(temp)(value);
          });
          indices.push(index);
        });

      } else {

        var inputViewValues = this.ngModel.$modelValue;

        _.each(inputViewValues, function(savedObject) {

          if(!_.isUndefined(savedObject.id) ) {

            if(!_.isEmpty(savedObject[self.options.idSubstitute])) {

              savedObject.id = savedObject[self.options.idSubstitute];

            } else {
              throw new Error('dropdown list must have a id or a alternative value to use as a id');
            }

          }

          indices.push(savedObject.id);

        });
      }

      if(indices.length > 0) {
        viewValue = indices;
      }

      return viewValue;

    };

    this.setValues = function() {

      var viewValue = self.ngModel.$viewValue;

      if(!angular.isArray(viewValue)) {
        viewValue = [];
      }

      if(!_.isEmpty(viewValue) && _.isObject(viewValue[0])) {
        viewValue = this.getMultiSelected(viewValue);
      }

      $timeout(function() {
        $element
          .select2('val', viewValue);
      });
    };

    this.ngOptions = function() {

      this.match = $attrs.ngOptions.match(AV_UI.NG_OPTIONS);
      if(!this.match) {
        throw new Error('Invalid ngOptions for avDropdown');
      }
      // AV_UI.NG_OPTIONS regex will parse into arrays like below:
      //
      // 0: "state.name for state in states"
      // 1: "state.name"
      // 2: undefined
      // 3: undefined
      // 4: "state"
      // 5: undefined
      // 6: undefined
      // 7: "states"
      // 8: undefined
      //
      // 0: "state.id as state.name for state in states"
      // 1: "state.id"
      // 2: "state.name"
      // 3: undefined
      // 4: "state"
      // 5: undefined
      // 6: undefined
      // 7: "states"
      // 8: undefined
      //
      // 0: "state.name for state in states track by state.id"
      // 1: "state.name"
      // 2: undefined
      // 3: undefined
      // 4: "state"
      // 5: undefined
      // 6: undefined
      // 7: "states"
      // 8: "state.id"
      //
      // 0: "person.fullName as (person.lastName + ', ' + person.firstName) for person in feeScheduleModel.persons"
      // 1: "person.fullName"
      // 2: "(person.lastName + ', ' + person.firstName)"
      // 3: undefined
      // 4: "person"
      // 5: undefined
      // 6: undefined
      // 7: "feeScheduleModel.persons"
      // 8: undefined
      //
      this.displayFn = $parse(this.match[2] || this.match[1]); // this is the function to retrieve the text to show as
      this.collection = $parse(this.match[7]);
      this.valueName = this.match[4] || this.match[6];
      this.valueFn = $parse(this.match[2] ? this.match[1] : this.valueName);
      this.keyName = this.match[5];

      $scope.$watchCollection(this.collection, function(newVal, oldVal) {
        if(angular.equals(newVal, oldVal)) {
          return;
        }

        self.setValue();

      }, true);

    };
  });

  availity.ui.directive('avDropdown', function($timeout, $log, $window) {

    return {
      restrict: 'A',
      require: ['ngModel', 'avDropdown'],
      controller: 'AvDropdownController',
      link: function(scope, element, attrs, controllers) {
        var ngModel = controllers[0];
        var avDropdown = controllers[1];

        avDropdown.setNgModel(ngModel);
        avDropdown.init();

        if(attrs.ngOptions ) {
          avDropdown.ngOptions();
        }

        ngModel.$parsers.push(function(value) {
          var parent = element.prev();
          parent
            .toggleClass('ng-invalid', !ngModel.$valid)
            .toggleClass('ng-valid', ngModel.$valid)
            .toggleClass('ng-invalid-required', !ngModel.$valid)
            .toggleClass('ng-valid-required', ngModel.$valid)
            .toggleClass('ng-dirty', ngModel.$dirty)
            .toggleClass('ng-pristine', ngModel.$pristine);
          return value;
        });

        element.on('change', function(e) {

          // special case since the ajax handling doesn't bind to the model correctly
          // this has to do with select2 (v3.5.2) using a hidden field instead of a select for ajax
          if(avDropdown.options.query) {
            $timeout(function() {
              // look at moving this to the controller
              if(element.get(0).tagName.toLowerCase() === 'input' && attrs.multiple) {

                var index;

                if(!angular.isArray(ngModel.$viewValue) || !angular.isObject(ngModel.$viewValue)) {

                  ngModel.$setValue([]);

                }

                if(e.added) {

                  ngModel.$viewValue.push(e.added);

                } else {

                  index = _.findIndex(ngModel.$viewValue, function(value) {

                    return  _.matches(e.removed)(value);

                  });

                  ngModel.$viewValue.splice(index,1);
                }

                var currentValues = ngModel.$viewValue;

                ngModel.$setViewValue(currentValues);

              } else {

                ngModel.$setViewValue(e.added);

              }

            }, false, 0);
          }

          $log.info(e);

        });

        // fires ng-focus when select2-focus fires.
        element.on('select2-focus', function() {
          if(attrs.ngFocus) {
            scope.$eval(scope.$eval(attrs.ngFocus));
          }
        });

        // fires ng-blur when select2-blur occurs.
        element.on('select2-blur', function() {
          if(attrs.ngBlur) {
            scope.$eval(scope.$eval(attrs.ngBlur));
          }
        });

        // https://github.com/t0m/select2-bootstrap-css/issues/37#issuecomment-42714589
        element.on('select2-open', function () {
          // look for .has-success, .has-warning, .has-error
          // (really look for .has-* … which is good enough for the demo page, but obviously might interfere with other CSS-classes starting with "has-")
          if(element.parents('[class*="has-"]').length) {

            // get all CSS-classes from the element where we found "has-*" and collect them in an array
            var classNames = $(this).parents('[class*="has-"]')[0].className.split(/\s+/);

            // go through the class names, find "has-"
            for(var i = 0; i < classNames.length; ++i) {
              if(classNames[i].match('has-')) {
                $('#select2-drop').addClass(classNames[i]);
              }
            }
          }
        });

        var _$render = ngModel.$render;
        ngModel.$render = function() {
          _$render();

          if(avDropdown.multiple) {
            avDropdown.setValues();
          }else {
            avDropdown.setValue();
          }

        };

        var win = angular.element($window);

        win.bind('resize', function() {
          element.select2('close');
        });

        attrs.$observe('disabled', function (value) {
          element.select2('enable', !value);
        });

        attrs.$observe('readonly', function (value) {
          element.select2('readonly', !!value);
        });

        scope.$on('destroy', function() {
          element.select2('destroy');
        });

        $timeout(function() {
          element.select2(avDropdown.options);
        });
      }
    };
  });

})(window);
<commit_msg>fixed a bug in dropdown.js<commit_after>(function(root) {

  'use strict';

  var availity = root.availity;

  availity.ui.provider('avDropdownConfig', function() {
    var config = {
      closeOnResize: true,
      dropdownAutoWidth: true,
      minimumResultsForSearch: 5
    };

    this.set = function(options) {
      angular.extend(config, options);
    };

    this.$get = function() {
      return angular.copy(config);
    };
  });

  availity.ui.constant('AV_DROPDOWN', {
    OPTIONS: [
      'width',
      'minimumInputLength',
      'maximumInputLength',
      'minimumResultsForSearch',
      'maximumSelectionSize',
      'placeholderOption',
      'separator',
      'allowClear',
      'multiple',
      'closeOnSelect',
      'openOnEnter',
      'id',
      'matcher',
      'sortResults',
      'formatSelection',
      'formatResult',
      'formatResultCssClass',
      'formatNoMatches',
      'formatSearching',
      'formatAjaxError',
      'formatInputTooShort',
      'formatInputTooLong',
      'formatSelectionTooBig',
      'formatLoadMore',
      'createSearchChoice',
      'createSearchChoicePosition',
      'initSelection',
      'tokenizer',
      'tokenSeparators',
      'query',
      'ajax',
      'data',
      'tags',
      'containerCss',
      'containerCssClass',
      'dropdownCss',
      'dropdownCssClass',
      'dropdownAutoWidth',
      'adaptContainerCssClass',
      'adaptDropdownCssClass',
      'escapeMarkup',
      'selectOnBlur',
      'loadMorePadding',
      'nextSearchTerm',
      'idSubstitute'
    ]
  });

  availity.ui.controller('AvDropdownController', function($element, $attrs, AV_UI, AV_DROPDOWN, avDropdownConfig, $log, $scope, $timeout, $parse) {

    var self = this;
    this.options = {};
    this.match = null;
    this.ngModel = null;

    this.init = function() {

      self.options = angular.extend({}, avDropdownConfig);

      _.forEach($attrs, function(value, key) {
        if(_.contains(AV_DROPDOWN.OPTIONS, key.replace('data-', ''))) {
          self.options[key] = $scope.$eval(value);
        }
      });

      if(angular.isDefined($attrs.multiple) && $element.get(0).tagName.toLowerCase() !== 'select') {

        self.options.multiple = angular.isDefined($attrs.multiple);

      }

      self.multiple = angular.isDefined($attrs.multiple);

      if(self.options.query) {

        self.queryFn = self.options.query;
        // Function used to query results for the search term.
        self.options.query = self.query;
        // Function used to get the id from the choice object or a string representing the key under which the id is stored.
        self.options.id = self.getId;
      }

    };

    this.setNgModel = function(ngModel) {
      this.ngModel = ngModel;
    };

    this.getSelected = function(model) {

      if(self.options.query) {
        return 0;
      }

      var items = this.collection($scope);

      var index = _.findIndex(items, function(item) {
        return angular.equals(item, model);
      });

      return index;

    };

    // Result:
    //
    // {
    //   "code": "252Y00000X",
    //   "value": "AGENCIES,EARLY INTERVENTION PROVIDER AGENCY,NOT APPLICABLE|Agency",
    //   "id": "252Y00000X"
    // }
    this.getId = function(result) {
      return result.id;
    };

    // Wrapper around the query function for Select2.  When the promise resolves
    // the callback
    this.query = function(options) {

      self.queryFn(options).then(function(response) {

        // Callback function that should be called with the result object. The result object:
        //
        // result.results (object) - Array of result objects. The default renderers
        //    expect objects with id and text keys. The id property is required,
        //    even if custom renderers are used. The object may also contain a children
        //    key if hierarchical data is displayed. The object may also contain a disabled
        //    boolean property indicating whether this result can be selected.
        //
        // result.more (boolean) - true if more results are available for the current
        //    search term.
        //
        // results.context (object) - A user-defined object that should be made available
        //    as the context parameter to the query function on subsequent queries to load
        //    more result pages for the same search term. See the description of
        //    options.context parameter.
        options.callback({more: response.more, results: response.results});
      });
    };

    this.setValue = function() {

      var viewValue = self.ngModel.$viewValue;
      var selected = null;
      if(viewValue) {
        selected = this.getSelected(viewValue);
      }

      // var apply = scope.$evalAsync || $timeout;
      $timeout(function() {
        $element
          .select2('val',  (selected === null || selected === 'undefined') ? '' : selected); // null === '' for Select2
      });
    };

    this.getMultiSelected = function(viewValue) {

      var indices = [];

      if($element.get(0).tagName.toLowerCase() !== 'input') {
        var options = this.collection($scope);

        _.each(viewValue, function(savedObject) {
          var index = _.findIndex(options, function(value) {
            var temp = angular.copy(savedObject); // remove hashkeys for comparison
            return _.matches(temp)(value);
          });
          indices.push(index);
        });

      } else {

        var inputViewValues = this.ngModel.$modelValue;

        _.each(inputViewValues, function(savedObject) {

          if(_.isUndefined(savedObject.id) ) {

            if(!_.isEmpty(savedObject[self.options.idSubstitute])) {

              savedObject.id = savedObject[self.options.idSubstitute];

            } else {
              throw new Error('dropdown list must have a id or a alternative value to use as a id');
            }

          }

          indices.push(savedObject.id);

        });
      }

      if(indices.length > 0) {
        viewValue = indices;
      }

      return viewValue;

    };

    this.setValues = function() {

      var viewValue = self.ngModel.$viewValue;

      if(!angular.isArray(viewValue)) {
        viewValue = [];
      }

      if(!_.isEmpty(viewValue) && _.isObject(viewValue[0])) {
        viewValue = this.getMultiSelected(viewValue);
      }

      $timeout(function() {
        $element
          .select2('val', viewValue);
      });
    };

    this.ngOptions = function() {

      this.match = $attrs.ngOptions.match(AV_UI.NG_OPTIONS);
      if(!this.match) {
        throw new Error('Invalid ngOptions for avDropdown');
      }
      // AV_UI.NG_OPTIONS regex will parse into arrays like below:
      //
      // 0: "state.name for state in states"
      // 1: "state.name"
      // 2: undefined
      // 3: undefined
      // 4: "state"
      // 5: undefined
      // 6: undefined
      // 7: "states"
      // 8: undefined
      //
      // 0: "state.id as state.name for state in states"
      // 1: "state.id"
      // 2: "state.name"
      // 3: undefined
      // 4: "state"
      // 5: undefined
      // 6: undefined
      // 7: "states"
      // 8: undefined
      //
      // 0: "state.name for state in states track by state.id"
      // 1: "state.name"
      // 2: undefined
      // 3: undefined
      // 4: "state"
      // 5: undefined
      // 6: undefined
      // 7: "states"
      // 8: "state.id"
      //
      // 0: "person.fullName as (person.lastName + ', ' + person.firstName) for person in feeScheduleModel.persons"
      // 1: "person.fullName"
      // 2: "(person.lastName + ', ' + person.firstName)"
      // 3: undefined
      // 4: "person"
      // 5: undefined
      // 6: undefined
      // 7: "feeScheduleModel.persons"
      // 8: undefined
      //
      this.displayFn = $parse(this.match[2] || this.match[1]); // this is the function to retrieve the text to show as
      this.collection = $parse(this.match[7]);
      this.valueName = this.match[4] || this.match[6];
      this.valueFn = $parse(this.match[2] ? this.match[1] : this.valueName);
      this.keyName = this.match[5];

      $scope.$watchCollection(this.collection, function(newVal, oldVal) {
        if(angular.equals(newVal, oldVal)) {
          return;
        }

        self.setValue();

      }, true);

    };
  });

  availity.ui.directive('avDropdown', function($timeout, $log, $window) {

    return {
      restrict: 'A',
      require: ['ngModel', 'avDropdown'],
      controller: 'AvDropdownController',
      link: function(scope, element, attrs, controllers) {
        var ngModel = controllers[0];
        var avDropdown = controllers[1];

        avDropdown.setNgModel(ngModel);
        avDropdown.init();

        if(attrs.ngOptions ) {
          avDropdown.ngOptions();
        }

        ngModel.$parsers.push(function(value) {
          var parent = element.prev();
          parent
            .toggleClass('ng-invalid', !ngModel.$valid)
            .toggleClass('ng-valid', ngModel.$valid)
            .toggleClass('ng-invalid-required', !ngModel.$valid)
            .toggleClass('ng-valid-required', ngModel.$valid)
            .toggleClass('ng-dirty', ngModel.$dirty)
            .toggleClass('ng-pristine', ngModel.$pristine);
          return value;
        });

        element.on('change', function(e) {

          // special case since the ajax handling doesn't bind to the model correctly
          // this has to do with select2 (v3.5.2) using a hidden field instead of a select for ajax
          if(avDropdown.options.query) {
            $timeout(function() {
              // look at moving this to the controller
              if(element.get(0).tagName.toLowerCase() === 'input' && attrs.multiple) {

                var index;

                if(!angular.isArray(ngModel.$viewValue) || !angular.isObject(ngModel.$viewValue)) {

                  ngModel.$setValue([]);

                }

                if(e.added) {

                  ngModel.$viewValue.push(e.added);

                } else {

                  index = _.findIndex(ngModel.$viewValue, function(value) {

                    return  _.matches(e.removed)(value);

                  });

                  ngModel.$viewValue.splice(index,1);
                }

                var currentValues = ngModel.$viewValue;

                ngModel.$setViewValue(currentValues);

              } else {

                ngModel.$setViewValue(e.added);

              }

            }, false, 0);
          }

          $log.info(e);

        });

        // fires ng-focus when select2-focus fires.
        element.on('select2-focus', function() {
          if(attrs.ngFocus) {
            scope.$eval(scope.$eval(attrs.ngFocus));
          }
        });

        // fires ng-blur when select2-blur occurs.
        element.on('select2-blur', function() {
          if(attrs.ngBlur) {
            scope.$eval(scope.$eval(attrs.ngBlur));
          }
        });

        // https://github.com/t0m/select2-bootstrap-css/issues/37#issuecomment-42714589
        element.on('select2-open', function () {
          // look for .has-success, .has-warning, .has-error
          // (really look for .has-* … which is good enough for the demo page, but obviously might interfere with other CSS-classes starting with "has-")
          if(element.parents('[class*="has-"]').length) {

            // get all CSS-classes from the element where we found "has-*" and collect them in an array
            var classNames = $(this).parents('[class*="has-"]')[0].className.split(/\s+/);

            // go through the class names, find "has-"
            for(var i = 0; i < classNames.length; ++i) {
              if(classNames[i].match('has-')) {
                $('#select2-drop').addClass(classNames[i]);
              }
            }
          }
        });

        var _$render = ngModel.$render;
        ngModel.$render = function() {
          _$render();

          if(avDropdown.multiple) {
            avDropdown.setValues();
          }else {
            avDropdown.setValue();
          }

        };

        var win = angular.element($window);

        win.bind('resize', function() {
          element.select2('close');
        });

        attrs.$observe('disabled', function (value) {
          element.select2('enable', !value);
        });

        attrs.$observe('readonly', function (value) {
          element.select2('readonly', !!value);
        });

        scope.$on('destroy', function() {
          element.select2('destroy');
        });

        $timeout(function() {
          element.select2(avDropdown.options);
        });
      }
    };
  });

})(window);
<|endoftext|>


<commit_before>describe("About Mutability", function() {

  it("should expect object properties to be public and mutable", function () {
    var aPerson = {firstname: "John", lastname: "Smith" };
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe(FILL_ME_IN);
  });

  it("should understand that constructed properties are public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    var aPerson = new Person ("John", "Smith");
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe(FILL_ME_IN);
  });

  it("should expect prototype properties to be public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    Person.prototype.getFullName = function () {
      return this.firstname + " " + this.lastname;
    };

    var aPerson = new Person ("John", "Smith");
    expect(aPerson.getFullName()).toBe(FILL_ME_IN);

    aPerson.getFullName = function () {
      return this.lastname + ", " + this.firstname;
    };

    expect(aPerson.getFullName()).toBe(FILL_ME_IN);
  });

  it("should know that variables inside a constructor and constructor args are private", function () {
    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;

      this.getFirstName = function () { return firstname; };
      this.getLastName = function () { return lastname; };
      this.getFullName = function () { return fullName; };
    }
    var aPerson = new Person ("John", "Smith");

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe(FILL_ME_IN);
    expect(aPerson.getLastName()).toBe(FILL_ME_IN);
    expect(aPerson.getFullName()).toBe(FILL_ME_IN);

    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe(FILL_ME_IN);
  });

});
<commit_msg>answered 1st of mutability<commit_after>describe("About Mutability", function() {

  it("should expect object properties to be public and mutable", function () {
    var aPerson = {firstname: "John", lastname: "Smith" };
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe("Alan");
  });

  it("should understand that constructed properties are public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    var aPerson = new Person ("John", "Smith");
    aPerson.firstname = "Alan";

    expect(aPerson.firstname).toBe(FILL_ME_IN);
  });

  it("should expect prototype properties to be public and mutable", function () {
    function Person(firstname, lastname)
    {
      this.firstname = firstname;
      this.lastname = lastname;
    }
    Person.prototype.getFullName = function () {
      return this.firstname + " " + this.lastname;
    };

    var aPerson = new Person ("John", "Smith");
    expect(aPerson.getFullName()).toBe(FILL_ME_IN);

    aPerson.getFullName = function () {
      return this.lastname + ", " + this.firstname;
    };

    expect(aPerson.getFullName()).toBe(FILL_ME_IN);
  });

  it("should know that variables inside a constructor and constructor args are private", function () {
    function Person(firstname, lastname)
    {
      var fullName = firstname + " " + lastname;

      this.getFirstName = function () { return firstname; };
      this.getLastName = function () { return lastname; };
      this.getFullName = function () { return fullName; };
    }
    var aPerson = new Person ("John", "Smith");

    aPerson.firstname = "Penny";
    aPerson.lastname = "Andrews";
    aPerson.fullName = "Penny Andrews";

    expect(aPerson.getFirstName()).toBe(FILL_ME_IN);
    expect(aPerson.getLastName()).toBe(FILL_ME_IN);
    expect(aPerson.getFullName()).toBe(FILL_ME_IN);

    aPerson.getFullName = function () {
      return aPerson.lastname + ", " + aPerson.firstname;
    };

    expect(aPerson.getFullName()).toBe(FILL_ME_IN);
  });

});
<|endoftext|>


<commit_before>/*
* "buttons" plugin - for making button-like links
*/

( function( $, undefined ) {

$.fn.buttonMarkup = function( options ) {
	options = options || {};
	for ( var i = 0; i < this.length; i++ ) {
		var el = this.eq( i ),
			e = el[ 0 ],
			o = $.extend( {}, $.fn.buttonMarkup.defaults, {
				icon:       options.icon       !== undefined ? options.icon       : el.jqmData( "icon" ),
				iconpos:    options.iconpos    !== undefined ? options.iconpos    : el.jqmData( "iconpos" ),
				theme:      options.theme      !== undefined ? options.theme      : el.jqmData( "theme" ),
				inline:     options.inline     !== undefined ? options.inline     : el.jqmData( "inline" ),
				shadow:     options.shadow     !== undefined ? options.shadow     : el.jqmData( "shadow" ),
				corners:    options.corners    !== undefined ? options.corners    : el.jqmData( "corners" ),
				iconshadow: options.iconshadow !== undefined ? options.iconshadow : el.jqmData( "iconshadow" )
			}, options ),

			// Classes Defined
			innerClass = "ui-btn-inner",
			textClass = "ui-btn-text",
			buttonClass, iconClass,

			// Button inner markup
			buttonInner = document.createElement( o.wrapperEls ),
			buttonText = document.createElement( o.wrapperEls ),
			buttonIcon = o.icon ? document.createElement( "span" ) : null;

		if ( attachEvents ) {
			attachEvents();
		}

		// if not, try to find closest theme container
		if ( !o.theme ) {
			o.theme = $.mobile.getInheritedTheme( el, "c" );
		}

		buttonClass = "ui-btn ui-btn-up-" + o.theme;

		if ( o.inline ) {
			buttonClass += " ui-btn-inline";
		}

		if ( o.icon ) {
			o.icon = "ui-icon-" + o.icon;
			o.iconpos = o.iconpos || "left";

			iconClass = "ui-icon " + o.icon;

			if ( o.iconshadow ) {
				iconClass += " ui-icon-shadow";
			}
		}

		if ( o.iconpos ) {
			buttonClass += " ui-btn-icon-" + o.iconpos;

			if ( o.iconpos == "notext" && !el.attr( "title" ) ) {
				el.attr( "title", el.getEncodedText() );
			}
		}

		if ( o.corners ) {
			buttonClass += " ui-btn-corner-all";
			innerClass += " ui-btn-corner-all";
		}

		if ( o.shadow ) {
			buttonClass += " ui-shadow";
		}

		e.setAttribute( "data-" + $.mobile.ns + "theme", o.theme );
		el.addClass( buttonClass );

		buttonInner.className = innerClass;

		buttonText.className = textClass;
		buttonInner.appendChild( buttonText );

		if ( buttonIcon ) {
			buttonIcon.className = iconClass;
			buttonInner.appendChild( buttonIcon );
		}

		while ( e.firstChild ) {
			buttonText.appendChild( e.firstChild );
		}

		e.appendChild( buttonInner );

		// TODO obviously it would be nice to pull this element out instead of
		// retrieving it from the DOM again, but this change is much less obtrusive
		// and 1.0 draws nigh
		$.data( e, 'textWrapper', $( buttonText ) );
	}

	return this;
};

$.fn.buttonMarkup.defaults = {
	corners: true,
	shadow: true,
	iconshadow: true,
	inline: false,
	wrapperEls: "span"
};

function closestEnabledButton( element ) {
    var cname;

    while ( element ) {
		// Note that we check for typeof className below because the element we
		// handed could be in an SVG DOM where className on SVG elements is defined to
		// be of a different type (SVGAnimatedString). We only operate on HTML DOM
		// elements, so we look for plain "string".
        cname = ( typeof element.className === 'string' ) && (element.className + ' ');
        if ( cname && cname.indexOf("ui-btn ") > -1 && cname.indexOf("ui-disabled ") < 0 ) {
            break;
        }

        element = element.parentNode;
    }

    return element;
}

var attachEvents = function() {
	var hoverDelay = 200,
		hov, foc;
	$( document ).bind( {
		"vmousedown": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;

			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
				hov = setTimeout(function() {
					$btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
				}, hoverDelay );
			}
		},
		"vmousecancel vmouseup": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;

			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
				$btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
			}
		},
		"vmouseover focus": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;

			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
				foc = setTimeout(function() {
					$btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
				}, hoverDelay );
			}
		},
		"vmouseout blur scrollstart": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;
			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
				$btn.removeClass( "ui-btn-hover-" + theme  + " ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );

				hov && clearTimeout( hov );
				foc && clearTimeout( foc );
			}
		}
	});

	attachEvents = null;
};

//links in bars, or those with  data-role become buttons
//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ){

	$( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
		.not( ".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
		.buttonMarkup();
});

})( jQuery );
<commit_msg>Ensured the hover delay only applies to touch devices, logic that was mysteriously absent from my previous commit.<commit_after>/*
* "buttons" plugin - for making button-like links
*/

( function( $, undefined ) {

$.fn.buttonMarkup = function( options ) {
	options = options || {};
	for ( var i = 0; i < this.length; i++ ) {
		var el = this.eq( i ),
			e = el[ 0 ],
			o = $.extend( {}, $.fn.buttonMarkup.defaults, {
				icon:       options.icon       !== undefined ? options.icon       : el.jqmData( "icon" ),
				iconpos:    options.iconpos    !== undefined ? options.iconpos    : el.jqmData( "iconpos" ),
				theme:      options.theme      !== undefined ? options.theme      : el.jqmData( "theme" ),
				inline:     options.inline     !== undefined ? options.inline     : el.jqmData( "inline" ),
				shadow:     options.shadow     !== undefined ? options.shadow     : el.jqmData( "shadow" ),
				corners:    options.corners    !== undefined ? options.corners    : el.jqmData( "corners" ),
				iconshadow: options.iconshadow !== undefined ? options.iconshadow : el.jqmData( "iconshadow" )
			}, options ),

			// Classes Defined
			innerClass = "ui-btn-inner",
			textClass = "ui-btn-text",
			buttonClass, iconClass,

			// Button inner markup
			buttonInner = document.createElement( o.wrapperEls ),
			buttonText = document.createElement( o.wrapperEls ),
			buttonIcon = o.icon ? document.createElement( "span" ) : null;

		if ( attachEvents ) {
			attachEvents();
		}

		// if not, try to find closest theme container
		if ( !o.theme ) {
			o.theme = $.mobile.getInheritedTheme( el, "c" );
		}

		buttonClass = "ui-btn ui-btn-up-" + o.theme;

		if ( o.inline ) {
			buttonClass += " ui-btn-inline";
		}

		if ( o.icon ) {
			o.icon = "ui-icon-" + o.icon;
			o.iconpos = o.iconpos || "left";

			iconClass = "ui-icon " + o.icon;

			if ( o.iconshadow ) {
				iconClass += " ui-icon-shadow";
			}
		}

		if ( o.iconpos ) {
			buttonClass += " ui-btn-icon-" + o.iconpos;

			if ( o.iconpos == "notext" && !el.attr( "title" ) ) {
				el.attr( "title", el.getEncodedText() );
			}
		}

		if ( o.corners ) {
			buttonClass += " ui-btn-corner-all";
			innerClass += " ui-btn-corner-all";
		}

		if ( o.shadow ) {
			buttonClass += " ui-shadow";
		}

		e.setAttribute( "data-" + $.mobile.ns + "theme", o.theme );
		el.addClass( buttonClass );

		buttonInner.className = innerClass;

		buttonText.className = textClass;
		buttonInner.appendChild( buttonText );

		if ( buttonIcon ) {
			buttonIcon.className = iconClass;
			buttonInner.appendChild( buttonIcon );
		}

		while ( e.firstChild ) {
			buttonText.appendChild( e.firstChild );
		}

		e.appendChild( buttonInner );

		// TODO obviously it would be nice to pull this element out instead of
		// retrieving it from the DOM again, but this change is much less obtrusive
		// and 1.0 draws nigh
		$.data( e, 'textWrapper', $( buttonText ) );
	}

	return this;
};

$.fn.buttonMarkup.defaults = {
	corners: true,
	shadow: true,
	iconshadow: true,
	inline: false,
	wrapperEls: "span"
};

function closestEnabledButton( element ) {
    var cname;

    while ( element ) {
		// Note that we check for typeof className below because the element we
		// handed could be in an SVG DOM where className on SVG elements is defined to
		// be of a different type (SVGAnimatedString). We only operate on HTML DOM
		// elements, so we look for plain "string".
        cname = ( typeof element.className === 'string' ) && (element.className + ' ');
        if ( cname && cname.indexOf("ui-btn ") > -1 && cname.indexOf("ui-disabled ") < 0 ) {
            break;
        }

        element = element.parentNode;
    }

    return element;
}

var attachEvents = function() {
	var hoverDelay = 200,
		hov, foc;
	$( document ).bind( {
		"vmousedown": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;

			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );

				if( $.support.touch ) {
					hov = setTimeout(function() {
						$btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
					}, hoverDelay );
				} else {
					$btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-down-" + theme );
				}
			}
		},
		"vmousecancel vmouseup": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;

			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
				$btn.removeClass( "ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );
			}
		},
		"vmouseover focus": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;

			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );

				if( $.support.touch ) {
					foc = setTimeout(function() {
						$btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
					}, hoverDelay );
				} else {
					$btn.removeClass( "ui-btn-up-" + theme ).addClass( "ui-btn-hover-" + theme );
				}
			}
		},
		"vmouseout blur scrollstart": function( event ) {
			var btn = closestEnabledButton( event.target ),
				$btn, theme;

			if ( btn ) {
				$btn = $( btn );
				theme = $btn.attr( "data-" + $.mobile.ns + "theme" );
				$btn.removeClass( "ui-btn-hover-" + theme  + " ui-btn-down-" + theme ).addClass( "ui-btn-up-" + theme );

				hov && clearTimeout( hov );
				foc && clearTimeout( foc );
			}
		}
	});

	attachEvents = null;
};

//links in bars, or those with  data-role become buttons
//auto self-init widgets
$( document ).bind( "pagecreate create", function( e ){

	$( ":jqmData(role='button'), .ui-bar > a, .ui-header > a, .ui-footer > a, .ui-bar > :jqmData(role='controlgroup') > a", e.target )
		.not( ".ui-btn, :jqmData(role='none'), :jqmData(role='nojs')" )
		.buttonMarkup();
});

})( jQuery );
<|endoftext|>