I am creating an interactive map that allows the user to select year from timeline and filter events, this is done via XML HttpRequest that redraws the SVG everytime.
The SVG code for the map, including the JavaScript functions to zoom and the tooltip are re written everytime the user selects the year/filter. The code is a string in Java as it relies on if statements. However, whenever the user selects the year/filter the JavaScript functions do not work. The JavaScript code is repeated three times in the one class in separate if statements
This is the XML http Request code:
var year_selected = document.getElementById('year').innerHTML;
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("map").innerHTML = xhttp.responseText;
}
};
xhttp.open("GET", "/BCMapYear.html/"+year_selected, true);
xhttp.send();
JavaScript:
"<script type=\"text/javascript\">" +
"var transformMatrix = [1,0,0,1,0,0];"+
"var svg = document.getElementById('svg-map');"+
"var viewBox = svg.getAttributeNS(null, \"viewBox\").split(\" \");"+
"var centerX = parseFloat(viewBox[2])/2;"+
"var centerY = parseFloat(viewBox[3])/2;"+
"var matrixGroup = svg.getElementById(\"matrix-group\");"+
"var origMatrix = [1,0,0,1,0,0];"+
"function reset() {\n" +
" for(var i = 0; i < 6; i++) {\n" +
" transformMatrix[i] = origMatrix[i];\n" +
" } \n" +
" var newMatrix = \"matrix(\"+ transformMatrix.join(' ') + \")\";\n" +
" matrixGroup.setAttributeNS(null, \"transform\", newMatrix); \n" +
" \n" +
" };"+
"function pan(dx, dy) {"+
"transformMatrix[4] += dx;"+
"transformMatrix[5] += dy;"+
"var newMatrix = \"matrix(\"+ transformMatrix.join(' ') + \")\";"+
"matrixGroup.setAttributeNS(null, \"transform\", newMatrix);"+
"}"+
"function zoom(scale) {"+
"for(var i = 0; i < 4; i++) {"+
"transformMatrix[i] *= scale;"+
"}"+
"transformMatrix[4] += (1-scale) * centerX;"+
"transformMatrix[5] += (1-scale)* centerY;"+
"var newMatrix = \"matrix(\"+ transformMatrix.join(' ') + \")\";"+
"matrixGroup.setAttributeNS(null, \"transform\", newMatrix);"+
"}"+
"</script>"
+"<script type=\"text/ecmascript\">\n" +
" (function() {\n" +
" var svg = document.getElementById('svg-map');\n" +
" var tooltip = svg.getElementById('tooltip');\n" +
" var tooltipText0 = document.getElementById('tooltiptext0').firstChild;\n" +
" var tooltipText1 = document.getElementById('tooltiptext1').firstChild;\n" +
" var tooltipText2 = document.getElementById('tooltiptext2').firstChild;\n" +
" var tooltipText3 = document.getElementById('tooltiptext3').firstChild;\n" +
" var triggers = svg.getElementsByClassName('tooltip-trigger');\n" +
" for (var i = 0; i < triggers.length; i++) {\n" +
" triggers[i].addEventListener('mousemove', showTooltip);\n" +
" triggers[i].addEventListener('mouseout', hideTooltip);\n" +
" }\n" +
" function showTooltip(evt) {\n" +
" var CTM = svg.getScreenCTM();\n" +
" var x = (evt.clientX - CTM.e + 6) / CTM.a;\n" +
" var y = (evt.clientY - CTM.f + 20) / CTM.d;\n" +
" tooltip.setAttributeNS(null, \"transform\", \"translate(\" + x + \" \" + y + \")\");\n" +
" tooltip.setAttributeNS(null, \"visibility\", \"visible\");\n" +
" tooltipText0.data = evt.target.getAttributeNS(null, \"data-tooltip-text0\");\n" +
" tooltipText1.data = evt.target.getAttributeNS(null, \"data-tooltip-text1\");\n" +
" tooltipText2.data =
evt.target.getAttributeNS(null, \"data-tooltip-text2\");\n" +
" tooltipText3.data =
evt.target.getAttributeNS(null, \"data-tooltip-text3\");\n" +
" }\n" +
" function hideTooltip(evt) {\n" +
"
tooltip.setAttributeNS(null, \"visibility\", \"hidden\");\n" +
" }\n" +
" })()" +
" </script>";
On the Console it comes up uncaught referenceerror zoom is not defined
You can add (); after your block that you want executed.
(function(){
//Bunch of code...
})();
Related
Description: A complex structure of HTML elements (rectangles) displayed on the screen, no overlaps, each rectangle having a distinct HTML id attribute (hence pickable by Selenium IWebDriver and C# code).
Target: I need programatically with Selenium and C# to create and trigger mousewheel event (via IJavaScriptExecutor or some other methods) on a selected rectangle element.
Q: How this can be done? Thank you
This is my implementation after investigating
//wheelTicks: negative for zoomin, positive to zoomout
public object zoomElementById(string elemId, int wheelTicks=1)
{
object response = null;
string myJavaScript =
// Callback (place in first!) used to notify the caller that the async callee is ready
" var callback = arguments[arguments.length - 1]; " +
" var maxIntervals = arguments[1]; " +
//ms
" var intervalDuration = 150; " +
" console.log('javascripting...', callback, arguments); " +
"var d = new Date(); " +
"var n = d.getTime(); " +
" var myZoomCenterElement = document.getElementById('" + elemId + "'); " +
// some debug output in the console
" console.log(myZoomCenterElement); " +
// *** THE CORE OF THE SOLUTION *** Creates proper WheelEvent object and triggers WheelEvent(Zoom)
" var box = myZoomCenterElement.getBoundingClientRect(); " +
" var boxMiddleX = Math.round((box.right + box.left )/2); " +
" var boxMiddleY = Math.round((box.bottom + box.top )/2); " +
" var myWheelableElement = document.getElementsByClassName('svg-tree-view')[0]; " +
" var wheelEventInitDict = { " +
" 'deltaX' : 0.0, " +
" 'deltaY' : -200.0, " +
" 'deltaZ' : 0.0, " +
" 'deltaMode' : 0, " +
" 'clientX' : boxMiddleX, " +
" 'clientY' : boxMiddleY " +
" }; " +
" var myWheelEvent = new WheelEvent('wheel', wheelEventInitDict); " +
" console.log(wheelEventInitDict, boxMiddleX, boxMiddleY, myWheelEvent); " +
" var myIntervalCounter = 0; " +
" var myInterval = setInterval(function(){ " +
" myWheelableElement.dispatchEvent(myWheelEvent); " +
" myIntervalCounter++; " +
" if (myIntervalCounter > maxIntervals) clearInterval(myInterval); " +
" }, intervalDuration); " +
" var sthToReturn = 'Returning: Nothing requested!'; " +
" var asyncAwaitInMiliSeconds = Math.ceil( 1.2 * intervalDuration * maxIntervals ); " +
// Triggers the callback (to indicate async ready)
" setTimeout( function(){ " +
" console.log((new Date()).getTime()-n); " +
" callback(sthToReturn); " +
" }, asyncAwaitInMiliSeconds); " +
""
;
_driver.Manage().Timeouts().SetScriptTimeout(new TimeSpan(0, 0, 20));
IJavaScriptExecutor js = _driver as IJavaScriptExecutor;
try
{
// addititonal args(optional) to be sent to the javascript func are put after the first arg
return response = js.ExecuteAsyncScript(myJavaScript, elemId, wheelTicks);
}
catch(UnhandledAlertException e)
{
Console.WriteLine("Error Occured! \n {0}", e.ToString() );
return null;
}
}
After loading this code into webView:
String fun = "javascript:function getTextPage(){" +
" if(document.caretRangeFromPoint){" +
" var caretRangeStart = document.caretRangeFromPoint(0, 0);\n" +
" var caretRangeEnd = document.caretRangeFromPoint(window.innerWidth, window.innerHeight);\n" +
" } else {\n" +
" return null;\n" +
" }" +
" var range = document.createRange();\n" +
" range.setStart(caretRangeStart.startContainer, caretRangeStart.startOffset);\n" +
" range.setEnd(caretRangeEnd.endContainer, caretRangeEnd.endOffset);\n" +
" alert(range.toString());" +
"};";
loadUrl(fun);
loadUrl("javascript:getTextPage()");
method findAll() or findAllAsync() find text but doesn't highlisht it
Instead of looping through one time to show
id1
id2
id3
it loops through 3 times before stopping. what can i put to make it loop through only once.
html:
<p id="show_me"></p>
<button onclick="ObjectArray()">click me</button>
javascript:
var ObjectArray = function() {
// object literal
var id1 = {
firstName: "John",
lastName: "Doe",
id: "12345"
};
// keyword new
var id2 = new Object;
id2.firstName = "Adam";
id2.lastName = "Bakely";
id2.id = "abcdef";
// object constructor
function employee(first, last, id) {
this.firstName = first;
this.lastName = last;
this.id = id;
}
var id3 = new employee("Dallas", "Star", "abc123");
//create an array
var IdArray = [id1, id2, id3];
//for loop to display results
var text="";
var i;
for (i = 0; i < IdArray.length; i++){
text += IdArray[0].firstName + " " + IdArray[0].lastName + " " + IdArray[0].id + "<br>";
text += IdArray[1].firstName + " " + IdArray[1].lastName + " " + IdArray[1].id + "<br>";
text += IdArray[2].firstName + " " + IdArray[2].lastName + " " + IdArray[2].id + "<br>";
}
document.getElementById("show_me").innerHTML = text;
}
It iterates three times, because you loop for the length of the array, which has 3 items.
If you want to 'iterate' once, you can just omit the for loop:
text += IdArray[0].firstName + " " + IdArray[0].lastName + " " + IdArray[0].id + "<br>";
text += IdArray[1].firstName + " " + IdArray[1].lastName + " " + IdArray[1].id + "<br>";
text += IdArray[2].firstName + " " + IdArray[2].lastName + " " + IdArray[2].id + "<br>";
But I think you actually wanted to do this:
for (i = 0; i < IdArray.length; i++){
text += IdArray[i].firstName + " " + IdArray[i].lastName + " " + IdArray[i].id + "<br>";
}
That way you use the loop what it's for: Iterate over an array of any length and repeat a piece of code for each item in the array.
Remove everything from the for loop, and add this instead:
text += IdArray[i].firstName + " " + IdArray[i].lastName + " " + IdArray[i].id + "<br>";
Every thing is fine ... but please replaced the following code
for (i = 0; i < IdArray.length; i++){
text += IdArray[i].firstName + " " + IdArray[i].lastName + " " + IdArray[i].id + "<br>";
text += IdArray[1].firstName + " " + IdArray[1].lastName + " " + IdArray[1].id + "<br>";
text += IdArray[2].firstName + " " + IdArray[2].lastName + " " + IdArray[2].id + "<br>";
}
with
for (i = 0; i < IdArray.length; i++){
text += IdArray[i].firstName + " " + IdArray[i].lastName + " " + IdArray[i].id + "<br>";
}
This code should work. Why doesn't it?
<!DOCTYPE html>
<body>
<h1> The "^" operator in Javascript </h1>
<p id = "foo"></p>
<script>
function f(){
//vars
var a = 5;
var b = 13;
var c = a ^ b;
var binA = a.toString(2);
var binB = b.toString(2);
var binC = c.toString(2);
var strA = a.toString();
var strB = b.toString();
var strC = c.toString();
//make output string
var lineA = "a = " + strA + " = " binA + ", ";
var lineB = "b = " + strB + " = " binB + ", ";
var lineC = "c = " + strC + " = " binC + ", ";
var outputStr = lineA + lineB + lineC;
//output
document.getElementById("foo").innerHTML = outputStr;
}
f();
// For some reason this shows the contents of the header only
</script>
</body>
I did the toString() conversions on a, b and c because I can't understand why the output is failing to display in Google Chrome. I recognize they should not be necessary. But I wanted to make the code as kosher as possible. I have concatenated the string as substrings because in a previous iteration of this code, commenting out the 'C' section of the string concatenation allowed the 'A' and 'B' related sections of the output string to display. Plus it keeps the visual format regular which I am trying to use to error-check.
Updated the code, you have missed out '+'
See this fiddle
var lineA = "a = " + strA + " = " + binA + ", ";
var lineB = "b = " + strB + " = " + binB + ", ";
var lineC = "c = " + strC + " = " + binC + ", ";
var outputStr = lineA + lineB + lineC;
There is a syntax error, you missed '+' before the binA, binB and binC
var lineA = "a = " + strA + " = " + binA + ", ";
var lineB = "b = " + strB + " = " + binB + ", ";
var lineC = "c = " + strC + " = " + binC + ", ";
var outputStr = lineA + lineB + lineC;
output prints as below when I fixed that error in ff and chrome
a = 5 = 101, b = 13 = 1101, c = 8 = 1000,
It's because you're missing the + marks before binA, binB, and binC on lines 24, 25, and 26 :) You have some invalid javascript, and it's throwing an error in the console.
You are making syntax error in javascript. Replace your output string block with
//make output string
var lineA = "a = " + strA + " = "+ binA + ", ";
var lineB = "b = " + strB + " = "+ binB + ", ";
var lineC = "c = " + strC + " = "+ binC + ", ";
var outputStr = lineA + lineB + lineC;
It will work for you. Thanks
So I was asked to create a way to auto set the owner of the Order to the current user and not the default owner of the account that maps over.
Also, I had to make it only run in the instance that the user is Creating an order.
So I started with this:
try{
var xml = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
" <soap:Body>" +
" <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
" <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
" <q1:EntityName>systemuser</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>businessunitid</q1:Attribute>" +
" <q1:Attribute>firstname</q1:Attribute>" +
" <q1:Attribute>fullname</q1:Attribute>" +
" <q1:Attribute>lastname</q1:Attribute>" +
" <q1:Attribute>organizationid</q1:Attribute>" +
" <q1:Attribute>systemuserid</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
" <q1:Criteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>systemuserid</q1:AttributeName>" +
" <q1:Operator>EqualUserId</q1:Operator>" +
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:Criteria>" +
" </query>" +
" </RetrieveMultiple>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";
var xmlHttpRequest2 = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest2.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest2 .setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest2.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest2.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest2.send(xml);
var resultXml = xmlHttpRequest2.responseXML;
var entityNode = resultXml.selectSingleNode("//RetrieveMultipleResult/BusinessEntities/BusinessEntity");
var firstNameNode = entityNode.selectSingleNode("q1:firstname");
var lastNameNode = entityNode.selectSingleNode("q1:lastname");
var fullNameNode = entityNode.selectSingleNode("q1:fullname");
var systemUserIdNode = entityNode.selectSingleNode("q1:systemuserid");
var businessUnitIdNode = entityNode.selectSingleNode("q1:businessunitid");
var organizationIdNode = entityNode.selectSingleNode("q1:organizationid");
//Create an array to set as the DataValue for the the lookup control.
var lookupData = new Array();
//Create an Object add to the array.
var lookupItem= new Object();
//Set the id, typename, and name properties to the object.
lookupItem.id = systemUserIdNode.text;
lookupItem.typename = 'systemuser';
lookupItem.name = fullNameNode.text;
// Add the object to the array.
lookupData[0] = lookupItem;
// Set the value of the lookup field to the value of the array.
crmForm.all.ownerid.DataValue = lookupData;
crmForm.all.ownerid.ForceSubmit = true;
}
catch(err){alert("Error on user set.")}
but this runs in every FormType... so I was at a loss for a bit.
Then, In my efforts, of figuring out many ways to achieve this I finally found one that worked and wanted to share.
Here was what I found to work:
var xml = "" +
"<?xml version=\"1.0\" encoding=\"utf-8\"?>" +
"<soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">" +
GenerateAuthenticationHeader() +
" <soap:Body>" +
" <RetrieveMultiple xmlns=\"http://schemas.microsoft.com/crm/2007/WebServices\">" +
" <query xmlns:q1=\"http://schemas.microsoft.com/crm/2006/Query\" xsi:type=\"q1:QueryExpression\">" +
" <q1:EntityName>systemuser</q1:EntityName>" +
" <q1:ColumnSet xsi:type=\"q1:ColumnSet\">" +
" <q1:Attributes>" +
" <q1:Attribute>businessunitid</q1:Attribute>" +
" <q1:Attribute>firstname</q1:Attribute>" +
" <q1:Attribute>fullname</q1:Attribute>" +
" <q1:Attribute>lastname</q1:Attribute>" +
" <q1:Attribute>organizationid</q1:Attribute>" +
" <q1:Attribute>systemuserid</q1:Attribute>" +
" </q1:Attributes>" +
" </q1:ColumnSet>" +
" <q1:Distinct>false</q1:Distinct>" +
" <q1:Criteria>" +
" <q1:FilterOperator>And</q1:FilterOperator>" +
" <q1:Conditions>" +
" <q1:Condition>" +
" <q1:AttributeName>systemuserid</q1:AttributeName>" +
" <q1:Operator>EqualUserId</q1:Operator>" +
" </q1:Condition>" +
" </q1:Conditions>" +
" </q1:Criteria>" +
" </query>" +
" </RetrieveMultiple>" +
" </soap:Body>" +
"</soap:Envelope>" +
"";
var xmlHttpRequest2 = new ActiveXObject("Msxml2.XMLHTTP");
xmlHttpRequest2.Open("POST", "/mscrmservices/2007/CrmService.asmx", false);
xmlHttpRequest2.setRequestHeader("SOAPAction", "http://schemas.microsoft.com/crm/2007/WebServices/RetrieveMultiple");
xmlHttpRequest2.setRequestHeader("Content-Type", "text/xml; charset=utf-8");
xmlHttpRequest2.setRequestHeader("Content-Length", xml.length);
xmlHttpRequest2.send(xml);
var resultXml = xmlHttpRequest2.responseXML;
var entityNode = resultXml.selectSingleNode("//RetrieveMultipleResult/BusinessEntities/BusinessEntity");
var firstNameNode = entityNode.selectSingleNode("q1:firstname");
var lastNameNode = entityNode.selectSingleNode("q1:lastname");
var fullNameNode = entityNode.selectSingleNode("q1:fullname");
var systemUserIdNode = entityNode.selectSingleNode("q1:systemuserid");
var businessUnitIdNode = entityNode.selectSingleNode("q1:businessunitid");
var organizationIdNode = entityNode.selectSingleNode("q1:organizationid");
//Create an array to set as the DataValue for the the lookup control.
var lookupData = new Array();
//Create an Object add to the array.
var lookupItem = new Object();
//Set the id, typename, and name properties to the object.
lookupItem.id = systemUserIdNode.text;
lookupItem.typename = 'systemuser';
lookupItem.name = fullNameNode.text;
// Add the object to the array.
lookupData[0] = lookupItem;
// Set the value of the lookup field to the value of the array.
var CRM_FORM_TYPE_CREATE = 1;
var CRM_FORM_TYPE_UPDATE = 2;
// To carry over firstname and fullname callouts into the switch statement
var fullname = fullNameNode.text;
var firstName = firstNameNode.text;
switch (crmForm.FormType) {
case CRM_FORM_TYPE_CREATE:
if (fullname == "Jeromie Kirchoff") {
// alert("Hi " + firstName + '\n' + '\n' +"Let me make this easy for you!");
crmForm.all.ownerid.DataValue = lookupData;
crmForm.all.ownerid.ForceSubmit = true;
// run the default order setting I had previously added in my Onload script.
crmForm.all.new_orderstatus.DataValue = 6;
try {crmForm.orderrstat(); } catch (err) {alert("Function Call Out - ERROR - 0001-1"); }
}
break;
case CRM_FORM_TYPE_UPDATE:
break;
}
I hope this helps. =)