package com.codeborne.selenide.impl;
import org.apache.commons.io.IOUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.By.ByCssSelector;
import org.openqa.selenium.SearchContext;
import org.openqa.selenium.WebDriverException;
import org.openqa.selenium.WebElement;
import java.io.IOException;
import java.util.List;
import static com.codeborne.selenide.Configuration.SelectorMode.CSS;
import static com.codeborne.selenide.Configuration.selectorMode;
import static com.codeborne.selenide.Selenide.executeJavaScript;
import static java.lang.Thread.currentThread;
/**
* Thanks to http://selenium.polteq.com/en/injecting-the-sizzle-css-selector-library/
*/
public class WebElementSelector {
public static WebElementSelector instance = new WebElementSelector();
protected String sizzleSource;
public WebElement findElement(SearchContext context, By selector) {
if (selectorMode == CSS || !(selector instanceof ByCssSelector)) {
return context.findElement(selector);
}
List<WebElement> webElements = evaluateSizzleSelector(context, (ByCssSelector) selector);
return webElements.isEmpty() ? null : webElements.get(0);
}
public List<WebElement> findElements(SearchContext context, By selector) {
if (selectorMode == CSS || !(selector instanceof ByCssSelector)) {
return context.findElements(selector);
}
return evaluateSizzleSelector(context, (ByCssSelector) selector);
}
protected List<WebElement> evaluateSizzleSelector(SearchContext context, ByCssSelector sizzleCssSelector) {
injectSizzleIfNeeded();
String sizzleSelector = sizzleCssSelector.toString()
.replace("By.selector: ", "")
.replace("By.cssSelector: ", "");
if (context instanceof WebElement)
return executeJavaScript("return Sizzle(arguments[0], arguments[1])", sizzleSelector, context);
else
return executeJavaScript("return Sizzle(arguments[0])", sizzleSelector);
}
protected void injectSizzleIfNeeded() {
if (!sizzleLoaded()) {
injectSizzle();
}
}
protected Boolean sizzleLoaded() {
try {
return executeJavaScript("return typeof Sizzle != 'undefined'");
} catch (WebDriverException e) {
return false;
}
}
protected synchronized void injectSizzle() {
if (sizzleSource == null) {
try {
sizzleSource = IOUtils.toString(currentThread().getContextClassLoader().getResource("sizzle.js"));
} catch (IOException e) {
throw new RuntimeException("Cannot load sizzle.js from classpath", e);
}
}
executeJavaScript(sizzleSource);
}
}