<commit_before>'use strict';

delete require.cache[require.resolve('..')];
var SuccinctRenderer = require('..');
var createRendererTester = require('../../../test_helper/create-renderer-tester');
var test = createRendererTester(SuccinctRenderer);
var assert = require('../../../test_helper/empowered-assert');

describe('SuccinctRenderer', function () {

    test('Identifier', function (transpiledCode) {
        var truthy = false;
        eval(transpiledCode);
    }, [
        'assert(truthy)',
        '       |      ',
        '       false  ',
    ]);

    test('MemberExpression', function (transpiledCode) {
        var en = { foo: false };
        eval(transpiledCode);
    }, [
        'assert(en.foo)',
        '          |   ',
        '          false',
    ]);

    test('deep MemberExpression', function (transpiledCode) {
        var en = { foo: { bar: false } };
        eval(transpiledCode);
    }, [
        'assert(en.foo.bar)',
        '              |   ',
        '              false',
    ]);

    test('CallExpression', function (transpiledCode) {
        var name = 'bar';
        var foo = function (n) { return false; };
        eval(transpiledCode);
    }, [
        'assert(foo(name))',
        '       |   |     ',
        '       |   "bar" ',
        '       false     ',
    ]);

    test('BinaryExpression', function (transpiledCode) {
        var foo = 'foo';
        var bar = 'bar';
        eval(transpiledCode);
    }, [
        'assert(foo === bar)',
        '       |       |   ',
        '       "foo"   "bar"',
    ]);

    test('StringLiteral', function (transpiledCode) {
        var foo = 'foo';
        eval(transpiledCode);
    }, [
        'assert(foo === "bar")',
        '       |             ',
        '       "foo"         '
    ]);

});
<commit_msg>test(power-assert-renderer-succinct): migrate tests from power-assert-renderers<commit_after>'use strict';

delete require.cache[require.resolve('..')];
var SuccinctRenderer = require('..');
var createRendererTester = require('../../../test_helper/create-renderer-tester');
var test = createRendererTester(SuccinctRenderer);
var assert = require('../../../test_helper/empowered-assert');

describe('SuccinctRenderer', function () {

    test('Identifier', function (transpiledCode) {
        var truthy = false;
        eval(transpiledCode);
    }, [
        'assert(truthy)',
        '       |      ',
        '       false  ',
    ]);

    test('MemberExpression', function (transpiledCode) {
        var en = { foo: false };
        eval(transpiledCode);
    }, [
        'assert(en.foo)',
        '          |   ',
        '          false',
    ]);

    test('deep MemberExpression', function (transpiledCode) {
        var en = { foo: { bar: false } };
        eval(transpiledCode);
    }, [
        'assert(en.foo.bar)',
        '              |   ',
        '              false',
    ]);

    test('CallExpression', function (transpiledCode) {
        var name = 'bar';
        var foo = function (n) { return false; };
        eval(transpiledCode);
    }, [
        'assert(foo(name))',
        '       |   |     ',
        '       |   "bar" ',
        '       false     ',
    ]);

    test('deep CallExpression', function (transpiledCode) {
        var bar = function () { return 'baz'; };
        var en = { foo: function (n) { return false; } };
        eval(transpiledCode);
    }, [
        'assert(en.foo(bar()))',
        '          |   |      ',
        '          |   "baz"  ',
        '          false      '
    ]);

    test('BinaryExpression of Identifier', function (transpiledCode) {
        var foo = 'foo';
        var bar = 'bar';
        eval(transpiledCode);
    }, [
        'assert(foo === bar)',
        '       |       |   ',
        '       "foo"   "bar"',
    ]);

    test('BinaryExpression of Identifier and StringLiteral', function (transpiledCode) {
        var foo = 'foo';
        eval(transpiledCode);
    }, [
        'assert(foo === "bar")',
        '       |             ',
        '       "foo"         '
    ]);

    test('BinaryExpression of StringLiteral', function (transpiledCode) {
        eval(transpiledCode);
    }, [
        'assert("foo" === "bar")',
        '                       ',
        '                       '
    ]);

    test('BinaryExpression of MemberExpression', function (transpiledCode) {
        var en = { foo: 'bar', toto: 'tata' };
        var fr = { toto: 'tata'};
        eval(transpiledCode);
    }, [
        'assert(en.foo === fr.toto)',
        '          |          |    ',
        '          "bar"      "tata"'
    ]);

    test('BinaryExpression of CallExpression', function (transpiledCode) {
        var en = { foo: function() { return 'bar';} };
        var fr = { toto: function() { return 'tata'; } };
        eval(transpiledCode);
    }, [
        'assert(en.foo() === fr.toto())',
        '          |            |      ',
        '          "bar"        "tata" '
    ]);

    test('non-Punctuator BinaryExpression operator', function (transpiledCode) {
        function Person (name) { this.name = name; };
        var foo = 'bob';
        eval(transpiledCode);
    }, [
        'assert(foo instanceof Person)',
        '       |              |      ',
        '       "bob"          #function#'
    ]);

    test('LogicalExpression of Identifiers', function (transpiledCode) {
        var x = false;
        var y = 0;
        var z = null;
        eval(transpiledCode);
    }, [
        'assert(x || y || z)',
        '       |    |    | ',
        '       |    0    null',
        '       false       '
    ]);

    test('LogicalExpression of Identifier evaluation order', function (transpiledCode) {
        var x = 'yeah';
        var y = 0;
        var z = true;
        eval(transpiledCode);
    }, [
        'assert(x && y && z)',
        '       |    |      ',
        '       |    0      ',
        '       "yeah"      '
    ]);

    test('LogicalExpression of CallExpression and MemberExpression', function (transpiledCode) {
        var x = { foo: function(n) { return false; } };
        var y = function(n) { return null; };
        var z = { val: 0 };
        eval(transpiledCode);
    }, [
        'assert(x.foo() || y() || z.val)',
        '         |        |        |   ',
        '         false    null     0   '
    ]);

    test('ArrayExpression as an argument of CallExpression', function (transpiledCode) {
        var pop = function (ary) { return ary.pop(); };
        var zero = 0;
        var one = 1;
        var two = 2;
        eval(transpiledCode);
    }, [
        'assert(pop([zero, one, two]) === one)',
        '       |    |     |    |         |   ',
        '       2    0     1    2         1   '
    ]);

});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Button, Clipboard, Text, View } from 'react-native';

import { Header } from '../components';

class ActiveTrip extends Component {
  state = { id: '', results: {} };

  constructor(props) {
    super(props);
  }

  componentWillMount() {
    this.fetchID();
  }

  copyID = id => {
    Clipboard.setString(id);
  };

  fetchID = () => {
    fetch('http://localhost:8000/v1/keygen')
      .then(response => response.json())
      .then(responseJSON => {
        this.setState({ id: responseJSON.id });
      })
      .catch(error => {
        console.log('Failed to fetch response.', error);
      });
  };

  fetchResults = () => {
    fetch('http://localhost:8000/v1/results?id=' + this.state.id)
      .then(response => response.json())
      .then(responseJSON => {
        this.setState({ results: responseJSON });
      })
      .catch(error => {
        console.log('Failed to fetch response.', error);
      });
  };

  render() {
    return (
      <View>
        Active Trip
        <Text>
          {this.state.id}
        </Text>
        <View style={styles.buttonStyle}>
          <Button
            onPress={() => this.copyID(this.state.id)}
            title="Copy"
            color="#007aff"
          />
          <Button onPress={this.fetchResults} title="Done" color="#007aff" />
          <Text>
            {' '}{JSON.stringify(this.state.results)}{' '}
          </Text>
          <Text> Head on over to your mail app </Text>
        </View>
      </View>
    );
  }
}

const styles = {
  buttonStyle: {
    borderWidth: 1,
    padding: 5,
  },
};

export default ActiveTrip;
<commit_msg>alert on copy<commit_after>import React, { Component } from 'react';
import { Alert, Button, Clipboard, Text, View } from 'react-native';

import { Header } from '../components';

class ActiveTrip extends Component {
  state = { id: '', results: {} };

  constructor(props) {
    super(props);
  }

  componentWillMount() {
    this.fetchID();
  }

  copyID = id => {
    Clipboard.setString(id);
    Alert.alert('Copied ID!');
  };

  fetchID = () => {
    fetch('http://localhost:8000/v1/keygen')
      .then(response => response.json())
      .then(responseJSON => {
        this.setState({ id: responseJSON.id });
      })
      .catch(error => {
        console.log('Failed to fetch response.', error);
      });
  };

  fetchResults = () => {
    fetch('http://localhost:8000/v1/results?id=' + this.state.id)
      .then(response => response.json())
      .then(responseJSON => {
        this.setState({ results: responseJSON });
      })
      .catch(error => {
        console.log('Failed to fetch response.', error);
      });
  };

  render() {
    return (
      <View>
        Active Trip
        <View style={styles.buttonStyle}>
          <Button
            onPress={() => this.copyID(this.state.id)}
            title={this.state.id}
            color="#007aff"
          />
          <Button onPress={this.fetchResults} title="Done" color="#007aff" />
        </View>
      </View>
    );
  }
}

const styles = {
  buttonStyle: {
    borderWidth: 1,
    padding: 5,
  },
};

export default ActiveTrip;
<|endoftext|>


<commit_before>/*
 * jQuery UI Button @VERSION
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Button
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

var lastActive, startXPos, startYPos, clickDragged,
	baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
	stateClasses = "ui-state-hover ui-state-active ",
	typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
	formResetHandler = function() {
		var buttons = $( this ).find( ":ui-button" );
		setTimeout(function() {
			buttons.button( "refresh" );
		}, 1 );
	},
	radioGroup = function( radio ) {
		var name = radio.name,
			form = radio.form,
			radios = $( [] );
		if ( name ) {
			if ( form ) {
				radios = $( form ).find( "[name='" + name + "']" );
			} else {
				radios = $( "[name='" + name + "']", radio.ownerDocument )
					.filter(function() {
						return !this.form;
					});
			}
		}
		return radios;
	};

$.widget( "ui.button", {
	version: "@VERSION",
	defaultElement: "<button>",
	options: {
		disabled: null,
		text: true,
		label: null,
		icons: {
			primary: null,
			secondary: null
		}
	},
	_create: function() {
		this.element.closest( "form" )
			.unbind( "reset.button" )
			.bind( "reset.button", formResetHandler );

		if ( typeof this.options.disabled !== "boolean" ) {
			this.options.disabled = this.element.prop( "disabled" );
		}

		this._determineButtonType();
		this.hasTitle = !!this.buttonElement.attr( "title" );

		var self = this,
			options = this.options,
			toggleButton = this.type === "checkbox" || this.type === "radio",
			hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
			focusClass = "ui-state-focus";

		if ( options.label === null ) {
			options.label = this.buttonElement.html();
		}

		if ( this.element.is( ":disabled" ) ) {
			options.disabled = true;
		}

		this.buttonElement
			.addClass( baseClasses )
			.attr( "role", "button" )
			.bind( "mouseenter.button", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).addClass( "ui-state-hover" );
				if ( this === lastActive ) {
					$( this ).addClass( "ui-state-active" );
				}
			})
			.bind( "mouseleave.button", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).removeClass( hoverClass );
			})
			.bind( "click.button", function( event ) {
				if ( options.disabled ) {
					event.preventDefault();
					event.stopImmediatePropagation();
				}
			});

		this.element
			.bind( "focus.button", function() {
				// no need to check disabled, focus won't be triggered anyway
				self.buttonElement.addClass( focusClass );
			})
			.bind( "blur.button", function() {
				self.buttonElement.removeClass( focusClass );
			});

		if ( toggleButton ) {
			this.element.bind( "change.button", function() {
				if ( clickDragged ) {
					return;
				}
				self.refresh();
			});
			// if mouse moves between mousedown and mouseup (drag) set clickDragged flag
			// prevents issue where button state changes but checkbox/radio checked state
			// does not in Firefox (see ticket #6970)
			this.buttonElement
				.bind( "mousedown.button", function( event ) {
					if ( options.disabled ) {
						return;
					}
					clickDragged = false;
					startXPos = event.pageX;
					startYPos = event.pageY;
				})
				.bind( "mouseup.button", function( event ) {
					if ( options.disabled ) {
						return;
					}
					if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
						clickDragged = true;
					}
			});
		}

		if ( this.type === "checkbox" ) {
			this.buttonElement.bind( "click.button", function() {
				if ( options.disabled || clickDragged ) {
					return false;
				}
				$( this ).toggleClass( "ui-state-active" );
				self.buttonElement.attr( "aria-pressed", self.element[0].checked );
			});
		} else if ( this.type === "radio" ) {
			this.buttonElement.bind( "click.button", function() {
				if ( options.disabled || clickDragged ) {
					return false;
				}
				$( this ).addClass( "ui-state-active" );
				self.buttonElement.attr( "aria-pressed", "true" );

				var radio = self.element[ 0 ];
				radioGroup( radio )
					.not( radio )
					.map(function() {
						return $( this ).button( "widget" )[ 0 ];
					})
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", "false" );
			});
		} else {
			this.buttonElement
				.bind( "mousedown.button", function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).addClass( "ui-state-active" );
					lastActive = this;
					$( document ).one( "mouseup", function() {
						lastActive = null;
					});
				})
				.bind( "mouseup.button", function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).removeClass( "ui-state-active" );
				})
				.bind( "keydown.button", function(event) {
					if ( options.disabled ) {
						return false;
					}
					if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {
						$( this ).addClass( "ui-state-active" );
					}
				})
				.bind( "keyup.button", function() {
					$( this ).removeClass( "ui-state-active" );
				});

			if ( this.buttonElement.is("a") ) {
				this.buttonElement.keyup(function(event) {
					if ( event.keyCode === $.ui.keyCode.SPACE ) {
						// TODO pass through original event correctly (just as 2nd argument doesn't work)
						$( this ).click();
					}
				});
			}
		}

		// TODO: pull out $.Widget's handling for the disabled option into
		// $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
		// be overridden by individual plugins
		this._setOption( "disabled", options.disabled );
		this._resetButton();
	},

	_determineButtonType: function() {

		if ( this.element.is(":checkbox") ) {
			this.type = "checkbox";
		} else if ( this.element.is(":radio") ) {
			this.type = "radio";
		} else if ( this.element.is("input") ) {
			this.type = "input";
		} else {
			this.type = "button";
		}

		if ( this.type === "checkbox" || this.type === "radio" ) {
			// we don't search against the document in case the element
			// is disconnected from the DOM
			var ancestor = this.element.parents().last(),
				labelSelector = "label[for='" + this.element.attr("id") + "']";
			this.buttonElement = ancestor.find( labelSelector );
			if ( !this.buttonElement.length ) {
				ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
				this.buttonElement = ancestor.filter( labelSelector );
				if ( !this.buttonElement.length ) {
					this.buttonElement = ancestor.find( labelSelector );
				}
			}
			this.element.addClass( "ui-helper-hidden-accessible" );

			var checked = this.element.is( ":checked" );
			if ( checked ) {
				this.buttonElement.addClass( "ui-state-active" );
			}
			this.buttonElement.prop( "aria-pressed", checked );
		} else {
			this.buttonElement = this.element;
		}
	},

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

	_destroy: function() {
		this.element
			.removeClass( "ui-helper-hidden-accessible" );
		this.buttonElement
			.removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
			.removeAttr( "role" )
			.removeAttr( "aria-pressed" )
			.html( this.buttonElement.find(".ui-button-text").html() );

		if ( !this.hasTitle ) {
			this.buttonElement.removeAttr( "title" );
		}
	},

	_setOption: function( key, value ) {
		this._super( "_setOption", key, value );
		if ( key === "disabled" ) {
			if ( value ) {
				this.element.prop( "disabled", true );
			} else {
				this.element.prop( "disabled", false );
			}
			return;
		}
		this._resetButton();
	},

	refresh: function() {
		var isDisabled = this.element.is( ":disabled" );
		if ( isDisabled !== this.options.disabled ) {
			this._setOption( "disabled", isDisabled );
		}
		if ( this.type === "radio" ) {
			radioGroup( this.element[0] ).each(function() {
				if ( $( this ).is( ":checked" ) ) {
					$( this ).button( "widget" )
						.addClass( "ui-state-active" )
						.attr( "aria-pressed", "true" );
				} else {
					$( this ).button( "widget" )
						.removeClass( "ui-state-active" )
						.attr( "aria-pressed", "false" );
				}
			});
		} else if ( this.type === "checkbox" ) {
			if ( this.element.is( ":checked" ) ) {
				this.buttonElement
					.addClass( "ui-state-active" )
					.attr( "aria-pressed", "true" );
			} else {
				this.buttonElement
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", "false" );
			}
		}
	},

	_resetButton: function() {
		if ( this.type === "input" ) {
			if ( this.options.label ) {
				this.element.val( this.options.label );
			}
			return;
		}
		var buttonElement = this.buttonElement.removeClass( typeClasses ),
			buttonText = $( "" )
				.addClass( "ui-button-text" )
				.html( this.options.label )
				.appendTo( buttonElement.empty() )
				.text(),
			icons = this.options.icons,
			multipleIcons = icons.primary && icons.secondary,
			buttonClasses = [];

		if ( icons.primary || icons.secondary ) {
			if ( this.options.text ) {
				buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
			}

			if ( icons.primary ) {
				buttonElement.prepend( "" );
			}

			if ( icons.secondary ) {
				buttonElement.append( "" );
			}

			if ( !this.options.text ) {
				buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );

				if ( !this.hasTitle ) {
					buttonElement.attr( "title", buttonText );
				}
			}
		} else {
			buttonClasses.push( "ui-button-text-only" );
		}
		buttonElement.addClass( buttonClasses.join( " " ) );
	}
});

$.ui.button.version = "@VERSION";

$.widget( "ui.buttonset", {
	options: {
		items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)"
	},

	_create: function() {
		this.element.addClass( "ui-buttonset" );
	},

	_init: function() {
		this.refresh();
	},

	_setOption: function( key, value ) {
		if ( key === "disabled" ) {
			this.buttons.button( "option", key, value );
		}

		this._super( "_setOption", key, value );
	},

	refresh: function() {
		var ltr = this.element.css( "direction" ) === "ltr";

		this.buttons = this.element.find( this.options.items )
			.filter( ":ui-button" )
				.button( "refresh" )
			.end()
			.not( ":ui-button" )
				.button()
			.end()
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
				.filter( ":first" )
					.addClass( ltr ? "ui-corner-left" : "ui-corner-right" )
				.end()
				.filter( ":last" )
					.addClass( ltr ? "ui-corner-right" : "ui-corner-left" )
				.end()
			.end();
	},

	_destroy: function() {
		this.element.removeClass( "ui-buttonset" );
		this.buttons
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-left ui-corner-right" )
			.end()
			.button( "destroy" );
	}
});

}( jQuery ) );
<commit_msg>Button: Fixed RTL detection to default to LTR. Fixes #7697 - Buttonset: Incorrect corners for disconnected elements.<commit_after>/*
 * jQuery UI Button @VERSION
 *
 * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 * Dual licensed under the MIT or GPL Version 2 licenses.
 * http://jquery.org/license
 *
 * http://docs.jquery.com/UI/Button
 *
 * Depends:
 *	jquery.ui.core.js
 *	jquery.ui.widget.js
 */
(function( $, undefined ) {

var lastActive, startXPos, startYPos, clickDragged,
	baseClasses = "ui-button ui-widget ui-state-default ui-corner-all",
	stateClasses = "ui-state-hover ui-state-active ",
	typeClasses = "ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only",
	formResetHandler = function() {
		var buttons = $( this ).find( ":ui-button" );
		setTimeout(function() {
			buttons.button( "refresh" );
		}, 1 );
	},
	radioGroup = function( radio ) {
		var name = radio.name,
			form = radio.form,
			radios = $( [] );
		if ( name ) {
			if ( form ) {
				radios = $( form ).find( "[name='" + name + "']" );
			} else {
				radios = $( "[name='" + name + "']", radio.ownerDocument )
					.filter(function() {
						return !this.form;
					});
			}
		}
		return radios;
	};

$.widget( "ui.button", {
	version: "@VERSION",
	defaultElement: "<button>",
	options: {
		disabled: null,
		text: true,
		label: null,
		icons: {
			primary: null,
			secondary: null
		}
	},
	_create: function() {
		this.element.closest( "form" )
			.unbind( "reset.button" )
			.bind( "reset.button", formResetHandler );

		if ( typeof this.options.disabled !== "boolean" ) {
			this.options.disabled = this.element.prop( "disabled" );
		}

		this._determineButtonType();
		this.hasTitle = !!this.buttonElement.attr( "title" );

		var self = this,
			options = this.options,
			toggleButton = this.type === "checkbox" || this.type === "radio",
			hoverClass = "ui-state-hover" + ( !toggleButton ? " ui-state-active" : "" ),
			focusClass = "ui-state-focus";

		if ( options.label === null ) {
			options.label = this.buttonElement.html();
		}

		if ( this.element.is( ":disabled" ) ) {
			options.disabled = true;
		}

		this.buttonElement
			.addClass( baseClasses )
			.attr( "role", "button" )
			.bind( "mouseenter.button", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).addClass( "ui-state-hover" );
				if ( this === lastActive ) {
					$( this ).addClass( "ui-state-active" );
				}
			})
			.bind( "mouseleave.button", function() {
				if ( options.disabled ) {
					return;
				}
				$( this ).removeClass( hoverClass );
			})
			.bind( "click.button", function( event ) {
				if ( options.disabled ) {
					event.preventDefault();
					event.stopImmediatePropagation();
				}
			});

		this.element
			.bind( "focus.button", function() {
				// no need to check disabled, focus won't be triggered anyway
				self.buttonElement.addClass( focusClass );
			})
			.bind( "blur.button", function() {
				self.buttonElement.removeClass( focusClass );
			});

		if ( toggleButton ) {
			this.element.bind( "change.button", function() {
				if ( clickDragged ) {
					return;
				}
				self.refresh();
			});
			// if mouse moves between mousedown and mouseup (drag) set clickDragged flag
			// prevents issue where button state changes but checkbox/radio checked state
			// does not in Firefox (see ticket #6970)
			this.buttonElement
				.bind( "mousedown.button", function( event ) {
					if ( options.disabled ) {
						return;
					}
					clickDragged = false;
					startXPos = event.pageX;
					startYPos = event.pageY;
				})
				.bind( "mouseup.button", function( event ) {
					if ( options.disabled ) {
						return;
					}
					if ( startXPos !== event.pageX || startYPos !== event.pageY ) {
						clickDragged = true;
					}
			});
		}

		if ( this.type === "checkbox" ) {
			this.buttonElement.bind( "click.button", function() {
				if ( options.disabled || clickDragged ) {
					return false;
				}
				$( this ).toggleClass( "ui-state-active" );
				self.buttonElement.attr( "aria-pressed", self.element[0].checked );
			});
		} else if ( this.type === "radio" ) {
			this.buttonElement.bind( "click.button", function() {
				if ( options.disabled || clickDragged ) {
					return false;
				}
				$( this ).addClass( "ui-state-active" );
				self.buttonElement.attr( "aria-pressed", "true" );

				var radio = self.element[ 0 ];
				radioGroup( radio )
					.not( radio )
					.map(function() {
						return $( this ).button( "widget" )[ 0 ];
					})
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", "false" );
			});
		} else {
			this.buttonElement
				.bind( "mousedown.button", function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).addClass( "ui-state-active" );
					lastActive = this;
					$( document ).one( "mouseup", function() {
						lastActive = null;
					});
				})
				.bind( "mouseup.button", function() {
					if ( options.disabled ) {
						return false;
					}
					$( this ).removeClass( "ui-state-active" );
				})
				.bind( "keydown.button", function(event) {
					if ( options.disabled ) {
						return false;
					}
					if ( event.keyCode == $.ui.keyCode.SPACE || event.keyCode == $.ui.keyCode.ENTER ) {
						$( this ).addClass( "ui-state-active" );
					}
				})
				.bind( "keyup.button", function() {
					$( this ).removeClass( "ui-state-active" );
				});

			if ( this.buttonElement.is("a") ) {
				this.buttonElement.keyup(function(event) {
					if ( event.keyCode === $.ui.keyCode.SPACE ) {
						// TODO pass through original event correctly (just as 2nd argument doesn't work)
						$( this ).click();
					}
				});
			}
		}

		// TODO: pull out $.Widget's handling for the disabled option into
		// $.Widget.prototype._setOptionDisabled so it's easy to proxy and can
		// be overridden by individual plugins
		this._setOption( "disabled", options.disabled );
		this._resetButton();
	},

	_determineButtonType: function() {

		if ( this.element.is(":checkbox") ) {
			this.type = "checkbox";
		} else if ( this.element.is(":radio") ) {
			this.type = "radio";
		} else if ( this.element.is("input") ) {
			this.type = "input";
		} else {
			this.type = "button";
		}

		if ( this.type === "checkbox" || this.type === "radio" ) {
			// we don't search against the document in case the element
			// is disconnected from the DOM
			var ancestor = this.element.parents().last(),
				labelSelector = "label[for='" + this.element.attr("id") + "']";
			this.buttonElement = ancestor.find( labelSelector );
			if ( !this.buttonElement.length ) {
				ancestor = ancestor.length ? ancestor.siblings() : this.element.siblings();
				this.buttonElement = ancestor.filter( labelSelector );
				if ( !this.buttonElement.length ) {
					this.buttonElement = ancestor.find( labelSelector );
				}
			}
			this.element.addClass( "ui-helper-hidden-accessible" );

			var checked = this.element.is( ":checked" );
			if ( checked ) {
				this.buttonElement.addClass( "ui-state-active" );
			}
			this.buttonElement.prop( "aria-pressed", checked );
		} else {
			this.buttonElement = this.element;
		}
	},

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

	_destroy: function() {
		this.element
			.removeClass( "ui-helper-hidden-accessible" );
		this.buttonElement
			.removeClass( baseClasses + " " + stateClasses + " " + typeClasses )
			.removeAttr( "role" )
			.removeAttr( "aria-pressed" )
			.html( this.buttonElement.find(".ui-button-text").html() );

		if ( !this.hasTitle ) {
			this.buttonElement.removeAttr( "title" );
		}
	},

	_setOption: function( key, value ) {
		this._super( "_setOption", key, value );
		if ( key === "disabled" ) {
			if ( value ) {
				this.element.prop( "disabled", true );
			} else {
				this.element.prop( "disabled", false );
			}
			return;
		}
		this._resetButton();
	},

	refresh: function() {
		var isDisabled = this.element.is( ":disabled" );
		if ( isDisabled !== this.options.disabled ) {
			this._setOption( "disabled", isDisabled );
		}
		if ( this.type === "radio" ) {
			radioGroup( this.element[0] ).each(function() {
				if ( $( this ).is( ":checked" ) ) {
					$( this ).button( "widget" )
						.addClass( "ui-state-active" )
						.attr( "aria-pressed", "true" );
				} else {
					$( this ).button( "widget" )
						.removeClass( "ui-state-active" )
						.attr( "aria-pressed", "false" );
				}
			});
		} else if ( this.type === "checkbox" ) {
			if ( this.element.is( ":checked" ) ) {
				this.buttonElement
					.addClass( "ui-state-active" )
					.attr( "aria-pressed", "true" );
			} else {
				this.buttonElement
					.removeClass( "ui-state-active" )
					.attr( "aria-pressed", "false" );
			}
		}
	},

	_resetButton: function() {
		if ( this.type === "input" ) {
			if ( this.options.label ) {
				this.element.val( this.options.label );
			}
			return;
		}
		var buttonElement = this.buttonElement.removeClass( typeClasses ),
			buttonText = $( "" )
				.addClass( "ui-button-text" )
				.html( this.options.label )
				.appendTo( buttonElement.empty() )
				.text(),
			icons = this.options.icons,
			multipleIcons = icons.primary && icons.secondary,
			buttonClasses = [];

		if ( icons.primary || icons.secondary ) {
			if ( this.options.text ) {
				buttonClasses.push( "ui-button-text-icon" + ( multipleIcons ? "s" : ( icons.primary ? "-primary" : "-secondary" ) ) );
			}

			if ( icons.primary ) {
				buttonElement.prepend( "" );
			}

			if ( icons.secondary ) {
				buttonElement.append( "" );
			}

			if ( !this.options.text ) {
				buttonClasses.push( multipleIcons ? "ui-button-icons-only" : "ui-button-icon-only" );

				if ( !this.hasTitle ) {
					buttonElement.attr( "title", buttonText );
				}
			}
		} else {
			buttonClasses.push( "ui-button-text-only" );
		}
		buttonElement.addClass( buttonClasses.join( " " ) );
	}
});

$.ui.button.version = "@VERSION";

$.widget( "ui.buttonset", {
	options: {
		items: ":button, :submit, :reset, :checkbox, :radio, a, :data(button)"
	},

	_create: function() {
		this.element.addClass( "ui-buttonset" );
	},

	_init: function() {
		this.refresh();
	},

	_setOption: function( key, value ) {
		if ( key === "disabled" ) {
			this.buttons.button( "option", key, value );
		}

		this._super( "_setOption", key, value );
	},

	refresh: function() {
		var rtl = this.element.css( "direction" ) === "rtl";

		this.buttons = this.element.find( this.options.items )
			.filter( ":ui-button" )
				.button( "refresh" )
			.end()
			.not( ":ui-button" )
				.button()
			.end()
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-all ui-corner-left ui-corner-right" )
				.filter( ":first" )
					.addClass( rtl ? "ui-corner-right" : "ui-corner-left" )
				.end()
				.filter( ":last" )
					.addClass( rtl ? "ui-corner-left" : "ui-corner-right" )
				.end()
			.end();
	},

	_destroy: function() {
		this.element.removeClass( "ui-buttonset" );
		this.buttons
			.map(function() {
				return $( this ).button( "widget" )[ 0 ];
			})
				.removeClass( "ui-corner-left ui-corner-right" )
			.end()
			.button( "destroy" );
	}
});

}( jQuery ) );
<|endoftext|>


<commit_before>/**
 * Copyright (c) 2006
 * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **/

/**
 * Init namespaces
 */
if(!ORYX) {var ORYX = {};}
if(!ORYX.Core) {ORYX.Core = {};}

/**
 * @classDescription Top Level uiobject.
 *
 */
ORYX.Core.Canvas = ORYX.Core.AbstractShape.extend({

	/**
	 * Constructor
	 */
	construct: function(options) {
		arguments.callee.$.construct.apply(this, arguments);

		if(!(options && options.width && options.height)) {

			ORYX.Log.fatal("Canvas is missing mandatory parameters options.width and options.height.");
			return;
		};

		//TODO set document resource id
		this.resourceId = options.id;

		//init svg document
		this.rootNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", null,
			['svg', {id: this.id, width: options.width, height: options.height},
				['defs', {}]
			]);

		this.rootNode.setAttributeNS("xmlns", "xlink", "http://www.w3.org/1999/xlink");
		this.rootNode.setAttributeNS("xmlns", "svg", "http://www.w3.org/2000/svg");

		this._htmlContainer = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", null,
			['div', {id: "kunzestinkt", style:"position:relative; top:-" + (options.height + 4) + "px"}]);

		this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.rootNode,
			['g', {},
				['g', {"class": "stencils"},
					['g', {"class": "me"}],
					['g', {"class": "children"}],
					['g', {"class": "edge"}]
				],
				['g', {"class":"svgcontainer"}]
			]);

		/*
		var off = 2 * ORYX.CONFIG.GRID_DISTANCE;
		var size = 3;
		var d = "";
		for(var i = 0; i <= options.width; i += off)
			for(var j = 0; j <= options.height; j += off)
				d = d + "M" + (i - size) + " " + j + " l" + (2*size) + " 0 m" + (-size) + " " + (-size) + " l0 " + (2*size) + " m0" + (-size) + " ";

		ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node.firstChild.firstChild,
			['path', {d:d , stroke:'#000000', 'stroke-width':'0.15px'},]);
		*/

		this.bounds.set(0,0,options.width, options.height);

		this.addEventHandlers(this.rootNode);
	},

	update: function() {
		this.layout();
	},

	layout: function() {
		this.children.each(function(child) {
			child._update();
		})
	},

	/**
	 * Overrides the UIObject.add method. Adds uiObject to the correct sub node.
	 * @param {UIObject} uiObject
	 */
	add: function(uiObject) {
		//if uiObject is child of another UIObject, remove it.
		if(uiObject instanceof ORYX.Core.UIObject) {
			if (!(this.children.member(uiObject))) {
				//if uiObject is child of another parent, remove it from that parent.
				if(uiObject.parent) {
					uiObject.parent.remove(uiObject);
				}

				//add uiObject to the Canvas
				this.children.push(uiObject);

				//set parent reference
				uiObject.parent = this;

				//add uiObject.node to this.node depending on the type of uiObject
				if(uiObject instanceof ORYX.Core.Shape) {
					if(uiObject instanceof ORYX.Core.Edge) {
						uiObject.addMarkers(this.rootNode.getElementsByTagNameNS(NAMESPACE_SVG, "defs")[0]);
						uiObject.node = this.node.childNodes[0].childNodes[2].appendChild(uiObject.node);
					} else {
						uiObject.node = this.node.childNodes[0].childNodes[1].appendChild(uiObject.node);
					}
				} else {	//UIObject
					uiObject.node = this.node.appendChild(uiObject.node);
				}

				uiObject.bounds.registerCallback(this._changedCallback);
			} else {

				ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object.");
			}
		} else {

			ORYX.Log.fatal("add: Parameter is not of type ORYX.Core.UIObject.");
		}
	},

	/**
	 * Overrides the UIObject.remove method. Removes uiObject.
	 * @param {UIObject} uiObject
	 */
	remove: function(uiObject) {
		//if uiObject is a child of this object, remove it.
		if (this.children.member(uiObject)) {
			//remove uiObject from children
			this.children = this.children.without(uiObject);

			//delete parent reference of uiObject
			uiObject.parent = undefined;

			//delete uiObject.node from this.node
			if(uiObject instanceof ORYX.Core.Shape) {
				if(uiObject instanceof ORYX.Core.Edge) {
					uiObject.removeMarkers();
					uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node);
				} else {
					uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node);
				}
			} else {	//UIObject
					uiObject.node = this.node.removeChild(uiObject.node);
			}

			uiObject.bounds.unregisterCallback(this._changedCallback);
		} else {

			ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object.");
		}
	},

	getRootNode: function() {
		return this.rootNode;
	},

	getSvgContainer: function() {
		return this.node.childNodes[1];
	},

	getHTMLContainer: function() {
		return this._htmlContainer;
	},

	/**
	 * Return all elements of the same highest level
	 * @param {Object} elements
	 */
	getShapesWithSharedParent: function(elements) {

		// If there is no elements, return []
		if(!elements || elements.length < 1) { return [] }
		// If there is one element, return this element
		if(elements.length == 1) { return elements}

		return elements.findAll(function(value){
			var parentShape = value.parent;
			while(parentShape){
				if(elements.member(parentShape)) return false;
				parentShape = parentShape.parent
			}
			return true;
		});

	},

	setSize: function(size) {
		if(!size || !size.width || !size.height){return}

		if(this.rootNode.parentNode){
			this.rootNode.parentNode.style.width = size.width + 'px';
			this.rootNode.parentNode.style.height = size.height + 'px';
		}

		this.rootNode.setAttributeNS(null, 'width', size.width);
		this.rootNode.setAttributeNS(null, 'height', size.height);

		this._htmlContainer.style.top = "-" + (size.height + 4) + 'px';
	},

	/**
	 * Returns an SVG document of the current process.
	 * @param {Boolean} escapeText Use true, if you want to parse it with an XmlParser,
	 * 					false, if you want to use the SVG document in browser on client side.
	 */
	getSVGRepresentation: function(escapeText) {
		// Get the serialized svg image source
        var svgClone = this.getRootNode().cloneNode(true);

		var x1, y1, x2, y2;
		this.getChildShapes(true).each(function(shape) {
			var absBounds = shape.absoluteBounds();
			var ul = absBounds.upperLeft();
			var lr = absBounds.lowerRight();
			if(x1 == undefined) {
				x1 = ul.x;
				y1 = ul.y;
				x2 = lr.x;
				y2 = lr.y;
			} else {
				x1 = Math.min(x1, ul.x);
				y1 = Math.min(y1, ul.y);
				x2 = Math.max(x2, lr.x);
				y2 = Math.max(y2, lr.y);
			}
		});

		var margin = 10;

		var width, height, tx, ty;
		if(x1 == undefined) {
			width = 0;
			height = 0;
			tx = 0;
			ty = 0;
		} else {
			width = x2 - x1;
			height = y2 - y1;
			tx = -x1+margin/2;
			ty = -y1+margin/2;
		}

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', width + margin);
        svgClone.setAttributeNS(null, 'height', height + margin);

		svgClone.childNodes[1].firstChild.setAttributeNS(null, 'transform', 'translate(' + tx + ", " + ty + ')');

		try{
			var svgCont = svgClone.childNodes[1].childNodes[1];
			svgCont.parentNode.removeChild(svgCont);
		} catch(e) {}

		if(escapeText) {
			$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan')).each(function(elem) {
				elem.textContent = elem.textContent.escapeHTML();
			});

			$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text')).each(function(elem) {
				if(elem.childNodes.length == 0)
					elem.textContent = elem.textContent.escapeHTML();
			});
		}

        return svgClone;
	},

	toString: function() { return "Canvas " + this.id }
 });<commit_msg>edited layout() method of the Canvas class to call the stencil's layout callback. (to be checked first, line is commented out.)<commit_after>/**
 * Copyright (c) 2006
 * Martin Czuchra, Nicolas Peters, Daniel Polak, Willi Tscheschner
 *
 * Permission is hereby granted, free of charge, to any person obtaining a
 * copy of this software and associated documentation files (the "Software"),
 * to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
 * and/or sell copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 **/

/**
 * Init namespaces
 */
if(!ORYX) {var ORYX = {};}
if(!ORYX.Core) {ORYX.Core = {};}

/**
 * @classDescription Top Level uiobject.
 *
 */
ORYX.Core.Canvas = ORYX.Core.AbstractShape.extend({

	/**
	 * Constructor
	 */
	construct: function(options) {
		arguments.callee.$.construct.apply(this, arguments);

		if(!(options && options.width && options.height)) {

			ORYX.Log.fatal("Canvas is missing mandatory parameters options.width and options.height.");
			return;
		};

		//TODO set document resource id
		this.resourceId = options.id;

		//init svg document
		this.rootNode = ORYX.Editor.graft("http://www.w3.org/2000/svg", null,
			['svg', {id: this.id, width: options.width, height: options.height},
				['defs', {}]
			]);

		this.rootNode.setAttributeNS("xmlns", "xlink", "http://www.w3.org/1999/xlink");
		this.rootNode.setAttributeNS("xmlns", "svg", "http://www.w3.org/2000/svg");

		this._htmlContainer = ORYX.Editor.graft("http://www.w3.org/1999/xhtml", null,
			['div', {id: "kunzestinkt", style:"position:relative; top:-" + (options.height + 4) + "px"}]);

		this.node = ORYX.Editor.graft("http://www.w3.org/2000/svg", this.rootNode,
			['g', {},
				['g', {"class": "stencils"},
					['g', {"class": "me"}],
					['g', {"class": "children"}],
					['g', {"class": "edge"}]
				],
				['g', {"class":"svgcontainer"}]
			]);

		/*
		var off = 2 * ORYX.CONFIG.GRID_DISTANCE;
		var size = 3;
		var d = "";
		for(var i = 0; i <= options.width; i += off)
			for(var j = 0; j <= options.height; j += off)
				d = d + "M" + (i - size) + " " + j + " l" + (2*size) + " 0 m" + (-size) + " " + (-size) + " l0 " + (2*size) + " m0" + (-size) + " ";

		ORYX.Editor.graft("http://www.w3.org/2000/svg", this.node.firstChild.firstChild,
			['path', {d:d , stroke:'#000000', 'stroke-width':'0.15px'},]);
		*/

		this.bounds.set(0,0,options.width, options.height);

		this.addEventHandlers(this.rootNode);
	},

	update: function() {
		this.layout();
	},

	layout: function() {
		// call stencil's layout callback
		// (needed for row layouting of xforms)
		// this.getStencil().layout(this);

		this.children.each(function(child) {
			child._update();
		})
	},

	/**
	 * Overrides the UIObject.add method. Adds uiObject to the correct sub node.
	 * @param {UIObject} uiObject
	 */
	add: function(uiObject) {
		//if uiObject is child of another UIObject, remove it.
		if(uiObject instanceof ORYX.Core.UIObject) {
			if (!(this.children.member(uiObject))) {
				//if uiObject is child of another parent, remove it from that parent.
				if(uiObject.parent) {
					uiObject.parent.remove(uiObject);
				}

				//add uiObject to the Canvas
				this.children.push(uiObject);

				//set parent reference
				uiObject.parent = this;

				//add uiObject.node to this.node depending on the type of uiObject
				if(uiObject instanceof ORYX.Core.Shape) {
					if(uiObject instanceof ORYX.Core.Edge) {
						uiObject.addMarkers(this.rootNode.getElementsByTagNameNS(NAMESPACE_SVG, "defs")[0]);
						uiObject.node = this.node.childNodes[0].childNodes[2].appendChild(uiObject.node);
					} else {
						uiObject.node = this.node.childNodes[0].childNodes[1].appendChild(uiObject.node);
					}
				} else {	//UIObject
					uiObject.node = this.node.appendChild(uiObject.node);
				}

				uiObject.bounds.registerCallback(this._changedCallback);
			} else {

				ORYX.Log.warn("add: ORYX.Core.UIObject is already a child of this object.");
			}
		} else {

			ORYX.Log.fatal("add: Parameter is not of type ORYX.Core.UIObject.");
		}
	},

	/**
	 * Overrides the UIObject.remove method. Removes uiObject.
	 * @param {UIObject} uiObject
	 */
	remove: function(uiObject) {
		//if uiObject is a child of this object, remove it.
		if (this.children.member(uiObject)) {
			//remove uiObject from children
			this.children = this.children.without(uiObject);

			//delete parent reference of uiObject
			uiObject.parent = undefined;

			//delete uiObject.node from this.node
			if(uiObject instanceof ORYX.Core.Shape) {
				if(uiObject instanceof ORYX.Core.Edge) {
					uiObject.removeMarkers();
					uiObject.node = this.node.childNodes[0].childNodes[2].removeChild(uiObject.node);
				} else {
					uiObject.node = this.node.childNodes[0].childNodes[1].removeChild(uiObject.node);
				}
			} else {	//UIObject
					uiObject.node = this.node.removeChild(uiObject.node);
			}

			uiObject.bounds.unregisterCallback(this._changedCallback);
		} else {

			ORYX.Log.warn("remove: ORYX.Core.UIObject is not a child of this object.");
		}
	},

	getRootNode: function() {
		return this.rootNode;
	},

	getSvgContainer: function() {
		return this.node.childNodes[1];
	},

	getHTMLContainer: function() {
		return this._htmlContainer;
	},

	/**
	 * Return all elements of the same highest level
	 * @param {Object} elements
	 */
	getShapesWithSharedParent: function(elements) {

		// If there is no elements, return []
		if(!elements || elements.length < 1) { return [] }
		// If there is one element, return this element
		if(elements.length == 1) { return elements}

		return elements.findAll(function(value){
			var parentShape = value.parent;
			while(parentShape){
				if(elements.member(parentShape)) return false;
				parentShape = parentShape.parent
			}
			return true;
		});

	},

	setSize: function(size) {
		if(!size || !size.width || !size.height){return}

		if(this.rootNode.parentNode){
			this.rootNode.parentNode.style.width = size.width + 'px';
			this.rootNode.parentNode.style.height = size.height + 'px';
		}

		this.rootNode.setAttributeNS(null, 'width', size.width);
		this.rootNode.setAttributeNS(null, 'height', size.height);

		this._htmlContainer.style.top = "-" + (size.height + 4) + 'px';
	},

	/**
	 * Returns an SVG document of the current process.
	 * @param {Boolean} escapeText Use true, if you want to parse it with an XmlParser,
	 * 					false, if you want to use the SVG document in browser on client side.
	 */
	getSVGRepresentation: function(escapeText) {
		// Get the serialized svg image source
        var svgClone = this.getRootNode().cloneNode(true);

		var x1, y1, x2, y2;
		this.getChildShapes(true).each(function(shape) {
			var absBounds = shape.absoluteBounds();
			var ul = absBounds.upperLeft();
			var lr = absBounds.lowerRight();
			if(x1 == undefined) {
				x1 = ul.x;
				y1 = ul.y;
				x2 = lr.x;
				y2 = lr.y;
			} else {
				x1 = Math.min(x1, ul.x);
				y1 = Math.min(y1, ul.y);
				x2 = Math.max(x2, lr.x);
				y2 = Math.max(y2, lr.y);
			}
		});

		var margin = 10;

		var width, height, tx, ty;
		if(x1 == undefined) {
			width = 0;
			height = 0;
			tx = 0;
			ty = 0;
		} else {
			width = x2 - x1;
			height = y2 - y1;
			tx = -x1+margin/2;
			ty = -y1+margin/2;
		}

        // Set the width and height
        svgClone.setAttributeNS(null, 'width', width + margin);
        svgClone.setAttributeNS(null, 'height', height + margin);

		svgClone.childNodes[1].firstChild.setAttributeNS(null, 'transform', 'translate(' + tx + ", " + ty + ')');

		try{
			var svgCont = svgClone.childNodes[1].childNodes[1];
			svgCont.parentNode.removeChild(svgCont);
		} catch(e) {}

		if(escapeText) {
			$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'tspan')).each(function(elem) {
				elem.textContent = elem.textContent.escapeHTML();
			});

			$A(svgClone.getElementsByTagNameNS(ORYX.CONFIG.NAMESPACE_SVG, 'text')).each(function(elem) {
				if(elem.childNodes.length == 0)
					elem.textContent = elem.textContent.escapeHTML();
			});
		}

        return svgClone;
	},

	toString: function() { return "Canvas " + this.id }
 });<|endoftext|>


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

//import { MozillaBrowserBot } from "./selenium-browserbot";
import { bot, core } from "./closure-polyfill";
import { parse_locator } from "./utils";
import finder from "@medv/finder";

export default function LocatorBuilders(window) {
  this.window = window;
}

window.LocatorBuilders = LocatorBuilders;

LocatorBuilders.prototype.detach = function() {
};

LocatorBuilders.prototype.buildWith = function(name, e, opt_contextNode) {
  return LocatorBuilders.builderMap[name].call(this, e, opt_contextNode);
};

LocatorBuilders.prototype.elementEquals = function(name, e, locator) {
  let fe = this.findElement(locator);
  //TODO: add match function to the ui locator builder, note the inverted parameters
  return (e == fe) || (LocatorBuilders.builderMap[name] && LocatorBuilders.builderMap[name].match && LocatorBuilders.builderMap[name].match(e, fe));
};

LocatorBuilders.prototype.build = function(e) {
  let locators = this.buildAll(e);
  if (locators.length > 0) {
    return locators[0][0];
  } else {
    return "LOCATOR_DETECTION_FAILED";
  }
};

LocatorBuilders.prototype.buildAll = function(el) {
  let e = core.firefox.unwrap(el); //Samit: Fix: Do the magic to get it to work in Firefox 4
  let locator;
  let locators = [];
  for (let i = 0; i < LocatorBuilders.order.length; i++) {
    let finderName = LocatorBuilders.order[i];
    try {
      locator = this.buildWith(finderName, e);
      if (locator) {
        locator = String(locator);
        //Samit: The following is a quickfix for above commented code to stop exceptions on almost every locator builder
        //TODO: the builderName should NOT be used as a strategy name, create a feature to allow locatorBuilders to specify this kind of behaviour
        //TODO: Useful if a builder wants to capture a different element like a parent. Use the this.elementEquals
        let fe = this.findElement(locator);
        if (e == fe) {
          locators.push([locator, finderName]);
        }
      }
    } catch (e) {
      // TODO ignore the buggy locator builder for now
      //this.log.debug("locator exception: " + e);
    }
  }
  return locators;
};

LocatorBuilders.prototype.findElement = function(loc) {
  try {
    const locator = parse_locator(loc, true);
    return bot.locators.findElement({ [locator.type]: locator.string }, this.window.document);
  } catch (error) {
    //this.log.debug("findElement failed: " + error + ", locator=" + locator);
    return null;
  }
};

/*
 * Class methods
 */

LocatorBuilders.order = [];
LocatorBuilders.builderMap = {};
LocatorBuilders._preferredOrder = [];
// NOTE: for some reasons we does not use this part
// classObservable(LocatorBuilders);

LocatorBuilders.add = function(name, finder) {
  this.order.push(name);
  this.builderMap[name] = finder;
  this._orderChanged();
};

/**
 * Call when the order or preferred order changes
 */
LocatorBuilders._orderChanged = function() {
  let changed = this._ensureAllPresent(this.order, this._preferredOrder);
  this._sortByRefOrder(this.order, this._preferredOrder);
  if (changed) {
    // NOTE: for some reasons we does not use this part
    // this.notify('preferredOrderChanged', this._preferredOrder);
  }
};

/**
 * Set the preferred order of the locator builders
 *
 * @param preferredOrder can be an array or a comma separated string of names
 */
LocatorBuilders.setPreferredOrder = function(preferredOrder) {
  if (typeof preferredOrder === "string") {
    this._preferredOrder = preferredOrder.split(",");
  } else {
    this._preferredOrder = preferredOrder;
  }
  this._orderChanged();
};

/**
 * Returns the locator builders preferred order as an array
 */
LocatorBuilders.getPreferredOrder = function() {
  return this._preferredOrder;
};

/**
 * Sorts arrayToSort in the order of elements in sortOrderReference
 * @param arrayToSort
 * @param sortOrderReference
 */
LocatorBuilders._sortByRefOrder = function(arrayToSort, sortOrderReference) {
  let raLen = sortOrderReference.length;
  arrayToSort.sort(function(a, b) {
    let ai = sortOrderReference.indexOf(a);
    let bi = sortOrderReference.indexOf(b);
    return (ai > -1 ? ai : raLen) - (bi > -1 ? bi : raLen);
  });
};

/**
 * Function to add to the bottom of destArray elements from source array that do not exist in destArray
 * @param sourceArray
 * @param destArray
 */
LocatorBuilders._ensureAllPresent = function(sourceArray, destArray) {
  let changed = false;
  sourceArray.forEach(function(e) {
    if (destArray.indexOf(e) == -1) {
      destArray.push(e);
      changed = true;
    }
  });
  return changed;
};

/*
 * Utility function: Encode XPath attribute value.
 */
LocatorBuilders.prototype.attributeValue = function(value) {
  if (value.indexOf("'") < 0) {
    return "'" + value + "'";
  } else if (value.indexOf("\"") < 0) {
    return "\"" + value + "\"";
  } else {
    let result = "concat(";
    let part = "";
    let didReachEndOfValue = false;
    while (!didReachEndOfValue) {
      let apos = value.indexOf("'");
      let quot = value.indexOf("\"");
      if (apos < 0) {
        result += "'" + value + "'";
        didReachEndOfValue = true;
        break;
      } else if (quot < 0) {
        result += "\"" + value + "\"";
        didReachEndOfValue = true;
        break;
      } else if (quot < apos) {
        part = value.substring(0, apos);
        result += "'" + part + "'";
        value = value.substring(part.length);
      } else {
        part = value.substring(0, quot);
        result += "\"" + part + "\"";
        value = value.substring(part.length);
      }
      result += ",";
    }
    result += ")";
    return result;
  }
};

LocatorBuilders.prototype.xpathHtmlElement = function(name) {
  if (this.window.document.contentType == "application/xhtml+xml") {
    // "x:" prefix is required when testing XHTML pages
    return "x:" + name;
  } else {
    return name;
  }
};

LocatorBuilders.prototype.relativeXPathFromParent = function(current) {
  let index = this.getNodeNbr(current);
  let currentPath = "/" + this.xpathHtmlElement(current.nodeName.toLowerCase());
  if (index > 0) {
    currentPath += "[" + (index + 1) + "]";
  }
  return currentPath;
};

LocatorBuilders.prototype.getNodeNbr = function(current) {
  let childNodes = current.parentNode.childNodes;
  let total = 0;
  let index = -1;
  for (let i = 0; i < childNodes.length; i++) {
    let child = childNodes[i];
    if (child.nodeName == current.nodeName) {
      if (child == current) {
        index = total;
      }
      total++;
    }
  }
  return index;
};

LocatorBuilders.prototype.getCSSSubPath = function(e) {
  let css_attributes = ["id", "name", "class", "type", "alt", "title", "value"];
  for (let i = 0; i < css_attributes.length; i++) {
    let attr = css_attributes[i];
    let value = e.getAttribute(attr);
    if (value) {
      if (attr == "id")
        return "#" + value;
      if (attr == "class")
        return e.nodeName.toLowerCase() + "." + value.replace(" ", ".").replace("..", ".");
      return e.nodeName.toLowerCase() + "[" + attr + "=\"" + value + "\"]";
    }
  }
  if (this.getNodeNbr(e))
    return e.nodeName.toLowerCase() + ":nth-of-type(" + this.getNodeNbr(e) + ")";
  else
    return e.nodeName.toLowerCase();
};

LocatorBuilders.prototype.preciseXPath = function(xpath, e) {
  //only create more precise xpath if needed
  if (this.findElement(xpath) != e) {
    let result = e.ownerDocument.evaluate(xpath, e.ownerDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    //skip first element (result:0 xpath index:1)
    for (let i = 0, len = result.snapshotLength; i < len; i++) {
      let newPath = "xpath=(" + xpath + ")[" + (i + 1) + "]";
      if (this.findElement(newPath) == e) {
        return newPath;
      }
    }
  }
  return "xpath=" + xpath;
};

/*
 * ===== builders =====
 */

LocatorBuilders.add("id", function(e) {
  if (e.id) {
    return "id=" + e.id;
  }
  return null;
});

LocatorBuilders.add("linkText", function(e) {
  if (e.nodeName == "A") {
    let text = e.textContent;
    if (!text.match(/^\s*$/)) {
      return "linkText=" + text.replace(/\xA0/g, " ").replace(/^\s*(.*?)\s*$/, "$1");
    }
  }
  return null;
});

LocatorBuilders.add("name", function(e) {
  if (e.name) {
    return "name=" + e.name;
  }
  return null;
});

LocatorBuilders.add("css", function(e) {
  let current = e;
  let sub_path = this.getCSSSubPath(e);
  while (this.findElement("css=" + sub_path) != e && current.nodeName.toLowerCase() != "html") {
    sub_path = this.getCSSSubPath(current.parentNode) + " > " + sub_path;
    current = current.parentNode;
  }
  return "css=" + sub_path;
});

LocatorBuilders.add("css:finder", function(e) {
  return "css=" + finder(e);
});

LocatorBuilders.add("xpath:link", function(e) {
  if (e.nodeName == "A") {
    let text = e.textContent;
    if (!text.match(/^\s*$/)) {
      return this.preciseXPath("//" + this.xpathHtmlElement("a") + "[contains(text(),'" + text.replace(/^\s+/, "").replace(/\s+$/, "") + "')]", e);
    }
  }
  return null;
});

LocatorBuilders.add("xpath:img", function(e) {
  if (e.nodeName == "IMG") {
    if (e.alt != "") {
      return this.preciseXPath("//" + this.xpathHtmlElement("img") + "[@alt=" + this.attributeValue(e.alt) + "]", e);
    } else if (e.title != "") {
      return this.preciseXPath("//" + this.xpathHtmlElement("img") + "[@title=" + this.attributeValue(e.title) + "]", e);
    } else if (e.src != "") {
      return this.preciseXPath("//" + this.xpathHtmlElement("img") + "[contains(@src," + this.attributeValue(e.src) + ")]", e);
    }
  }
  return null;
});

LocatorBuilders.add("xpath:attributes", function(e) {
  const PREFERRED_ATTRIBUTES = ["id", "name", "value", "type", "action", "onclick"];
  let i = 0;

  function attributesXPath(name, attNames, attributes) {
    let locator = "//" + this.xpathHtmlElement(name) + "[";
    for (i = 0; i < attNames.length; i++) {
      if (i > 0) {
        locator += " and ";
      }
      let attName = attNames[i];
      locator += "@" + attName + "=" + this.attributeValue(attributes[attName]);
    }
    locator += "]";
    return this.preciseXPath(locator, e);
  }

  if (e.attributes) {
    let atts = e.attributes;
    let attsMap = {};
    for (i = 0; i < atts.length; i++) {
      let att = atts[i];
      attsMap[att.name] = att.value;
    }
    let names = [];
    // try preferred attributes
    for (i = 0; i < PREFERRED_ATTRIBUTES.length; i++) {
      let name = PREFERRED_ATTRIBUTES[i];
      if (attsMap[name] != null) {
        names.push(name);
        let locator = attributesXPath.call(this, e.nodeName.toLowerCase(), names, attsMap);
        if (e == this.findElement(locator)) {
          return locator;
        }
      }
    }
  }
  return null;
});

LocatorBuilders.add("xpath:idRelative", function(e) {
  let path = "";
  let current = e;
  while (current != null) {
    if (current.parentNode != null) {
      path = this.relativeXPathFromParent(current) + path;
      if (1 == current.parentNode.nodeType && // ELEMENT_NODE
        current.parentNode.getAttribute("id")) {
        return this.preciseXPath("//" + this.xpathHtmlElement(current.parentNode.nodeName.toLowerCase()) +
          "[@id=" + this.attributeValue(current.parentNode.getAttribute("id")) + "]" +
          path, e);
      }
    } else {
      return null;
    }
    current = current.parentNode;
  }
  return null;
});

LocatorBuilders.add("xpath:href", function(e) {
  if (e.attributes && e.hasAttribute("href")) {
    let href = e.getAttribute("href");
    if (href.search(/^http?:\/\//) >= 0) {
      return this.preciseXPath("//" + this.xpathHtmlElement("a") + "[@href=" + this.attributeValue(href) + "]", e);
    } else {
      // use contains(), because in IE getAttribute("href") will return absolute path
      return this.preciseXPath("//" + this.xpathHtmlElement("a") + "[contains(@href, " + this.attributeValue(href) + ")]", e);
    }
  }
  return null;
});

LocatorBuilders.add("xpath:position", function(e, opt_contextNode) {
  let path = "";
  let current = e;
  while (current != null && current != opt_contextNode) {
    let currentPath;
    if (current.parentNode != null) {
      currentPath = this.relativeXPathFromParent(current);
    } else {
      currentPath = "/" + this.xpathHtmlElement(current.nodeName.toLowerCase());
    }
    path = currentPath + path;
    let locator = "/" + path;
    if (e == this.findElement(locator)) {
      return "xpath=" + locator;
    }
    current = current.parentNode;
  }
  return null;
});
// Samit: Warning: The old method of setting the order using LocatorBuilders.order is now deprecated
// You can change the priority of builders by setting LocatorBuilders.order.
//LocatorBuilders.order = ['id', 'link', 'name', 'css', 'xpath:link', 'xpath:img', 'xpath:attributes', 'xpath:idRelative', 'xpath:href', 'xpath:position'];
<commit_msg>Swapped priority order of css locator builders so the new one takes lead<commit_after>/*
 * Copyright 2005 Shinya Kasatani
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//import { MozillaBrowserBot } from "./selenium-browserbot";
import { bot, core } from "./closure-polyfill";
import { parse_locator } from "./utils";
import finder from "@medv/finder";

export default function LocatorBuilders(window) {
  this.window = window;
}

window.LocatorBuilders = LocatorBuilders;

LocatorBuilders.prototype.detach = function() {
};

LocatorBuilders.prototype.buildWith = function(name, e, opt_contextNode) {
  return LocatorBuilders.builderMap[name].call(this, e, opt_contextNode);
};

LocatorBuilders.prototype.elementEquals = function(name, e, locator) {
  let fe = this.findElement(locator);
  //TODO: add match function to the ui locator builder, note the inverted parameters
  return (e == fe) || (LocatorBuilders.builderMap[name] && LocatorBuilders.builderMap[name].match && LocatorBuilders.builderMap[name].match(e, fe));
};

LocatorBuilders.prototype.build = function(e) {
  let locators = this.buildAll(e);
  if (locators.length > 0) {
    return locators[0][0];
  } else {
    return "LOCATOR_DETECTION_FAILED";
  }
};

LocatorBuilders.prototype.buildAll = function(el) {
  let e = core.firefox.unwrap(el); //Samit: Fix: Do the magic to get it to work in Firefox 4
  let locator;
  let locators = [];
  for (let i = 0; i < LocatorBuilders.order.length; i++) {
    let finderName = LocatorBuilders.order[i];
    try {
      locator = this.buildWith(finderName, e);
      if (locator) {
        locator = String(locator);
        //Samit: The following is a quickfix for above commented code to stop exceptions on almost every locator builder
        //TODO: the builderName should NOT be used as a strategy name, create a feature to allow locatorBuilders to specify this kind of behaviour
        //TODO: Useful if a builder wants to capture a different element like a parent. Use the this.elementEquals
        let fe = this.findElement(locator);
        if (e == fe) {
          locators.push([locator, finderName]);
        }
      }
    } catch (e) {
      // TODO ignore the buggy locator builder for now
      //this.log.debug("locator exception: " + e);
    }
  }
  return locators;
};

LocatorBuilders.prototype.findElement = function(loc) {
  try {
    const locator = parse_locator(loc, true);
    return bot.locators.findElement({ [locator.type]: locator.string }, this.window.document);
  } catch (error) {
    //this.log.debug("findElement failed: " + error + ", locator=" + locator);
    return null;
  }
};

/*
 * Class methods
 */

LocatorBuilders.order = [];
LocatorBuilders.builderMap = {};
LocatorBuilders._preferredOrder = [];
// NOTE: for some reasons we does not use this part
// classObservable(LocatorBuilders);

LocatorBuilders.add = function(name, finder) {
  this.order.push(name);
  this.builderMap[name] = finder;
  this._orderChanged();
};

/**
 * Call when the order or preferred order changes
 */
LocatorBuilders._orderChanged = function() {
  let changed = this._ensureAllPresent(this.order, this._preferredOrder);
  this._sortByRefOrder(this.order, this._preferredOrder);
  if (changed) {
    // NOTE: for some reasons we does not use this part
    // this.notify('preferredOrderChanged', this._preferredOrder);
  }
};

/**
 * Set the preferred order of the locator builders
 *
 * @param preferredOrder can be an array or a comma separated string of names
 */
LocatorBuilders.setPreferredOrder = function(preferredOrder) {
  if (typeof preferredOrder === "string") {
    this._preferredOrder = preferredOrder.split(",");
  } else {
    this._preferredOrder = preferredOrder;
  }
  this._orderChanged();
};

/**
 * Returns the locator builders preferred order as an array
 */
LocatorBuilders.getPreferredOrder = function() {
  return this._preferredOrder;
};

/**
 * Sorts arrayToSort in the order of elements in sortOrderReference
 * @param arrayToSort
 * @param sortOrderReference
 */
LocatorBuilders._sortByRefOrder = function(arrayToSort, sortOrderReference) {
  let raLen = sortOrderReference.length;
  arrayToSort.sort(function(a, b) {
    let ai = sortOrderReference.indexOf(a);
    let bi = sortOrderReference.indexOf(b);
    return (ai > -1 ? ai : raLen) - (bi > -1 ? bi : raLen);
  });
};

/**
 * Function to add to the bottom of destArray elements from source array that do not exist in destArray
 * @param sourceArray
 * @param destArray
 */
LocatorBuilders._ensureAllPresent = function(sourceArray, destArray) {
  let changed = false;
  sourceArray.forEach(function(e) {
    if (destArray.indexOf(e) == -1) {
      destArray.push(e);
      changed = true;
    }
  });
  return changed;
};

/*
 * Utility function: Encode XPath attribute value.
 */
LocatorBuilders.prototype.attributeValue = function(value) {
  if (value.indexOf("'") < 0) {
    return "'" + value + "'";
  } else if (value.indexOf("\"") < 0) {
    return "\"" + value + "\"";
  } else {
    let result = "concat(";
    let part = "";
    let didReachEndOfValue = false;
    while (!didReachEndOfValue) {
      let apos = value.indexOf("'");
      let quot = value.indexOf("\"");
      if (apos < 0) {
        result += "'" + value + "'";
        didReachEndOfValue = true;
        break;
      } else if (quot < 0) {
        result += "\"" + value + "\"";
        didReachEndOfValue = true;
        break;
      } else if (quot < apos) {
        part = value.substring(0, apos);
        result += "'" + part + "'";
        value = value.substring(part.length);
      } else {
        part = value.substring(0, quot);
        result += "\"" + part + "\"";
        value = value.substring(part.length);
      }
      result += ",";
    }
    result += ")";
    return result;
  }
};

LocatorBuilders.prototype.xpathHtmlElement = function(name) {
  if (this.window.document.contentType == "application/xhtml+xml") {
    // "x:" prefix is required when testing XHTML pages
    return "x:" + name;
  } else {
    return name;
  }
};

LocatorBuilders.prototype.relativeXPathFromParent = function(current) {
  let index = this.getNodeNbr(current);
  let currentPath = "/" + this.xpathHtmlElement(current.nodeName.toLowerCase());
  if (index > 0) {
    currentPath += "[" + (index + 1) + "]";
  }
  return currentPath;
};

LocatorBuilders.prototype.getNodeNbr = function(current) {
  let childNodes = current.parentNode.childNodes;
  let total = 0;
  let index = -1;
  for (let i = 0; i < childNodes.length; i++) {
    let child = childNodes[i];
    if (child.nodeName == current.nodeName) {
      if (child == current) {
        index = total;
      }
      total++;
    }
  }
  return index;
};

LocatorBuilders.prototype.getCSSSubPath = function(e) {
  let css_attributes = ["id", "name", "class", "type", "alt", "title", "value"];
  for (let i = 0; i < css_attributes.length; i++) {
    let attr = css_attributes[i];
    let value = e.getAttribute(attr);
    if (value) {
      if (attr == "id")
        return "#" + value;
      if (attr == "class")
        return e.nodeName.toLowerCase() + "." + value.replace(" ", ".").replace("..", ".");
      return e.nodeName.toLowerCase() + "[" + attr + "=\"" + value + "\"]";
    }
  }
  if (this.getNodeNbr(e))
    return e.nodeName.toLowerCase() + ":nth-of-type(" + this.getNodeNbr(e) + ")";
  else
    return e.nodeName.toLowerCase();
};

LocatorBuilders.prototype.preciseXPath = function(xpath, e) {
  //only create more precise xpath if needed
  if (this.findElement(xpath) != e) {
    let result = e.ownerDocument.evaluate(xpath, e.ownerDocument, null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
    //skip first element (result:0 xpath index:1)
    for (let i = 0, len = result.snapshotLength; i < len; i++) {
      let newPath = "xpath=(" + xpath + ")[" + (i + 1) + "]";
      if (this.findElement(newPath) == e) {
        return newPath;
      }
    }
  }
  return "xpath=" + xpath;
};

/*
 * ===== builders =====
 */

LocatorBuilders.add("id", function(e) {
  if (e.id) {
    return "id=" + e.id;
  }
  return null;
});

LocatorBuilders.add("linkText", function(e) {
  if (e.nodeName == "A") {
    let text = e.textContent;
    if (!text.match(/^\s*$/)) {
      return "linkText=" + text.replace(/\xA0/g, " ").replace(/^\s*(.*?)\s*$/, "$1");
    }
  }
  return null;
});

LocatorBuilders.add("name", function(e) {
  if (e.name) {
    return "name=" + e.name;
  }
  return null;
});

LocatorBuilders.add("css:finder", function(e) {
  return "css=" + finder(e);
});

LocatorBuilders.add("css", function(e) {
  let current = e;
  let sub_path = this.getCSSSubPath(e);
  while (this.findElement("css=" + sub_path) != e && current.nodeName.toLowerCase() != "html") {
    sub_path = this.getCSSSubPath(current.parentNode) + " > " + sub_path;
    current = current.parentNode;
  }
  return "css=" + sub_path;
});

LocatorBuilders.add("xpath:link", function(e) {
  if (e.nodeName == "A") {
    let text = e.textContent;
    if (!text.match(/^\s*$/)) {
      return this.preciseXPath("//" + this.xpathHtmlElement("a") + "[contains(text(),'" + text.replace(/^\s+/, "").replace(/\s+$/, "") + "')]", e);
    }
  }
  return null;
});

LocatorBuilders.add("xpath:img", function(e) {
  if (e.nodeName == "IMG") {
    if (e.alt != "") {
      return this.preciseXPath("//" + this.xpathHtmlElement("img") + "[@alt=" + this.attributeValue(e.alt) + "]", e);
    } else if (e.title != "") {
      return this.preciseXPath("//" + this.xpathHtmlElement("img") + "[@title=" + this.attributeValue(e.title) + "]", e);
    } else if (e.src != "") {
      return this.preciseXPath("//" + this.xpathHtmlElement("img") + "[contains(@src," + this.attributeValue(e.src) + ")]", e);
    }
  }
  return null;
});

LocatorBuilders.add("xpath:attributes", function(e) {
  const PREFERRED_ATTRIBUTES = ["id", "name", "value", "type", "action", "onclick"];
  let i = 0;

  function attributesXPath(name, attNames, attributes) {
    let locator = "//" + this.xpathHtmlElement(name) + "[";
    for (i = 0; i < attNames.length; i++) {
      if (i > 0) {
        locator += " and ";
      }
      let attName = attNames[i];
      locator += "@" + attName + "=" + this.attributeValue(attributes[attName]);
    }
    locator += "]";
    return this.preciseXPath(locator, e);
  }

  if (e.attributes) {
    let atts = e.attributes;
    let attsMap = {};
    for (i = 0; i < atts.length; i++) {
      let att = atts[i];
      attsMap[att.name] = att.value;
    }
    let names = [];
    // try preferred attributes
    for (i = 0; i < PREFERRED_ATTRIBUTES.length; i++) {
      let name = PREFERRED_ATTRIBUTES[i];
      if (attsMap[name] != null) {
        names.push(name);
        let locator = attributesXPath.call(this, e.nodeName.toLowerCase(), names, attsMap);
        if (e == this.findElement(locator)) {
          return locator;
        }
      }
    }
  }
  return null;
});

LocatorBuilders.add("xpath:idRelative", function(e) {
  let path = "";
  let current = e;
  while (current != null) {
    if (current.parentNode != null) {
      path = this.relativeXPathFromParent(current) + path;
      if (1 == current.parentNode.nodeType && // ELEMENT_NODE
        current.parentNode.getAttribute("id")) {
        return this.preciseXPath("//" + this.xpathHtmlElement(current.parentNode.nodeName.toLowerCase()) +
          "[@id=" + this.attributeValue(current.parentNode.getAttribute("id")) + "]" +
          path, e);
      }
    } else {
      return null;
    }
    current = current.parentNode;
  }
  return null;
});

LocatorBuilders.add("xpath:href", function(e) {
  if (e.attributes && e.hasAttribute("href")) {
    let href = e.getAttribute("href");
    if (href.search(/^http?:\/\//) >= 0) {
      return this.preciseXPath("//" + this.xpathHtmlElement("a") + "[@href=" + this.attributeValue(href) + "]", e);
    } else {
      // use contains(), because in IE getAttribute("href") will return absolute path
      return this.preciseXPath("//" + this.xpathHtmlElement("a") + "[contains(@href, " + this.attributeValue(href) + ")]", e);
    }
  }
  return null;
});

LocatorBuilders.add("xpath:position", function(e, opt_contextNode) {
  let path = "";
  let current = e;
  while (current != null && current != opt_contextNode) {
    let currentPath;
    if (current.parentNode != null) {
      currentPath = this.relativeXPathFromParent(current);
    } else {
      currentPath = "/" + this.xpathHtmlElement(current.nodeName.toLowerCase());
    }
    path = currentPath + path;
    let locator = "/" + path;
    if (e == this.findElement(locator)) {
      return "xpath=" + locator;
    }
    current = current.parentNode;
  }
  return null;
});
// Samit: Warning: The old method of setting the order using LocatorBuilders.order is now deprecated
// You can change the priority of builders by setting LocatorBuilders.order.
//LocatorBuilders.order = ['id', 'link', 'name', 'css', 'xpath:link', 'xpath:img', 'xpath:attributes', 'xpath:idRelative', 'xpath:href', 'xpath:position'];
<|endoftext|>