diff --git a/ide/main/src/content/debugger.js b/ide/main/src/content/debugger.js
index dc5653f869980..1c8c1038bcaf5 100644
--- a/ide/main/src/content/debugger.js
+++ b/ide/main/src/content/debugger.js
@@ -205,6 +205,53 @@ Debugger.prototype.showElement = function (locator) {
this.runner.showElement(locator);
};
+Debugger.prototype.selectElement = function () {
+ this.init();
+ var button = document.getElementById("selectElementButton");
+ var help = document.getElementById("selectElementTip");
+ if (this.targetSelecter) {
+ this.targetSelecter.cleanup();
+ this.targetSelecter = null;
+ return;
+ }
+ var self = this;
+ var isRecording = this.editor.recordingEnabled;
+ if (isRecording) {
+ this.editor.setRecordingEnabled(false);
+ }
+ button.label = "Cancel";
+ help.removeAttribute("style");
+ this.targetSelecter = new TargetSelecter(function (element, win) {
+ if (element && win) {
+ var locatorBuilders = new LocatorBuilders(win);
+ var target = locatorBuilders.buildAll(element);
+ locatorBuilders.detach();
+ if (target != null && target instanceof Array) {
+ if (target[0]) {
+ self.editor.treeView.updateCurrentCommand('targetCandidates', target);
+ } else {
+ alert("LOCATOR_DETECTION_FAILED");
+ }
+ }
+
+ }
+ self.targetSelecter = null;
+ }, function () {
+ button.label = "Select";
+ help.setAttribute("style", "display: none;");
+ if (isRecording) {
+ self.editor.setRecordingEnabled(true);
+ }
+ });
+};
+
+Debugger.prototype.unload = function () {
+ if (this.targetSelecter) {
+ this.targetSelecter.cleanup();
+ this.targetSelecter = null;
+ }
+};
+
/*
* Use to reload the Selenium Core API
* and its overrides and extensions (user-extensions file)
diff --git a/ide/main/src/content/editor.js b/ide/main/src/content/editor.js
index c75ce656fa6e5..13b9c1b442bdb 100644
--- a/ide/main/src/content/editor.js
+++ b/ide/main/src/content/editor.js
@@ -501,6 +501,7 @@ Editor.prototype.log = Editor.log = new Log("Editor");
Editor.prototype.unload = function () {
this.app.saveState();
+ this.selDebugger.unload();
this.deregisterRecorder();
top.controllers.removeController(Editor.controller);
diff --git a/ide/main/src/content/selenium-ide.xul b/ide/main/src/content/selenium-ide.xul
index 2d7728fdfa48f..37e2484a7b318 100644
--- a/ide/main/src/content/selenium-ide.xul
+++ b/ide/main/src/content/selenium-ide.xul
@@ -132,12 +132,19 @@ limitations under the License.
-
+
-
+
+
+ Select an element by clicking on it in the browser or click Cancel to cancel.
+
+
diff --git a/ide/main/src/content/tools.js b/ide/main/src/content/tools.js
index e48933596a54c..929ac4d311b66 100644
--- a/ide/main/src/content/tools.js
+++ b/ide/main/src/content/tools.js
@@ -316,3 +316,83 @@ function defineEnum(clazz, names) {
function $(id) {
return document.getElementById(id);
}
+
+function TargetSelecter(callback, cleanupCallback) {
+ this.callback = callback;
+ this.cleanupCallback = cleanupCallback;
+ var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"].getService(Components.interfaces.nsIWindowMediator);
+ this.win = wm.getMostRecentWindow('navigator:browser').getBrowser().contentWindow;
+ var doc = this.win.document;
+ var div = doc.createElement("div");
+ div.setAttribute("style", "display: none;");
+ doc.body.insertBefore(div, doc.body.firstChild);
+ this.div = div;
+ this.e = null;
+ this.r = null;
+ doc.addEventListener("mousemove", this, true);
+ doc.addEventListener("click", this, true);
+}
+
+TargetSelecter.prototype.cleanup = function () {
+ if (this.div) {
+ if (this.div.parentNode) {
+ this.div.parentNode.removeChild(this.div);
+ }
+ this.div = null;
+ }
+ if (this.win) {
+ var doc = this.win.document;
+ doc.removeEventListener("mousemove", this, true);
+ doc.removeEventListener("click", this, true);
+ this.win = null;
+ }
+ if (this.cleanupCallback) {
+ this.cleanupCallback();
+ }
+};
+
+TargetSelecter.prototype.handleEvent = function (evt) {
+ switch (evt.type) {
+ case "mousemove":
+ this.highlight(evt.target.ownerDocument, evt.clientX, evt.clientY);
+ break;
+ case "click":
+ if (evt.button == 0 && this.e && this.callback) {
+ this.callback(this.e, this.win);
+ } //Right click would cancel the select
+ evt.preventDefault();
+ evt.stopPropagation();
+ this.cleanup();
+ break;
+ }
+};
+
+TargetSelecter.prototype.highlight = function (doc, x, y) {
+ if (doc) {
+ var e = doc.elementFromPoint(x, y);
+ if (e && e != this.e) {
+ this.highlightElement(e);
+ }
+ }
+}
+
+TargetSelecter.prototype.highlightElement = function (element) {
+ if (element && element != this.e) {
+ this.e = element;
+ } else {
+ return;
+ }
+ var r = element.getBoundingClientRect();
+ var or = this.r;
+ if (r.left >= 0 && r.top >= 0 && r.width > 0 && r.height > 0) {
+ if (or && r.top == or.top && r.left == or.left && r.width == or.width && r.height == or.height) {
+ return;
+ }
+ this.r = r;
+ var style = "pointer-events: none; position: absolute; box-shadow: 0 0 0 1px black; outline: 1px dashed white; outline-offset: -1px; background-color: rgba(250,250,128,0.4); z-index: 100;";
+ var pos = "top:" + (r.top + this.win.scrollY) + "px; left:" + (r.left + this.win.scrollX) + "px; width:" + r.width + "px; height:" + r.height + "px;";
+ this.div.setAttribute("style", style + pos);
+ } else if (or) {
+ this.div.setAttribute("style", "display: none;");
+ }
+};
diff --git a/ide/main/src/content/treeView.js b/ide/main/src/content/treeView.js
index f2d5774300c13..cce31f6016a60 100644
--- a/ide/main/src/content/treeView.js
+++ b/ide/main/src/content/treeView.js
@@ -128,6 +128,12 @@ objectExtend(TreeView.prototype, {
this.document.getElementById(id).disabled = disabled;
},
+ updateTarget: function(value, disabled) {
+ this.setTextBox("commandTarget", value, disabled);
+ this.document.getElementById('selectElementButton').disabled = disabled;
+ this.document.getElementById('findElementButton').disabled = disabled;
+ },
+
getCommand: function(row) {
if (row < this.testCase.commands.length) {
return this.testCase.commands[row];
@@ -225,11 +231,11 @@ objectExtend(TreeView.prototype, {
Editor.GENERIC_AUTOCOMPLETE.setCandidatesWithComments(XulUtils.toXPCOMString(this.editor.getAutoCompleteSearchParam("commandTarget")),
XulUtils.toXPCOMArray(locators),
XulUtils.toXPCOMArray(types));
- this.setTextBox("commandTarget", this.encodeText(command.target), false);
+ this.updateTarget(this.encodeText(command.target), false);
} else {
targetBox.setAttribute("enablehistory", "false");
targetBox.disableAutoComplete = true;
- this.setTextBox("commandTarget", this.encodeText(command.target), false);
+ this.updateTarget(this.encodeText(command.target), false);
}
},
@@ -325,7 +331,7 @@ objectExtend(TreeView.prototype, {
this.setTextBox("commandValue", this.encodeText(command.value), false);
} else if (command.type == 'comment') {
this.setTextBox("commandAction", command.comment, false);
- this.setTextBox("commandTarget", '', true);
+ this.updateTarget('', true);
this.setTextBox("commandValue", '', true);
}
@@ -335,7 +341,7 @@ objectExtend(TreeView.prototype, {
this.editor.showRollupReference(command);
} else {
this.setTextBox("commandAction", '', true);
- this.setTextBox("commandTarget", '', true);
+ this.updateTarget('', true);
this.setTextBox("commandValue", '', true);
this.currentCommand = null;
}
@@ -355,6 +361,13 @@ objectExtend(TreeView.prototype, {
this.updateSeleniumTargets();
this.editor.showReference(this.currentCommand);
}
+ else if (key == 'targetCandidates') {
+ this.updateSeleniumTargets();
+ if (value != null && value instanceof Array && value[0]) {
+ this.updateCurrentCommand('target', value[0][0]);
+ this.selectCommand();
+ }
+ }
else if (key == 'target') {
this.updateSeleniumValues();
this.editor.showUIReference(value);
@@ -367,7 +380,7 @@ objectExtend(TreeView.prototype, {
},
onHide: function() {
this.setTextBox("commandAction", '', true);
- this.setTextBox("commandTarget", '', true);
+ this.updateTarget('', true);
this.setTextBox("commandValue", '', true);
this.currentCommand = null;
},
@@ -672,7 +685,9 @@ TreeView.UpdateCommandAction.prototype = {
this.treeView.treebox.rowCountChanged(this.treeView.rowCount - 1, -1);
this.treeView.rowCount--;
this.treeView.log.debug("removed new command");
- }
+ } else if (this.index == this.treeView.tree.currentIndex) {
+ this.treeView.selectCommand();
+ }
}
}