Monday, June 7, 2010

node.setAttributeNS(namespaceURI, qualifiedName, value)

When trying to implement this missing method in MSXML,
several interesing
inconsistencies in other browsers apeared,
all claim the native support for this method.

Pseudopcode:

set("ns1","a:a","1")
old=getAttributeWithXPath
set("ns1","b:a","2")
new=getAttributeWithXPath
print compare pointers
print new.nodeName
print new.value
print serialized xml


MSXML 6.0

result:false
p2:a
2
xmlns:p2="ns" p2:a="2"


Firefox/3.5.6

result:true
p1:a
2
p2:a="2" xmlns:p2="ns"

Safari/531.22.7

result:true
p1:a
1
p1:a="2" xmlns:p1="ns"


Chrome/5.0.375.55

result:true
p1:a
2
p1:a="2" xmlns:p1="ns"

Of course there is always an excuse:
http://www.w3.org/TR/DOM-Level-2-Core/core.html
Note: DOM Level 1 methods are namespace ignorant. Therefore, while it is safe to use these methods when not dealing with namespaces, using them and the new ones at the same time should be avoided. DOM Level 1 methods solely identify attribute nodes by their nodeName. On the contrary, the DOM Level 2 methods related to namespaces, identify attribute nodes by their namespaceURI and localName. Because of this fundamental difference, mixing both sets of methods can lead to unpredictable results. In particular, using setAttributeNS, an element may have two attributes (or more) that have the same nodeName, but different namespaceURIs. Calling getAttribute with that nodeName could then return any of those attributes. The result depends on the implementation. Similarly, using setAttributeNode, one can set two attributes (or more) that have different nodeNames but the same prefix and namespaceURI. In this case getAttributeNodeNS will return either attribute, in an implementation dependent manner. The only guarantee in such cases is that all methods that access a named item by its nodeName will access the same item, and all methods which access a node by its URI and local name will access the same node. For instance, setAttribute and setAttributeNS affect the node that getAttribute and getAttributeNS, respectively, return.

Friday, May 7, 2010

getAttribute("href",MAGIC_FLAG)

I have notice the cross-browser difference on
getAttribute("href"), value.href
long, long time ago,
but I hade no reasonable explanation nor workaround ;-(

Of course jQuery people already knew ;-)
// Check to see if an attribute returns normalized href attributes
div.innerHTML = "";
if (div.firstChild && typeof div.firstChild.getAttribute !== "undefined" &&
div.firstChild.getAttribute("href") !== "#") {
Expr.attrHandle.href = function(elem) {
return elem.getAttribute("href", 2);
};
}
I have missed the RTFM step ?

http://msdn.microsoft.com/en-us/library/ms536429(VS.85).aspx

Thursday, May 6, 2010

Safari crops all (maxLength=5 and 123456)

http://www.w3.org/TR/html401/interact/forms.html#adef-maxlength
this attribute specifies the maximum number of characters the user may enter.
All tested browsers (MSIE, FF, Opera, Chrome, Safari) follow this line. However all except safari are too precise and allow user to enter 5 chars maximum, but server markup and client code can fill whatever value. Safari forces all (server markup, client script and user) to obey 5, too long string "123456" received from server markup input type text="123456" set by client code i.value="123456"; i.setAttribute("value","123456") or typed by user will always end up CROPPED as 12345. All others will show overflowed "123456" (even Chrome ;-)).

ViewLocationFormats (just code hint)

To use standard engine but searching in modified (extended) list of locations: protected void Application_Start() { ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new WebFormViewEngine() { ViewLocationFormats = new[] { "~/MYEXTRALOCATION/Views/{1}/{0}/Form.aspx", "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx", "~/Views/Shared/{0}.ascx" }, }); RegisterRoutes(RouteTable.Routes); }

Thursday, April 29, 2010

input.value vs. input.getAttribute("value")

Just quick obervation:

HTML comes to client with server side value
"input value='orig'.
Now let's dump
i.value and i.getAttribute("value")
in window.onload handler.

results:
MSIE 7.0: orig, orig
FF: 3.5.6: orig, orig
as expected both values reflect the data sent from server inside value attribute.

Now, change value by typing to "new" text.
Click refresh (or navigate away and back).

You should read "new" in the field (if browser remembers).
All fine:

Now look at the dump from onload handler:

MSIE 7.0: new, new
FF: new, orig

In msie the original HTML markup value is not accessible (lost ?)
by getAttribute after return to the page.

TODO: test the others, find explanation

Thursday, April 15, 2010

WebFormViewEngine - how the MVC finds "The View"

Simplified pseudocode: if(useCache) return ViewLocationCache.GetViewLocation(cacheKey) if(IsSpecificPath) //"~" or "/" VirtualPathProvider.FileExists(name); //viewName else if(usingAreas) locations=AreaLocationFormats+LocationFormats else locations=LocationFormats GetPathFromGeneralName(name, controllerName, areaName ,locations) string virtualPath = location.Format(name, controllerName, areaName); VirtualPathProvider.FileExists(virtualPath); So it uses name directly as VirualPath, or tries each virtual path in locations (with or without area specific first) and than tries each. If in cahing mode, returns from cache based on cacheKey. Formats: //{0} - name (viewName), not staring with ~ or / //{1} - controllerName, ControllerContext.RouteData.GetRequiredString("controller"); //{2} - areaName , AreaHelpers.GetAreaName(controllerContext.RouteData); WebFormViewEngine: MasterLocationFormats = new[] { "~/Views/{1}/{0}.master", "~/Views/Shared/{0}.master" }; AreaMasterLocationFormats = new[] { "~/Areas/{2}/Views/{1}/{0}.master", "~/Areas/{2}/Views/Shared/{0}.master", }; ViewLocationFormats = new[] { "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx", "~/Views/Shared/{0}.ascx" }; AreaViewLocationFormats = new[] { "~/Areas/{2}/Views/{1}/{0}.aspx", "~/Areas/{2}/Views/{1}/{0}.ascx", "~/Areas/{2}/Views/Shared/{0}.aspx", "~/Areas/{2}/Views/Shared/{0}.ascx", }; PartialViewLocationFormats = ViewLocationFormats; AreaPartialViewLocationFormats = AreaViewLocationFormats; // format is ":ViewCacheEntry:{cacheType}:{prefix}:{name}:{controllerName}:{areaName}:" private const string _cacheKeyFormat = ":ViewCacheEntry:{0}:{1}:{2}:{3}:{4}:"; See MVC source code. P.S. It would be nice to append this inside some poster ;-) Any better explanation links are welcomed.

Wednesday, April 7, 2010

XHR.onreadystatechange and exceptions

Generally it is not good idea to throw exception in event handler.
However people are lazy and bugs happen, so let's see out chances in this situation.

xhr.onreadystatechange=function(){throw new Error();}

MSIE and FF supports window.onerror event, so uncought exceptions can end up in
this global handler.

All browsers support some sort of "display JavaScript errors" but usually well hidden
as small icon on status bar (MSIE) or deeply in menus (other browsers).

Uniform handling is almost impossible. The very first idea was to rely on
window.error in MSIE an FF and call window.onerror explicitly in
other browsers (even if the browser does not support this error you can define

window.onerror=function...
and call it using window.onerror(msg,..,...) syntax.

However situation is even worse.

  1. FF 3.5.6 works fine, ewrror thrown, ends in window.onerror as expected.
  2. MSIE 7.0 NativeXHR + 200 response - works fine
  3. MSIE 7.0 NativeXHR + conditional request + 304 response - exception lost, window.onerror not called
  4. MSIE 7.0 NativeXHR + cached version not tested byt expected - exception lost, window.onerror not called
  5. FF 3.6 exception lost, window.onerror not called
So it seems that we cannot rely:
  1. exception being thrown out of boundaries of the handler (eaten exception)
  2. even if thrown to be catched somewhere (missing window.onerror concept)
P.S. tested in async true scenarios, async false can reveal more troubles....