Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Monday, February 23, 2015

Javascript Namespaces

Google "namespace" and "javascript" and you'll get a lot of different approaches to the solution, since vanilla Javascript doesn't provide out of the box namespaces.  Here's how jQuery and others do it.  If you want the quick answers, you can skip the link and just copy paste from below. The solution is to create an anonymous function and call it immediately, associating it with the Javascript window object.

A few notes from me:


  1. My library doesn't load correctly.

    My library has some pre-reqs; the easiest solution was to wrap the declaration in jQuery's $().ready().  See below.  There are other better solutions for Javascript dependency management, but they weren't necessary.
  2. This is great, but underscore templating doesn't work INSIDE the namespace?  Ahh!?! What do I do?

    Well, here's the key parts of the sample solution.  Note that the function definition has three arguments.  The first is the namespace itself, then a $, then undefined.  The first argument's purpose is obvious, the last is a Javascript technicality; just include it.  You can add additional arguments in the middle. Note the call to the "namespace" function on the last line passes in jQuery for argument two, which maps jQuery to $.

    (function( skillet, $, undefined ) {
       //stuff
    }( window.skillet = window.skillet || {}, jQuery ));

    So if you want to use jQuery AND underscore, or any library for that matter, you'll have to add arguments to the definition and function call.  For openbrewery, the namespace declaration looks like this, defining and passing both $/jQuery and _/underscore:
    $().ready(function() {
       (function( openbrewery, $, _, undefined ) {
          //Stuff
       }( window.openbrewery = window.openbrewery || {}, jQuery, _ ));
    });


Tuesday, March 25, 2014

JSON REST Webservice Error Responses

Over the years I've seen many formats for error responses from JSON formatted REST webservices.  Well, there's a draft standard.

The quick answer is:

Error Response

In the event of an error, a 4xx or 5xx HTTP status code SHOULD BE expressed in the response, with an entity body containing an error object adhering to the following structure: { "error": number, "reason": string, "detail": string }

Thursday, June 28, 2012

Cross Site Scripting PHP Proxy

I needed to access a REST web service from jQuery, but Chrome would throw an error during the ajax call due to the "origin" policy.  It's possible to setup a CORS filter with Tomcat and Apache, but that sounded like a lot of work.

Instead, if you can use PHP, just download the following PHP proxy:
https://github.com/developerforce/Force.com-JavaScript-REST-Toolkit/blob/master/proxy.php

Two changes are needed:

  1. Edit line 176 such that it reads  $url_query_param = 'url';
  2. Either fix the regexp at lines 172 and 173 which checks that the call is to sales force.com (set it to match your website) or  comment out lines 206 to 212 (potentially dangerous).
Now your $.ajax call needs to be modified so that the target url is part of the url.  Everything else is seamless.  See below.

 
 var req = $.ajax({
    type: 'GET',
    contentType: 'application/json',
    mimeType: 'application/json',
    url: 'http://proxy-server/app/proxy.php?mode=native&url=http://api-server/api/object/'+$("#objectID").val(),
    dataType: 'json',
    success: function(data, textStatus, jqXHR) {
 alert("Got data successfully");
 $('#responseData').text(JSON.stringify(data));
 },
    error: function(xhr, textStatus, error) {
 alert("Error: " + textStatus);
 } 
  });
That's it!

Monday, February 07, 2011

Google Chrome Keeps Caching Code

Google Chrome is nice for mobile apps because it has decent developer tools and can render webkit css properties (otherwise, Firefox has better debugging facilities).

What is maddening is that Chrome randomly seems to cache pages regardless of header settings. During development, pages are updated very often-- making debugging in Chrome supremely frustrating. I've only found two solutions:
  1. Reboot
  2. Append a dummy variable to the page URL (for example, myapp.com/index.php?google_sucks=1

JSLint

Lint is a tool which finds common errors in Java code. It's very handy and is usually able to find *something* you ought to fix. Well, there's a JSLint for Javascript too!
Note, it will complain about globals (like alert). You can, at the top of your javascript, put a comment and define a comma delimited list of globals to ignore:
/*global alert, console, $, $$ */

Tuesday, December 23, 2008

IE6 Quirks When Sizing HTML Elements

IE6 rolls with another party foul at the HTML kegger.

You can set the height and width of elements in Mozilla browsers to be 100%, or some percentage thereof.

Guess what.

In IE6 these elements will not appear. It doesn't seem to be enough to then use JavaScript to set the element width and height to a fixed value. They've got to start fixed.

IE6 actually allows a percentage width, but the height had better start out absolute or your element will just disappear-- in fact it will have a height of 0px, no matter what the IE debugger tells you.

IE Bug - Dynamically Created Elements Have No Name

IE fails to set the name of elements generated using createElement correctly:
http://www.easy-reader.net/archives/2005/09/02/death-to-bad-dom-implementations/

The solution is to butcher createElement and use it like createElement(""); but this doesn't work in sensible browsers.

Dynamically Adding Styles via JavaScript

This one is straight forward but then IE has to go and spoil the party. The idea is to create a style element and then append a text node containing your style information to it; then append the style element to the head of the page. Trouble is, IE blows up when you try to run createElement("style"). So you have to use MS' proprietary function. I won't bore you more, here is the code (replace YOURCSSTEXT):
var ss = null;
if(document.createStyleSheet) // IE
{
ss = document.createStyleSheet();
ss.cssText=YOURCSSTEXT;
} else { // All other browsers
ss = document.createElement("style");
ss.type="text/css"; ss.appendChild(document.createTextNode(YOURCSSTEXT));
document.getElementsByTagName("head")[0].appendChild(ss);
}

Friday, December 19, 2008

Parsing a Document into a DomDocument in JavaScript

XMLHttpRequest includes an attribute called responseXML besides responseText which should be populated when the returned data is XML. But actually often this doesn't work right because the headers are set right. Found this post by Darko in Google Groups about how to force parsing:

http://groups.google.com/group/comp.lang.javascript/browse_thread/thread/762990f37ae218a3/6e0d948e1820bf24?pli=1

I called this in my "showResponse" function called by prototype.js' Ajax.Request onSuccess event. showResponse(originalRequest) receives the original XMLHttpRequest object and you need to call Darko's code using originalRequest.

However of course it didn't work for me-- in Firefox, the script runs forever. Turns out there was actually an error parsing the doc, but there's no way to tell what it is.

Time to add error output, which is defined nicely here:
http://www.faqts.com/knowledge_base/entry/versions/index.phtml?aid=15302

Haven't finished this yet :)

Thursday, December 18, 2008

Passing Arguments to Prototype.js' onSuccess

Ready to have your head spin? Most of the prototype.js examples define the function that will handle onSuccess as an anonymous function, that is, it has no name as is defined inline. Like so:
var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: paramstring,
onSuccess: function(transport) {$('myhtmlelement').innerHTML=transport.responseText;}
});


That code would find the element with name 'myhtmlelement' and set its contents to the page returned by url. That's great, but what if you want to pass in some values from wherever you are creating the Ajax Request?

For example, I created a prototype constructor for a class. Part of its job is dynamically creating a div that I want to stuff with responseText.

var divObj = document.createElement( "DIV" ); 
document.body.appendChild(divObj);


So then I tried to access divObj from inside the anonymous function. Guess what, all the attributes are null or undefined. Hmm. I tried all sorts of combos of stuff but no go. Finally I hit on something works.

var divObj = document.createElement( "DIV" ); 
document.body.appendChild(divObj);
divObj.name='foo';
var name=divObj.name;


Then I created an anonymous function and stuff it in a variable.

this.showResponse = function(transport) { $(name).innerHTML = transport.responseText;};


Prototype's $() function is a shortcut for document.getElementById(). Got that so far? Now just create the Ajax request.

var myAjax = new Ajax.Request(
url,
{
method: 'get',
parameters: paramstring,
onSuccess: this.showResponse
});


And go figure, that works. For some reason accessing an object in the anonymous function doesn't work, but a simple string does.

Wednesday, December 17, 2008

IE Bug - Dynamically Created IFrames have No Name

IE has an annoying bug that when you use JavaScript to create an IFrame (or, as Jeff Norton points out in the comments, ANY element!), you can't set the name using .name or setAttribute. It just doesn't work.

I had tried to submit a form and set the target to the IFrame, and a new window popped open. WTF?

Solution is here:
http://terminalapp.net/submitting-a-form-with-target-set-to-a-script-generated-iframe-on-ie/

So instead of document.createElement("IFRAME"); do document.createElement("<iframe name="'blah'">"); and catch the exception on good browsers.

Tuesday, December 16, 2008

Browser Development Tools

Firefox
  • Venkman - JavaScript debugger. Bit of a head scratcher at first-- you need to navigate to your source, set a breakpoint, and then load the page in FireFox. Execution will stop when the breakpoint is reached (note this means you also can't look up other webpages will debugging)
  • DOM Inspector - allows you to navigate the DOM of a page loaded in Firefox. Just press Ctrl-Shift-I to load the Inspector
  • Developer Toolbar - really handy tool bar that outlines elements and shows all sorts of other handy info; also allows editing of source and CSS in real time
Interner Explorer
  • Script debugger - IE6 only - very buggy debugger. Crashes often. But it's the only way to see into IE's crazy mind.
  • Fiddler and Fiddler 2 - plug-in that intercepts communications between IE and sites and logs it. You can inspect all sorts of data and edit it. I found Fiddler to be more stable, but Fiddler 2 has some limited support for HTTPS.
  • IE Developer Toolbar - IE6 only - kind of like the DOM inspector for Firefox but in a toolbar

Monday, November 03, 2008

More CSS Styling

the format for styling elements is

element.class { property: value; property: value /* comment */ }

either element or class can be blank, but one of them has to be present, and if class is missing omit the period. this applies the properties and values you list inside the curly braces to all HTML elements which have class attribute set equal to the class you put after the period (if class is omitted, then it applies to all elements of that type).

For example

tr.poo { ... }

applies to all table rows which have class="poo" attribute on them.

tr { ... }

applies to all table rows, regardless of the class you set. Many CSS stylesheets you inherit style all elements of a certain type. You should be able to override the default (you probably don't want to screw with the default because it will screw up the rest of the stylesheet) by creating your own classes of elements.

There's one other variation on the element.class { .. } which is you can use a pound sign (#)

element.class#id { .. }

(you can even omit element.class and just have #id)

This applies the style to just elements with an attribute id equal to the name you put after the # sign

so tr id="fun" ... /tr (sorry I can't put the greater than or less than since it will be interpreted as html) could be styled with #fun { color: #775544 }

Look up w3schools on google to get a list of all the css properties. Common ones I use are:
font-size, font-face, font (this one combines all the font-... properties into one, the syntax is hard to remember though), padding (sets padding around a whole box), padding-left, padding-right..., margin, border (border: Xpx linestyle color), color (sets foreground text color format is hexadecimal #rrggbb), background-color and background (the one gotcha with background is if you want a background image, use the function url(...) but don't enclose the argument to url in quotes), width, height

if you want to understand padding, margin and border look up css box model. I believe padding is the space between the border and content inside a box; margin the area between the border and any neighboring content; border is just like word, you can set the thickness and dashed, solid, etc.

One other thing different from old school html is DIV and SPAN elements; a DIV is a box that can contain anything, a SPAN is an inline element, meaning its primarily intended for styling sections of text (like if you wanted to make the first few words of a paragraph bigger span style="font-size:20pt; color:grey" In the beginning /span there was nothing, OR, another handy one is to put an indent in a paragraph, use a span with a padding-left of like 15px that contains just some whitespace); a lot of the properties don't apply to SPAN. My products template mostly uses tables though because they are a lot easier to work with but I think the spans are really handy.

That's pretty much all I know. you can access the CSS properties using JavaScript via document.getElementById('
idofyourelement').style.propertyname

Tuesday, June 03, 2008

Javascript Regular Expression to match a comma delimited list

This example uses the JavaScript String's match() method to parse a comma delimited list into a JavaScript array.


<html>
<head>
<script>
var str = "completeurl, debug, foo";

var m = str.match(/\w+(,\w+)*/g);

var count = m.length; // the count

function parseit() {
document.getElementById("_output").innerHTML="Total length:"+m.length+" ";
for(var i = 0; i < m.length; i++) {
document.getElementById("_output").innerHTML+="Token:\'"+m[i]+"\' ";
}
}
</script>
</head>
</html>
<body onload="parseit();">
<div id="_output" name="_output" style="border:1px solid black"> </div>
</body>
</html>

Monday, May 19, 2008

Dynamically Resize an IFrame in Firefox AND IE

So this is a big mystery out there on the net. There are a ton of silly solutions that half work. This one works for me on IE 6 & 7 and Firefox 2.x. I haven't tried it on anything else. Firefox actually accomplishes all this easily; just set the height of the IFrame to 100%. IE, on the other hand, won't behave. The IFrame needs to be inside a table, and sized to 100% to fill the table. Then you have to alter the size of the table. This doesn't work in FireFox though.


/* Dynamic Resizer v1.1 by Peter Vieth
Resizes iframe(s) to be the same size as their content by attaching onload events for each browser
ATTACH THE FOLLOWING EVENT TO YOUR IFRAME (here called reportIFrame) */
if(window.addEventListener) // Mozilla, FF, NS
reportIFrame.addEventListener('load', resizeEvent, false) ;
else // IE
reportIFrame.attachEvent('onreadystatechange', resizeEvent );

/* Bug fix for IE (added v1.1): IFrames created by JavaScript don't actually have a "name" in IE's internals */
if(document.all) {
if(self.frames[reportIFrame.id].name!=reportIFrame.name)
self.frames[reportIFrame.id].name = reportIFrame.name;
}

/* HERE IS THE EVENT DEFINITION */

function resizeEvent(evt) {
var ieKey = "srcElement";
var mozKey = "currentTarget";
var IFrameObj;
evt[mozKey] ? IFrameObj = evt[mozKey] : IFrameObj = evt[ieKey];
fitIframe(IFrameObj);
}

/* THIS FUNCTION FITS THE IFRAME TO DOCUMENT SIZE */

function fitIframe(IFrameObj) {
var IFrameDoc;
if (IFrameObj.contentDocument) {
// For NS6
IFrameDoc = IFrameObj.contentDocument;
IFrameObj.style.height=(parseInt(IFrameDoc.height)+50)+"px";
//alert('detected NS6');
} else if (IFrameObj.contentWindow) {
// For IE5.5 and IE6
IFrameDoc = IFrameObj.contentWindow.document;
if(IFrameDoc.body!=null) { // the IE event fires too often, and fires before IFrame is loaded, in which case doc==null. It fires AGAIN once it loads fully, so ignore the first time
try {
var table = document.getElementById(IFrameObj.parentName);
} catch (e) { alert('IE5.5+: Unable to located IFrames parent table: '+IFrameObj.parentName ); }
try {
var height=parseInt(IFrameDoc.body.clientHeight)+20;
table.style.height=height;
} catch (e) { alert('IE5.5+: Unable to get size of IFrame: '+IFrameObj.name ); }
} // if IFrameDoc!=null

} else if (IFrameObj.document) {
// For IE5
IFrameDoc = IFrameObj.document;
try {
document.getElementById(IFrameObj.parentName).style.height=IFrameDoc.body.scrollHeight-IFrameDoc.body.offsetHeight;
} catch (e) { alert('IE 5.0: Unable to located IFrames parent table or get size of IFrame: '+IFrameObj.parentName ); }

} else {
alert('fitIframe was unable to detect the browser version');
return true;
}
}

Attach an OnLoad event in FireFox and IE using JavaScript

IE uses the function attachEvent while FireFox uses addEventListener. IE calls the event onload, while Firefox calls it load. Your function can be called anything.


if(document.all)
window.attachEvent('onload',Yourfunction);
else
window.addEventListener("load",Yourfunction,false);

Friday, March 02, 2007

Different Return types from AJAX calls

When you create an XMLHTTPREQUEST object, the ResponseText can contain just about anything. In Ajaxifying old apps and widgets, I find myself dealing with two situations:

1) Output is just plain HTML

This is easy to deal with. You can just update the innerHTML of a DIV to the ResponseText.

2) Output is mixed HTML and JavaScript

This is trickier. You can run the JavaScript function eval on output that is pure JavaScript. If it's mixed, I use JavaScript to create a String that stores the HTML output I want. Then you can update the innerHTML of a DIV to be eval(ReponseText).

Also, a Caveat:

A page may fail to load. It is possible to get the return code of a page from XMLHTTPRequest, BUT, if you catch errors in your page, the page will load 'successfully' though with errors. What I've done is to print the error out in the page, and then when updating my DIV, I do ResponseText.search('ERROR'). If the result is -1, the word ERROR was not found in the text. Of course you can get more specific about the type of error...

Thursday, December 14, 2006

Using innerHTML with Ajax - How Can I make JavaScript work?

JavaScript inside

script
tags does not work it is inserted in the body of an object using innerHTML.


If you set the innerHTML of a Div or other object to contain

script
tags, you must use the defer attribute and set it to true.



MSDN link here

Wednesday, July 05, 2006

Redirecting a User's Browser without Creating History

When writing web applications, it is sometimes desireable and/or necessary to redirect the user without creating history in the browser. This prevents the user from hitting the back button and ending up at a page. For example, when a form I have created submits to a JSP that processes the form and outputs status messages, the user is forwarded onwards after the processing is complete. If they press back, they would end up at the JSP that outputted the status messages, which is not the behavior the user would likely expect. If they hit back, they want to go back and edit something and hit save again.

Another example is changing, say, details of a user account. When the page is saved, a common task would be to submit the form to a servlet or JSP, then redirect back to the page. We don't want the user to hit back and reach an out of date page.

This can be done via javascript using location.replace and in Mozilla/Firefox with location.href. These change the URL in address bar and load the page specified, but without creating history. Changing location alone creates history. In the example below, ${navigateTo} stores the location to forward the user to.


if (document.images) // check for IE
location.replace('&{navigateTo}');
else // Mozilla, Firefox
location.href='&{navigateTo}';


And to give time for the user to see the output before forwarding them:


if (document.images)
window.setTimeout("location.replace('&{navigateTo}')","5000");
else
window.setTimeout("location.href='&{navigateTo}"',"5000");

Redirecting a User's Browser without Creating History

When writing web applications, it is sometimes desireable and/or necessary to redirect the user without creating history in the browser. This prevents the user from hitting the back button and ending up at a page. For example, when a form I have created submits to a JSP that processes the form and outputs status messages, the user is forwarded onwards after the processing is complete. If they press back, they would end up at the JSP that outputted the status messages, which is not the behavior the user would likely expect. If they hit back, they want to go back and edit something and hit save again.

Another example is changing, say, details of a user account. When the page is saved, a common task would be to submit the form to a servlet or JSP, then redirect back to the page. We don't want the user to hit back and reach an out of date page.

This can be done via javascript using location.replace and in Mozilla/Firefox with location.href. These change the URL in address bar and load the page specified, but without creating history. Changing location alone creates history. In the example below, ${navigateTo} stores the location to forward the user to.


if (document.images) // check for IE
location.replace('&{navigateTo}');
else // Mozilla, Firefox
location.href='&{navigateTo}';


And to give time for the user to see the output before forwarding them:


if (document.images)
window.setTimeout("location.replace('&{navigateTo}')","5000");
else
window.setTimeout("location.href='&{navigateTo}"',"5000");

Labels

Blog Archive

Contributors