Javascript code end of webpage with Spring and Dojo - ajax

I have a pretty specific issue to deal with : I am looking for a solution about IE6 crashing when there is too much javascript in a webpage. The project I am working on is using Dojo, SpringJS, Apache Tiles and Spring Webflow. For each field used (defined in .tagx files), the decoration is added as following :
<script type="text/javascript">
Spring.addDecoration(
new Spring.ElementDecoration({
elementId : '_${field}_id',
widgetType : 'dijit.form.ValidationTextBox',
widgetAttrs : {
<!-- Widget attrs -->
}
})
);
</script>
So, in the generated webpage, a lot of javascript is added everywhere. The problem is IE6 seems to crash when there is too much javascript. The solution "experts" found was to write all the javascript code at the end of the HTML page.
In intent to do that, I tried to create a new tag called putScriptInCache.tagx :
<jsp:useBean id="mapScripts" class="java.util.HashMap" scope="request"/>
<jsp:doBody var="theBody" />
<c:set target="${mapScripts}" property="${id}" value="${theBody}"/>
Which replaces previous javascript tag :
<lbputil:putScriptInCache id="${field}">
Spring.addDecoration(
new Spring.ElementDecoration({
elementId : '_${field}_id',
widgetType : 'dijit.form.ValidationTextBox',
widgetAttrs : {
<!-- Widget attrs -->
}
})
);
</lbputil:putScriptInCache>
Finally, I have written a piece of code which loops on the map created and write javascript at the end of the html body :
<script type="text/javascript">
dojo.addOnLoad(function(){
<c:forEach items="${mapScripts}" var="script">
<c:out value="${script.value}" escapeXml="false" />
</c:forEach>
});
</script>
It seems to work pretty well but an issue remains : when an ajax request is fired, an Apache Tiles fragment of the jsp is reloaded using Spring Webflow. After that, I noticed that the map in request scope was empty and I can't figure out why. It should have been filled with the reloaded fragment fields javascript code.
EDIT : If someone has a totally different way to solve my initial issue, do not hesitate to propose it !

After lookep at the spring-dojo.js, I found that this script already evaluates scripts at the end of the fragment rendering.
handleResponse: function(response, ioArgs, callbackResponse) {
//...
//Extract and store all <script> elements from the response
var scriptPattern = '(?:<script(.|[\n|\r])*?>)((\n|\r|.)*?)(?:<\/script>)';
var extractedScriptNodes = [];
var matchAll = new RegExp(scriptPattern, 'img');
var matchOne = new RegExp(scriptPattern, 'im');
var scriptNodes = response.match(matchAll);
if (scriptNodes != null)
{
for (var i=0; i<scriptNodes.length; i++)
{
var script = (scriptNodes[i].match(matchOne) || ['','',''])[2];
script = script.replace(/<!--/mg,'').replace(/\/\/-->/mg,'').replace(/<!\[CDATA\[(\/\/>)*/mg,'').replace(/(<!)*\]\]>/mg,'');
extractedScriptNodes.push(script);
}
}
//...
//Evaluate any script code
dojo.forEach(extractedScriptNodes, function(script){
dojo.eval(script);
});
// APPEL du callBackResponse
if (callbackResponse != null){
callbackResponse();
}
return response;
},
First, it stores script tags into extractedScriptNodes, then it replaces the script tags with // Original script removed to avoid re-execution . Finally, it evaluates each extractedScriptNodes after having rendered the view.
So, it should already work...

Related

Google App Scripts Function to Open URL [duplicate]

Is there a way to write a google apps script so when ran, a second browser window opens to www.google.com (or another site of my choice)?
I am trying to come up with a work-around to my previous question here:
Can I add a hyperlink inside a message box of a Google Apps spreadsheet
This function opens a URL without requiring additional user interaction.
/**
* Open a URL in a new tab.
*/
function openUrl( url ){
var html = HtmlService.createHtmlOutput('<html><script>'
+'window.close = function(){window.setTimeout(function(){google.script.host.close()},9)};'
+'var a = document.createElement("a"); a.href="'+url+'"; a.target="_blank";'
+'if(document.createEvent){'
+' var event=document.createEvent("MouseEvents");'
+' if(navigator.userAgent.toLowerCase().indexOf("firefox")>-1){window.document.body.append(a)}'
+' event.initEvent("click",true,true); a.dispatchEvent(event);'
+'}else{ a.click() }'
+'close();'
+'</script>'
// Offer URL as clickable link in case above code fails.
+'<body style="word-break:break-word;font-family:sans-serif;">Failed to open automatically. Click here to proceed.</body>'
+'<script>google.script.host.setHeight(40);google.script.host.setWidth(410)</script>'
+'</html>')
.setWidth( 90 ).setHeight( 1 );
SpreadsheetApp.getUi().showModalDialog( html, "Opening ..." );
}
This method works by creating a temporary dialog box, so it will not work in contexts where the UI service is not accessible, such as the script editor or a custom G Sheets formula.
You can build a small UI that does the job like this :
function test(){
showURL("http://www.google.com")
}
//
function showURL(href){
var app = UiApp.createApplication().setHeight(50).setWidth(200);
app.setTitle("Show URL");
var link = app.createAnchor('open ', href).setId("link");
app.add(link);
var doc = SpreadsheetApp.getActive();
doc.show(app);
}
If you want to 'show' the URL, just change this line like this :
var link = app.createAnchor(href, href).setId("link");
EDIT : link to a demo spreadsheet in read only because too many people keep writing unwanted things on it (just make a copy to use instead).
EDIT : UiApp was deprecated by Google on 11th Dec 2014, this method could break at any time and needs updating to use HTML service instead!
EDIT :
below is an implementation using html service.
function testNew(){
showAnchor('Stackoverflow','http://stackoverflow.com/questions/tagged/google-apps-script');
}
function showAnchor(name,url) {
var html = '<html><body>'+name+'</body></html>';
var ui = HtmlService.createHtmlOutput(html)
SpreadsheetApp.getUi().showModelessDialog(ui,"demo");
}
There really isn't a need to create a custom click event as suggested in the bountied answer or to show the url as suggested in the accepted answer.
window.open(url)1 does open web pages automatically without user interaction, provided pop- up blockers are disabled(as is the case with Stephen's answer)
openUrl.html
<!DOCTYPE html>
<html>
<head>
<base target="_blank">
<script>
const url1 ='https://stackoverflow.com/a/54675103';
const winRef = window.open(url1);
winRef ? google.script.host.close() : window.alert('Allow popup to redirect you to '+url1) ;
window.onload=function(){document.getElementById('url').href = url1;}
</script>
</head>
<body>
Kindly allow pop ups</br>
Or <a id='url'>Click here </a>to continue!!!
</body>
</html>
code.gs:
function modalUrl(){
SpreadsheetApp.getUi()
.showModalDialog(
HtmlService.createHtmlOutputFromFile('openUrl').setHeight(50),
'Opening StackOverflow'
)
}
Google Apps Script will not open automatically web pages, but it could be used to display a message with links, buttons that the user could click on them to open the desired web pages or even to use the Window object and methods like addEventListener() to open URLs.
It's worth to note that UiApp is now deprecated. From Class UiApp - Google Apps Script - Google Developers
Deprecated. The UI service was deprecated on December 11, 2014. To
create user interfaces, use the HTML service instead.
The example in the HTML Service linked page is pretty simple,
Code.gs
// Use this code for Google Docs, Forms, or new Sheets.
function onOpen() {
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.createMenu('Dialog')
.addItem('Open', 'openDialog')
.addToUi();
}
function openDialog() {
var html = HtmlService.createHtmlOutputFromFile('index')
.setSandboxMode(HtmlService.SandboxMode.IFRAME);
SpreadsheetApp.getUi() // Or DocumentApp or FormApp.
.showModalDialog(html, 'Dialog title');
}
A customized version of index.html to show two hyperlinks
<a href='http://stackoverflow.com' target='_blank'>Stack Overflow</a>
<br/>
<a href='http://meta.stackoverflow.com/' target='_blank'>Meta Stack Overflow</a>
Building of off an earlier example, I think there is a cleaner way of doing this. Create an index.html file in your project and using Stephen's code from above, just convert it into an HTML doc.
<!DOCTYPE html>
<html>
<base target="_top">
<script>
function onSuccess(url) {
var a = document.createElement("a");
a.href = url;
a.target = "_blank";
window.close = function () {
window.setTimeout(function() {
google.script.host.close();
}, 9);
};
if (document.createEvent) {
var event = document.createEvent("MouseEvents");
if (navigator.userAgent.toLowerCase().indexOf("firefox") > -1) {
window.document.body.append(a);
}
event.initEvent("click", true, true);
a.dispatchEvent(event);
} else {
a.click();
}
close();
}
function onFailure(url) {
var div = document.getElementById('failureContent');
var link = 'Process';
div.innerHtml = "Failure to open automatically: " + link;
}
google.script.run.withSuccessHandler(onSuccess).withFailureHandler(onFailure).getUrl();
</script>
<body>
<div id="failureContent"></div>
</body>
<script>
google.script.host.setHeight(40);
google.script.host.setWidth(410);
</script>
</html>
Then, in your Code.gs script, you can have something like the following,
function getUrl() {
return 'http://whatever.com';
}
function openUrl() {
var html = HtmlService.createHtmlOutputFromFile("index");
html.setWidth(90).setHeight(1);
var ui = SpreadsheetApp.getUi().showModalDialog(html, "Opening ..." );
}
I liked #Stephen M. Harris's answer, and it worked for me until recently. I'm not sure why it stopped working.
What works for me now on 2021-09-01:
function openUrl( url ){
Logger.log('openUrl. url: ' + url);
const html = `<html>
<a id='url' href="${url}">Click here</a>
<script>
var winRef = window.open("${url}");
winRef ? google.script.host.close() : window.alert('Configure browser to allow popup to redirect you to ${url}') ;
</script>
</html>`;
Logger.log('openUrl. html: ' + html);
var htmlOutput = HtmlService.createHtmlOutput(html).setWidth( 250 ).setHeight( 300 );
Logger.log('openUrl. htmlOutput: ' + htmlOutput);
SpreadsheetApp.getUi().showModalDialog( htmlOutput, `openUrl function in generic.gs is now opening a URL...` ); // https://developers.google.com/apps-script/reference/base/ui#showModalDialog(Object,String) Requires authorization with this scope: https://www.googleapis.com/auth/script.container.ui See https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes
}
https://developers.google.com/apps-script/reference/base/ui#showModalDialog(Object,String) Requires authorization with this scope: https://www.googleapis.com/auth/script.container.ui See https://developers.google.com/apps-script/concepts/scopes#setting_explicit_scopes

How to correctly set the request header in an ajax containing non-alphanumeric characters?

My HTML file contains a form with just a textarea whose contents are sent to a java servlet (called "Compiler"). The textarea text will always be java code, so it might include characters like +, %, =, etc.
I'm using ajax to get and display the response from the servlet.
But using ajax breaks the whole data being sent by the form, because it strips out part of the text or completely ignores the characters I mentioned above.
This is my html file:
<html>
<head>
<script type="text/javascript">
function objetoAjax(){
http_request= false;
if (window.XMLHttpRequest) { // Mozilla, Safari,...
http_request = new XMLHttpRequest();
if (http_request.overrideMimeType) {
http_request.overrideMimeType('text/xml');
}
} else if (window.ActiveXObject) { // IE
try {
http_request = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try {
http_request = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
return http_request;
}
function devolver_resultado(){
var llamadaAjax = objetoAjax();
var codigo = document.getElementById('codigo').value;
llamadaAjax.open("POST",'Compiler',true);
llamadaAjax.onreadystatechange = function() {
if(llamadaAjax.readyState == 4){
document.getElementById("resultado").innerHTML = llamadaAjax.responseText;
}
};
llamadaAjax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
llamadaAjax.send('codigo='+codigo);
}
</script>
</head>
<body>
<form action="Compiler" method="post">
<textarea rows="18" cols="70" id="codigo" name="codigo"></textarea>
<input type="submit" value="Compile" onclick="devolver_resultado(); return false;">
</form>
<div id="resultado">
</div>
</body>
</html>
I've debugged the javascript to see if the problem was where I assign the textarea value to the "codigo" variable:
var codigo = document.getElementById('codigo').value;
(screenshot)
But this variable is being correctly set, so I suspect the request is being incorrectly encoded (screenshot).
I'm new to ajax, but I assume this is controlled by llamadaAjax.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
From this page I get that I should encode the form as multipart/form-data. I tried adding the encoding type to the form: but this didn't help.
So, two questions here:
1) Is actually this line the faulty one? llamadaAjax.setRequestHeader("Content-Type","application/x-www-form-urlencoded")
If so, how do I fix it?
2) If that's not where the bug is, what else could be happening? (remember that removing all the ajax and leaving a plain form that calls my "Compiler" servlet works as expected, so the servlet is not buggy).
Thanks!
SOLVED.
All I needed was to encode the text before sending it:
llamadaAjax.send('codigo='+encodeURIComponent(codigo));

jQuery mobile : Linking next page doesn't work on Windows phone using phonegap

Currently im building a application using phonegap & jQuery Mobile
I have done the version which is perfectly working on iOS & Android.But the same code does not work on windows phone.When i click any link,redirection to the respective page is not loading..Its still says "Error Page loading".
<!DOCTYPE html>
Test
<div id="bg">
<div style="padding-top:14%;width:100%;text-align:center">
<div style="float:left;text-align:center;width:50%"><img src="pics/btn_1.png" /></div>
<div style="float:left;text-align:center;width:50%"><img src="pics/btn_2.png" /></div>
</div>
<div style="clear:both"></div>
</div>
</div>
<script type="text/javascript" src="cordova.js"></script>
<script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript">
app.initialize();
</script>
</body>
Need help on this.
Solution
Add data-ajax=false or rel=external to your anchor tag. But, if you do this, you will lose transitions. This tells the framework to do a full page reload to clear out the Ajax hash in the URL. You could enable this if the incoming device is a windows phone if needed :
$(document).on("mobileinit", function () {
//check for windows phone
$.mobile.ajaxEnabled = false;
});
Else, make your code into a single page template. Here's a demo of that : http://jsfiddle.net/hungerpain/aYW2f/
Edit
Currently jQM doesn't support query string parameters. You could use the localStorage API to store the parameters in cache and retrieve them later. Assuming you want to go to index.html from here :
<img src="pics/btn_2.png" />
You'd add a click event for it :
$(document).on("click", "a", function() {
//gets qs=2 and changes it into ["qs",2]
var query = this.href.split["?"][2].split["="];
//construct an array out of that
var paramString = { query[0]: query[1]} ;
//store it in localstorage
locaStorage["query"] = JSON.stringify(paramString);
//continue redirection
return true;
});
In your index.html :
$(document).on("pageinit", "[data-role=page]", function() {
//store it in localstorage
var params = JSON.parse(locaStorage["query"]);
//now params will contain { "qs" : 2 }
//you could access "2" by params["qs"]
});
More info about localStorage here.
I had Also same issue and finally resolve it by using below code
my html page is index.html and i am writtinga all code in one html
Before
$.mobile.changePage( "#second", {});
After
var url = window.location.href;
url = url.split('#').pop().split('?').pop();
url = url.replace(url.substring(url.lastIndexOf('/') + 1),"index.html#second");
$.mobile.changePage(url, { reloadPage : false, changeHash : false });
and suppose you have multiple html page then for more one page to another you can use
var url = window.location.href;
url = url.split('#').pop().split('?').pop();
url = url.replace(url.substring(url.lastIndexOf('/') + 1),"second.html");
$.mobile.changePage(url, { reloadPage : false, changeHash : false });
There is no support of querystring in web application using phonegap for windows phone 7.
However we can replace ? with # or anything else to pass the data,
like convert
Sample.html?id=12312
to
Sample.html#id=12312

How to enable data binding in KnockoutJS using the ASP.NET MVC 3 "Razor" View Engine?

I'm trying to implement this Knockout example using ASP MVC 3's "Razor" view engine.
The first topic covers simple data binding of a C# array using the standard ASP view engine. I am trying the sample example using "Razor", and this line:
<script type="text/javascript">
var initialData = <%= new JavaScriptSerializer().Serialize(Model) %>;
</script>
results in an empty variable for initialData.
I also tried this:
#{
string data = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(Model);
}
And then specified the initialData like this:
var initialData = #Html.Raw(data);
This populates initialData with the dataset, but binding does not work.
I'm just trying to databind this set in order to display a count of the ideas, as in the example:
<p>You have asked for <span data-bind="text: gifts().length"> </span> gift(s)</p>
Why isn't data binding working in this instance?
The easiest way in MVC3 is to do:
var initialData = #Html.Raw(Json.Encode(Model));
I ran into this same problem, and discovered that it was my own stupidity that caused the issue (which it so often is). I forgot to wait until the DOM loaded to call ko.applyBindings(viewModel) - so simply using:
$(document).ready(function () { ko.applyBindings(viewModel); });
So the whole script as
<script type="text/javascript">
var initialData = #Html.Raw( new JavaScriptSerializer().Serialize(Model));
var viewModel = {
gifts: ko.observableArray(initialData)
};
$(document).ready(function () { ko.applyBindings(viewModel); });
</script>
This worked with knockout-1.2.1.js and jquery-1.5.1.js

Using xmlhttprequest in IE only includes the contents of the body tag

When I try to get the contents of a htm file into a div using a xmlhttprequest object in Firefox it includes everything, but in IE it only includes the contents of the body tag. In other words it ignores all the styling (in the head tag) of the page, rendering it ugly.
Is it possible to get the full page when using xmlhttprequest in internet explorer?
edit:
document.getElementById('divtoreceivetheresponse').innerHTML = xmlHTTP.responseText
This line in FF gets the page contents including the <head></head> section.
In IE it just gets the contents inside the <body></body> section.
I got an answer from elsewhere. Basically it does include all the page (not just the body) but IE chooses not to render it (probably the correct behavour)
I therefore worked out some code to extract the css, place it in the head, and place the body stuff in the target div. So both html and css from the external page would be got.
<html><head>
<script type="text/javascript" language="javascript">
function include(lyr,url)
{
if (document.all)
{
try {
var xml = new ActiveXObject("Microsoft.XMLHTTP");
xml.Open( "GET", url, false );
xml.Send()
}
catch (e) {
var xml = new ActiveXObject("MSXML2.XMLHTTP.4.0");
xml.Open( "GET", url, false );
xml.Send()
}
}
else
{
var xml=new XMLHttpRequest();
xml.open("GET",url,false);
xml.send(null);
}
text = xml.responseText;
text = text.replace("<html>","");
text = text.replace("</html>","");
text = text.replace("<head>","");
text = text.replace("</head>","");
text = text.replace("<body>","");
text = text.replace("</body>","");
splittext = text.split("<style type=\"text/css\">");
splittext = splittext[1].split("</style>");
css = splittext[0];
everythingelse = splittext[1];
addCss(css);
document.getElementById(lyr).innerHTML=everythingelse;
}
function addCss(cssCode) {
var styleElement = document.createElement("style");
styleElement.type = "text/css";
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = cssCode;
} else {
styleElement.appendChild(document.createTextNode(cssCode));
}
document.getElementsByTagName("head")[0].appendChild(styleElement);
}
</script>
</head>
<body onload="include('adiv','test.htm')">
<div id="adiv">sdfgboui hsdguhwruh o ikuy </div>
</body>
</html>
The code is far from perfect, but it does the job and I will probably improve the code bit by bit now that I know it works

Resources