All Downloads are FREE. Search and download functionalities are using the official Maven repository.

geb.navigator.CssSelector.groovy Maven / Gradle / Ivy

Go to download

Geb (pronounced "jeb") is a browser automation solution. It brings together the power of WebDriver, the elegance of jQuery content selection, the robustness of Page Object modelling and the expressiveness of the Groovy language.

There is a newer version: 0.7.2
Show newest version
package geb.navigator

import org.openqa.selenium.By
import org.openqa.selenium.WebElement
import static java.util.Collections.EMPTY_LIST
import static geb.navigator.SelectorType.*

class CssSelector {

	private static final CssSelector DESCENDANT_SELECTOR = new CssSelector(SelectorType.DESCENDANT, " ")
	private static final String CSS_SELECTOR_SPECIAL_CHARS_PATTERN = '[!"#$%&\'\\(\\)*+,./:;<=>?@\\[\\]^`\\{|\\}~\\\\]'

	final SelectorType type
	final String value

	CssSelector() {
		super()
	}

	CssSelector(SelectorType type, String value) {
		this.type = type
		this.value = value
	}

	// TODO: better name

	static List findByCssSelector(Collection elements, String selectorString) {
		def result = []
		CssSelector.compile(selectorString).each { List selectorGroup ->
			def context = elements
			boolean descend = true
			selectorGroup.each { CssSelector selector ->
				if (selector.type == SelectorType.DESCENDANT) {
					descend = true
				} else {
					context = context.inject([]) { list, element ->
						list.addAll selector.apply(element, descend)
						list
					}
					descend = false
				}
			}
			result += context
		}
		return result
	}

	static String escape(String value) {
		value.replaceAll("($CSS_SELECTOR_SPECIAL_CHARS_PATTERN)", '\\\\$1')
	}
	
	static boolean matches(WebElement element, String selectorString) {
		def selectors = compile(selectorString)
		selectors.any { List selectorGroup ->
			selectorGroup.every { CssSelector selector ->
				selector.matches(element)
			}
		}
	}

	List apply(WebElement element, boolean descend) {
		if (descend) {
			return select(element)
		} else {
			return matches(element) ? [element] : EMPTY_LIST
		}
	}

	boolean matches(WebElement element) {
		// TODO: switch = failure of object orientation
		switch (type) {
			case ELEMENT:
				return element.tagName == value
			case HTML_CLASS:
				return element.getAttribute("class") =~ /(^|\s)$value($|\s)/
			case ID:
				return element.getAttribute("id") == value
			default:
				return false
		}
	}

	List select(WebElement element) {
		switch (type) {
			case ELEMENT:
				return element.findElements(By.tagName(value))
			case HTML_CLASS:
				return element.findElements(By.className(value))
			case ID:
				return element.findElements(By.id(value))
			default:
				return EMPTY_LIST
		}
	}

	String toString() {
		"${type.prefix}$value"
	}

	// TODO: should be private

	static List> compile(String groupSelector) {
		List> result = []
		groupSelector.split(",").each { String part ->
			part = part.trim()
			if (part) {
				List compiled = compileSingle(part)
				if (compiled) {
					result << compiled
				}
			}
		}
		return result
	}

	private static List compileSingle(String selector) {
		List result = []
		boolean first = true
		selector.split(/\s/).each { String part ->
			part = part.trim()
			if (part) {
				if (first) {
					first = false
				} else {
					result << DESCENDANT_SELECTOR
				}
				compileSimpleSelector(part, result)
			}
		}
		return result
	}

	private static void compileSimpleSelector(String selector, List list) {
		tokenize(selector).each { String part ->
			if (part) {
				if (part.startsWith(".")) {
					list << new CssSelector(SelectorType.HTML_CLASS, part.substring(1))
				} else if (part.startsWith("#")) {
					list << new CssSelector(SelectorType.ID, part.substring(1))
				} else {
					list << new CssSelector(SelectorType.ELEMENT, part)
				}
			}
		}
	}

	private static List tokenize(String selector) {
		List tokens = []
		int previous = 0
		int max = selector.length()
		for (int index = 0; index < max; ++index) {
			char character = selector.charAt(index)
			if (index > 0 && (character == '.' || character == '#')) {
				tokens << selector.substring(previous, index)
				previous = index
			}
		}
		tokens << selector.substring(previous)
		return tokens
	}
}

enum SelectorType {
	ELEMENT(""),
	HTML_CLASS("."),
	ID("#"),
	DESCENDANT("")

	final prefix

	SelectorType(String prefix) {
		this.prefix = prefix
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy