Im trying to execute a some JS code via a background task.
Im using a gateway which works similar to paypal, i.e. once payment details are taken a response is sent back to a listener on my server (this could be immediate or several minutes later)
Once a response is received by the listener (listener.cfm), using cfhttp im calling a file (runPixCode.cfm) which has some trigger code.
Because runPixCode.cfm is not rendered by the browser the JS is not executing.
Also to prove whether this worked or not, im getting the JS to call another file (provethisiscalled.cfm) which write a log to a txt file.
If i put the following straight after the cfhttp call, i can see an entry in the log file. This assures me there is no issue with the JS providing its rendered by the browser.
<cfoutput>#cfhttp.FileContent#</cfoutput><cfabort>
However, doesnt work with a background task. I dont know how else to deal with this, any suggestions appreciated.
listener.cfm
--Does a bunch of logic--
<cfif paymentsuccessful>
<CFHTTP URL="www.mysite.com/runPixCode.cfm" METHOD="post" timeout="12" resolveurl="true">
<CFHTTPPARAM NAME="TrackingId" VALUE="#trackingId#" TYPE="FormField">
</CFHTTP>
</cfif>
runPixCode.cfm
<SCRIPT language="JavaScript">
var axel = Math.random()+"";
var a = axel * 1000;
document.write('<IFRAME SRC="http://www.mysite.com/provethisiscalled.cfm?codearea=landing&num='+ a + '?" WIDTH=1 HEIGHT=1 FRAMEBORDER=0></IFRAME>');
</SCRIPT>
<NOSCRIPT><IFRAME SRC="http://www.mysite.com/provethisiscalled.cfm?codearea=landing&num=1" WIDTH=1 HEIGHT=1 FRAMEBORDER=0></IFRAME> </NOSCRIPT>
provethisiscalled.cfm
<cfloop collection=#ARGUMENTS.triggerParams# item="key">
<cfset docLogging = docLogging & chr(13) & "#key# = " & ARGUMENTS.triggerParams[key]>
</cfloop>
<cffile action="append" file="c:\serverlocation\someDir\triggerlog.txt" output="#docLogging#" addnewline="YES" >
Writing an iframe is not going to work, nor is javascript, because all of these processes are being called by applications, not by browsers.
So with that, you have to get creative. First, what are you really attempting to do?
If your purpose is to determine whether or not a file has been called or executed, use <cflog> or write an entry to a database.
If you are trying to pass an HTTP call from listener.cfm to runPixCode.cfm, use <cfhttp> instead of an iframe.
If your purpose is actually to execute JavaScript as part of this automated process (it isn't, but this is cool), you can execute JavaScript in your CF/Java server through Rhino, which is not incredibly simple, but you can get code snippets by googling. Rhino is included with ColdFusion as js.jar, so there are no special files to download to make it work.
Related
I am trying to make a script for my Google spreadsheet in which I upload an XML file and process its data. I am able to create a form, display it in a modal dialog, but I get a strange error when I attempt to submit a form with a file: Nothing is logged for the error in Stackdriver Error Reporting. However, the web browser console logs the following error message:
Error: We're sorry, a server error occurred. Please wait a bit and try again.
The error message comes with a stack trace:
Zd https://n-z7hx4jjtvixobmaqkddve7tkcdyndjsnh3plmfq-0lu-script.googleusercontent.com/static/macros/client/js/2745927008-mae_html_user_bin_i18n_mae_html_user__en_gb.js:56
bf https://n-z7hx4jjtvixobmaqkddve7tkcdyndjsnh3plmfq-0lu-script.googleusercontent.com/static/macros/client/js/2745927008-mae_html_user_bin_i18n_mae_html_user__en_gb.js:71
G https://n-z7hx4jjtvixobmaqkddve7tkcdyndjsnh3plmfq-0lu-script.googleusercontent.com/static/macros/client/js/2745927008-mae_html_user_bin_i18n_mae_html_user__en_gb.js:15
J https://n-z7hx4jjtvixobmaqkddve7tkcdyndjsnh3plmfq-0lu-script.googleusercontent.com/static/macros/client/js/2745927008-mae_html_user_bin_i18n_mae_html_user__en_gb.js:99
Id https://n-z7hx4jjtvixobmaqkddve7tkcdyndjsnh3plmfq-0lu-script.googleusercontent.com/static/macros/client/js/2745927008-mae_html_user_bin_i18n_mae_html_user__en_gb.js:47
Ed https://n-z7hx4jjtvixobmaqkddve7tkcdyndjsnh3plmfq-0lu-script.googleusercontent.com/static/macros/client/js/2745927008-mae_html_user_bin_i18n_mae_html_user__en_gb.js:48
b https://n-z7hx4jjtvixobmaqkddve7tkcdyndjsnh3plmfq-0lu-script.googleusercontent.com/static/macros/client/js/2745927008-mae_html_user_bin_i18n_mae_html_user__en_gb.js:44
Of course, the stack trace doesn't help here, as it points to a huge minified JavaScript file on Google's servers.
I have tried replicating the examples in the current Google Apps documentation as well as a few old and recent examples I could find on StackOverflow, and the issue is always the same: When comes the time to submit the form data, the script crashes.
I know that this is specifically caused by the file input field. If I remove it, I'm able to submit the form and process its data. If I add the file input field, I get the error as soon as I submit the form.
I can tell the issue is not the file. I have tried uploading a big (125 kb) text file at first, followed by one a few bytes in size, and even not submitting any file at all, and I get the same error. I'm encountering this issue on both Chrome and Firefox, on two separate Google accounts.
Here is my Google script. The updateTracker method is called when clicking on a drawing object that I placed in the spreadhseet.
function updateTracker()
{
var thisUI = SpreadsheetApp.getUi();
var htmlUpdatePage = HtmlService.createHtmlOutputFromFile('myPage');
var updatePrompt = thisUI.showModalDialog(htmlUpdatePage, 'Update');
}
function digestXml(theForm) {
//var fileBlob = theForm.xmlFile;
var thisUI = SpreadsheetApp.getUi();
thisUI.alert("Test");
}
Here is my HTML file, "myPage":
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script>
// Prevent forms from submitting.
function preventFormSubmit() {
var forms = document.querySelectorAll('form');
for (var i = 0; i < forms.length; i++) {
forms[i].addEventListener('submit', function(event) {
event.preventDefault();
});
}
}
window.addEventListener('load', preventFormSubmit);
function submitXml(objForm)
{
google.script.run.withSuccessHandler(updateUrl).digestXml(objForm);
}
function updateUrl(url) {
var div = document.getElementById('output');
div.innerHTML = 'Got it!';
}
</script>
</head>
<body>
<form id="xmlForm" onsubmit="submitXml(this)">
<input type="file" value="Browse" name="xmlFile" />
<input type="submit" value="Digest" />
</form>
<div id="output"></div>
</body>
</html>
I can tell that the issue occurs precisely when trying to pass objForm from the HTML to the Google Script. I'm able to write to the console right before the line google.script.run.withSuccessHandler(updateUrl).digestXml(objForm); in HTML, but I don't get to thisUI.alert("Test"); in the Google Script. If I remove the parameter objForm from digestXml() in the HTML, the crash does not occur.
It appears that the issue only occurs in a recently released version of Google App's scripting interface, "V8".
When I create a script, I am prompted to use this version of their scripting interface. Trusting Google to test their functionalities, I accepted without thinking.
If I edit my script's configuration file to use STABLE instead of V8, I do not encounter the issue. If you're having this issue, here's how to do that:
Open the Script Editor.
In the top menu, select View > Show manifest file.
In the files list, open appsscript.json.
Replace "runtimeVersion": "V8" with "runtimeVersion": "STABLE"
Save.
This is however alarming as I presume the current stable version will be deprecated eventually in favor of V8. I logged an issue for this: https://issuetracker.google.com/issues/149980602
Here is the issue that has been nagging for weeks and all solutions found online do not seem to work... ie. wait for ajax, etc...
here is versions of gems:
capybara (2.10.1, 2.7.1)
selenium-webdriver (3.0.1, 3.0.0)
rspec (3.5.0)
running ruby 2.2.5
ruby 2.2.5p319 (2016-04-26 revision 54774) [x64-mingw32]
in the env.rb
Capybara.register_driver :selenium do | app |
browser = (ENV['browser'] || 'firefox').to_sym
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
Capybara.default_max_wait_time = 5
end
Here is my dynamicpage.feature
Given I visit page X
Then placeholder text appears
And the placeholder text is replaced by the content provided by the json service
and the step.rb
When(/^I visit page X$/) do
visit('mysite.com/productx/')
end
When(/^placeholder text appears$/) do
expect(page).to have_css(".text-replacer-pending")
end
Then(/^the placeholder text is replaced by the content provided by the json service$/) do
expect(page).to have_css(".text-replacer-done")
end
the webpage in question, which I cannot add it here as it is not publicly accessible, contains the following on page load:
1- <span class="text-replacer-pending">Placeholder Text</span>
after a call to an external service (which provides the Json data), the same span class gets refreshed/updated to the following;
2- <span class="text-replacer-done">Correct Data</span>
The problem I have with the "visit" method in capybara + selenium is that as soon as it visits the page, it thinks everything loaded and freezes the browser, and it never lets the service be called to dynamically update the content.
I tried the following solutions but without success:
Capybara.default_max_wait_time = 5
Capybara::Driver::Selenium.new(app, :browser => browser.to_sym, :resynchronize => true)
add sleep 5 after the visit method
wait for ajax solution from several websites, etc...
adding after hooks
etc...
I am at a complete loss why "visit" can't wait or at least provide a simple solution to an issue i am sure is very common.
I am aware of the capybara methods that wait and those that don't wait such as 'visit' but the issue is;
there is no content that goes from hidden to displayed
there is there is no user interaction either, just the content is getting updated.
also unsure if this is a capybara issue or a selenium or both.
Anyhow have insight on any solutions? i am fairly new to ruby and cucumber so specifically what code goes in what file/folder would be much appreciated.
Mel
Restore wait_until method (add it to your spec_helpers.rb)
def wait_until(timeout = DEFAULT_WAIT_TIME)
Timeout.timeout(timeout) do
sleep(0.1) until value = yield
value
end
end
And then:
# time in seconds
wait_until(20) { has_no_css?('.text-replacer-pending') }
expect(page).to have_css(".text-replacer-done")
#maxple and #nattf0dd
Just to close the loop on our issue here...
After looking at this problem from a different angle,
we finally found out Cucumber/Capybara/ is not a problem at all :-)
The issue we are having lies with the browser Firefox driver (SSL related), since we have no issues when running the same test with the Chrome driver.
I do appreciate the replies and suggestions and will keep those in mind for future.
thanks again!
I've got a web page with its own scripts and variables that I need to execute and retrieve return values from my extension's Background.js.
I understand (I think!) that in order to interact with the web page, it must be done via chrome.tabs.executeScript or a ContentScript, but because the code must execute in the context of the original page (in order to have scope to the scripts and variables), it needs to be injected into the page first.
Following this great post by Rob W, I'm able to invoke the page-level script/variables, but I'm struggling to understand how to return values in this way.
Here's what I've got so far...
Web page code (that I want to interact with):
<html>
<head>
<script>
var favColor = "Blue";
function getURL() {
return window.location.href;
}
</script>
</head>
<body>
<p>Example web page with script content I want interact with...</p>
</body>
</html>
manifest.json:
{
// Extension ID: behakphdmjpjhhbilolgcfgpnpcoamaa
"name": "MyExtension",
"version": "1.0",
"manifest_version": 2,
"description": "My Desc Here",
"background": {
"scripts": ["background.js"]
},
"icons": {
"128": "icon-128px.png"
},
"permissions": [
"background",
"tabs",
"http://*/",
"https://*/",
"file://*/", //### (DEBUG ONLY)
"nativeMessaging"
]
}
background.js
codeToExec = ['var actualCode = "alert(favColor)";',
'var script = document.createElement("script");',
' script.textContent = actualCode;',
'(document.head||document.documentElement).appendChild(script);',
'script.parentNode.removeChild(script);'].join('\n');
chrome.tabs.executeScript( tab.id, {code:codeToExec}, function(result) {
console.log('Result = ' + result);
} );
I realise the code is currently just "alerting" the favColor variable (this was just a test to make sure I could see it working). However, if I ever try returning that variable (either by leaving it as the last statement or by saying "return favColor"), the executeScript callback never has the value.
So, there appear to be (at least) three levels here:
background.js
content scripts
actual web page (containing scripts/variables)
...and I would like to know what is the recommended way to talk from level 1 to level 3 (above) and return values?
Thanks in advance :o)
You are quite right in understanding the 3-layer context separation.
A background page is a separate page and therefore doesn't share JS or DOM with visible pages.
Content scripts are isolated from the webpage's JS context, but share DOM.
You can inject code into the page's context using the shared DOM. It has access to the JS context, but not to Chrome APIs.
To communicate, those layers use different methods:
Background <-> Content talk through Chrome API.
The most primitive is the callback of executeScript, but it's impractical for anything but one-liners.
The common way is to use Messaging.
Uncommon, but it's possible to communicate using chrome.storage and its onChanged event.
Page <-> Extension cannot use the same techniques.
Since injected page-context scripts do not technically differ from page's own scripts, you're looking for methods for a webpage to talk to an extension. There are 2 methods available:
While pages have very, very limited access to chrome.* APIs, they can nevertheless use Messaging to contact the extension. This is achieved through "externally_connectable" method.
I have recently described it in detail this answer. In short, if your extension declared that a domain is allowed to communicate with it, and the domain knows the extension's ID, it can send an external message to the extension.
The upside is directly talking to the extension, but the downside is the requirement to specifically whitelist domains you're using this from, and you need to keep track of your extension ID (but since you're injecting the code, you can supply the code with the ID). If you need to use it on any domain, this is unsuitable.
Another solution is to use DOM Events. Since the DOM is shared between the content script and the page script, an event generated by one will be visible to another.
The documentation demonstrates how to use window.postMessage for this effect; using Custom Events is conceptually more clear.
Again, I answered about this before.
The downside of this method is the requirement for a content script to act as a proxy. Something along these lines must be present in the content script:
window.addEventListener("PassToBackground", function(evt) {
chrome.runtime.sendMessage(evt.detail);
}, false);
while the background script processes this with a chrome.runtime.onMessage listener.
I encourage you to write a separate content script and invoke executeScript with a file attribute instead of code, and not rely on its callback. Messaging is cleaner and allows to return data to background script more than once.
The approach in Xan's answer (using events for communication) is the recommended approach. Implementing the concept (and in a secure way!) is however more difficult.
So I'll point out that it is possible to synchronously return a value from the page to the content script. When a <script> tag with an inline script is inserted in the page, the script is immediately and synchronously executed (before the .appendChild(script) method returns).
You can take advantage of this behavior by using the injected script to assign the result to a DOM object which can be accessed by the content script. For example, by overwriting the text content of the currently active <script> tag. The code in a <script> tag is executed only once, so you can assign any rubbish to the content of the <script> tag, because it won't be parsed as code any more. For example:
// background script
// The next code will run as a content script (via chrome.tabs.executeScript)
var codeToExec = [
// actualCode will run in the page's context
'var actualCode = "document.currentScript.textContent = favColor;";',
'var script = document.createElement("script");',
'script.textContent = actualCode;',
'(document.head||document.documentElement).appendChild(script);',
'script.remove();',
'script.textContent;'
].join('\n');
chrome.tabs.executeScript(tab.id, {
code: codeToExec
}, function(result) {
// NOTE: result is an array of results. It is usually an array with size 1,
// unless an error occurs (e.g. no permission to access page), or
// when you're executing in multiple frames (via allFrames:true).
console.log('Result = ' + result[0]);
});
This example is usable, but not perfect. Before you use this in your code, make sure that you implement proper error handling. Currently, when favColor is not defined, the script throws an error. Consequently the script text is not updated and the returned value is incorrect. After implementing proper error handling, this example will be quite solid.
And the example is barely readable because the script is constructed from a string. If the logic is quite big, but the content script in a separate file and use chrome.tabs.executeScript(tab.id, {file: ...}, ...);.
When actualCode becomes longer than a few lines, I suggest to wrap the code in a function literal and concatenate it with '(' and ')(); to allow you to more easily write code without having to add quotes and backslashes in actualCode (basically "Method 2b" of the answer that you've cited in the question).
chrome.browserAction.onClicked.addListener(function(tab) {
// No tabs or host permissions needed!
console.log('Turning ' + tab.url + ' red!');
chrome.tabs.executeScript({
file: 'index.js'
});
});
Here index.js is normal js file to inject in browser
#index.js
alert("Hello from api");
I'm trying to get websockets working with ColdFusion. I am unable to send or receive messages and I am at a loss as to why. Am I missing something? Do I need to have any other programs installed? I am using Adobe ColdFusion Builder 3 Developer Edition.
Here is the code I am attempting to use.
Websocket.cfm
<cfwebsocket name="mycfwebsocketobject" onmessage="MessageHandler" subscribeto="stocks" >
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
function MessageHandler(message)
{
alert(message.data);
}
function publishstock()
{
mycfwebsocketobject.Publish('stocks', 'I sent a message!');
}
setInterval('publishstock()',1000);
</script>
Application.cfc
<cfcomponent>
<cfset this.name="Websocket">
<cfset this.wschannels=[{name="stocks"}]>
</cfcomponent>
My goal is to get the MessageHandler function to trigger without explicitly calling it. I have no idea what is wrong and I have matched my code up perfectly with many examples on the web. I have been unsuccessful in both Chrome and Firefox.
I think that the real problem might have something to do with my machine. I found a demo online that worked perfectly, but when I downloaded the source it no longer worked. Is there a way to test for this?
Resources:
https://www.youtube.com/watch?v=Ys6BGrYJhNg
http://www.adobe.com/devnet/coldfusion/articles/html5-websockets-coldfusion-pt1.html
Your setInterval('publishstock()',1000);
Should be:
setInterval(function(){publishstock();},1000);
Hey, so I'm having a bunch of trouble getting ExternalInterface to work, which is odd, because I use it somewhat often.
I'm hoping it's something I just missed because I've been looking at it too long.
The flash_ready function is correctly returning the objectID, and as far as I can tell, everything else is in order.
Unfortunately, when I run it, I get an error (varying by browser) telling me that basically document.getElementById(<movename>).test() is not a valid method.
Here's the code:
javascript:
function flash_ready(i){
document.getElementById(i).test('success!');
}
Embed Html (Generated):
<script type="text/javascript">
swfobject.embedSWF("/chainmaille/includes/media/flash/upload_image.swf", "/chainmaille/includes/media/flash/upload_image", "500", "50", "9.0.0","expressInstall.swf", {}, {allowScriptAccess:'always', wmode:'transparent'},{id:'uploader_flash',name:'uploader_flash'});
</script>
<object type="application/x-shockwave-flash" id="uploader_flash" name="uploader_flash" data="/chainmaille/includes/media/flash/upload_image.swf" width="500" height="50"><param name="allowScriptAccess" value="always"><param name="wmode" value="transparent"></object>
AS3 :
package com.jesseditson.uploader {
import flash.display.MovieClip;
import flash.external.ExternalInterface;
import flash.system.Security;
public class UI extends MovieClip {
// Initialization:
public function UI() {
Security.allowDomain('*');
ExternalInterface.addCallback("test", test);
var jscommand:String = "flash_ready('"+ExternalInterface.objectID+"');";
var url:URLRequest = new URLRequest("javascript:" + jscommand + " void(0);");
navigateToURL(url, "_self");
}
public function test(t){
trace(t);
}
}
}
Swfobject is being included via google code, and the flash embeds just fine, so that's not the problem.
I've got a very similar setup working on another server, but can't seem to get it working on this one. It's a Hostgator shared server. Could it be the server's fault? Anybody see any obvious syntax problems?
Thanks in advance!
The Flash isn't actually finished constructing yet. You're calling your flash_ready callback from the constructor, and so the JS is trying to call in before the object is on the stage. Move your flash_ready call to, say, an Event.ADDED_TO_STAGE listener and it should start working.
Ok, so after further investigation, it appears that there was a problem with multiple instances of the flash object, because I was cloning it to a lightbox. I have gotten it working now.
Just spent 5 hours fighting with this. It was all really frustrating. In my case the solution was very very simple and I would have never guessed it.
So first of for all of you who have never seen the flash player debugger running on files inside your browser finding this link that walks you through the setup has resulted in a somewhat magical experience :)
Now to my ExternalInterface discovery: There was a sandbox violation inside the same domain. This meant that flash cannot access www.yourdomain.com from yourdomain.com. The weird thing of course is that you are not explicitly calling the domain with ExternalInterface.
Anyhow, the solution was very simple: add this to my .htaccess file and that was it!
# Redirect non-www to www
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule (.*) http://www.youtdomain.com/$1 [R=301,L]
Hope this helps someone
Is flash_ready receiving the objectID that you are expecting?
Also, why use:
var jscommand:String = "flash_ready('"+ExternalInterface.objectID+"');";
var url:URLRequest = new URLRequest("javascript:" + jscommand + " void(0);");
navigateToURL(url, "_self");
When this is designed to do that:
ExternalInterface.call("flash_ready", ExternalInterface.objectID);
Post your source (pre-generatred). When your browser says [Flash].Method is not a function, 99% of the time it means that you tried calling a function in Flash before the .swf was ready for it. I see that you tried to do that, but clearly its not working so something must be off. So post your pre-rendered source and I am sure we can find the problem.