Overview The qbo.ApplicationWeb was extended in late 2010 to optimize page load times. Current skins (including the standard skin) leverage these techniques (described below), but have a few gotchas associated with them. The purpose of this post is to help troubleshoot and avoid these gotchas. The gotchas are at the bottom of the post, but I strongly recommend developers read the entire post to understand what's going on. JavaScript and CSS Caching To minimize the number of 304 calls to the server, qbo.ApplicationWeb offers the option of serving up all javascript or css in a single hit:
More importantly, this web service tells the browser to cache these files for 24 hours. After receiving the results of these web service calls, the browser will stop making these call (no more 304s) for 24 hours. This noticeably speeds page load time. Main Menu Each page draw that includes a site's main menu includes a lot of HTML to handle the drop-down menu under each main menu item. In fact, on the average page, the majority of HTML streamed to the browser is just main menu related content. Rather than streaming this content to the browser on every page draw, we can now load this content via JSON, and more importantly, cache that JSON on the browser so this content is loaded once per day. This decreases our average page size by about 50%. To execute this technique, the are a few components that come into play:
When the page is rendered on the browser, each page that contains a main menu (e.g. has the skin rendered) contains a lines like these, from {skin}.SiteStructure.xslt: <script type="text/javascript" src="/Application/SkinService.asmx/Javascript"></script> ... <script type="text/javascript">qbo.UserID = '056';</script> ... <script type="text/javascript">window.addEvent('domready', LoadMainMenu);</script> Within the JavaScript cached by the page will be these functions: // This will tell the browser to get the main menu JSON; if it's cached, the browser will just use it from cache function LoadMainMenu() { var id = (qbo && qbo.UserID) ? qbo.UserID : 0; new Request.JSON({ url: '/Application/SkinService.asmx/MainMenu?' + id, method: 'get', secure: false, data: {}, onSuccess: RenderMainMenu }).send(); } // This will take the JSON returned, and render drop-down menus for each menu item function RenderMainMenu(json, text) { if ((json.MenuCollection == null) || (json.MenuCollection.MenuItem == null)) return; var mi = $splat(json.MenuCollection.MenuItem); mi.each(function(m){ var c = new qbo.ContextMenu(m.Target, {event: 'leftClick', position: 'left bottom'}); m.MenuOption.each(function(i){ c.addItem({label: i.Label, href: i.Url}); }); }); } The JSON served up by /Application/SkinService.asmx/MainMenu is something like this: { "MenuCollection": { "modules": 12, "qboWeb": "http://qbo.web.quandis.com/", "MenuItem": [ { "Target": "MenuItem_ContactModule", "MenuOption": [ { "Url": "/Contact/OrganizationSearch.aspx", "Title": "", "Label": "Organizations" }, { "Url": "/Contact/Broker/BrokerSearch.aspx", "Title": "", "Label": "Brokers" }, ... ] }, { "Target": "MenuItem_WorklistModule", "MenuOption": [ { "Url": "/Decision/SmartWorklistAssignByPerson.aspx?Action=Assign", "Title": "Click here to navigate to your next Smart Worklist item.", "Label": "Next Work Item" }, ... ] } ] } } Gotcha #1: 'this.trigger' is undefined JavaScript error The drop-down (or 'context') menus under each Main Menu item is drawn by JavaScript, specifically the qbo.ContextMenu class. The menu should show up when you click on a Main Menu item, or 'trigger'. Note in the JSON above that each object in the MenuItem array contains a 'Target' property. This should be a unique id of the HTML element that should be the trigger for the menu. If the JSON contains triggers that don't actually exist, the context menu will attempt to bind to an undefined element, and you have your error.
The fundamental cause for this is the browser cache of the main menu JSON is different than the main menu being rendered in the skin. This typically happens during development, when a developer modified the {skin}.SiteStructure.xml. Keep in mind that the main menu HTML is produced on every page draw by the server, and "popping web.config" will clear the server-side cache, but does nothing to the browser-side cache of the main menu JSON. Pressing F5 in the browser (or clicking the reload button) tells your browser to ignore items in the cache, and fetch them again from the server. This works like a charm -- expect in IE. We love IE. IE developers, in their infinite wisdom, treat the browser cache and the XMLHTTP cache differently. Note that we fetch the JSON via a call to the Request.JSON class. This class in turn uses an XMLHTTP object to fetch data (this is 'AJAX'). So pressing F5 in IE refreshes your HTML, Javascript, and CSS, but does not refresh anything fetched via XMLHTTP. Gotcha #2: 'qbo is undefined' JavaScript error (in development) This happens if the {skin}.SiteStructure.xml contains references to javascript files that don't actually exist. For example, when creating a skin by copying and pasting from other skins, you may inadvertently reference a JavaScript file that is not on your installation, such as qbo.Service.js or qbo.SkipTrace.js. You can quickly see this issue by navigating to /Application/SkinService.asmx/Javascript: you will see an error returned.
Gotcha #3: 'qbo is undefined' JavaScript error (in production) On rare occasion, /Application/SkinService.asmx/Javascript will ignore all extra JavaScript files referenced in {skin}.SiteStructure.xml. We do not yet know why this happens, but are researching is. Fortunately, the "fix" is easy.
|
Configuration >