The architecture is described in the following section.
Client-Server Interaction
The product details page was designed to minimize the number of round trips to the server. All information pertaining to a given product such as prices and features of the product’s child SKUs, is loaded immediately with the rest of the page. Subsequent round trips to the server require the user’s input and as such cannot be further optimized, for example, adding an item to the shopping cart.
Product Configuration Data
All data associated with a product’s child SKUs is rendered by /mobile/browse/json/getSkuJSON.jsp
. This data is then processed during the jQuery ‘ready’ event, and transformed into event handlers that close over the SKU data and DOM elements that will be modified as the user makes their selections. The resulting functions are highly optimized, as any calculations that do not depend on the execution context have been abstracted to the ‘ready’ event and bound in local scope. The following illustration shows the same product while the user is selecting a size.
Selecting a Size
Page Hierarchy
The user arrives at the product details page by clicking a link to a product. When such a link is generated, it points to one of four template pages:
productDetailColorSizePicker.jsp:
for products with color and size propertiesproductDetailSingleSku.jsp:
for products with only a single SKUproductDetailMultiSku.jsp:
for products with multiple unique SKUsproductDetailWoodFinishPicker.jsp:
for products with the “wood finish” property
Each of these template pages is responsible for deriving an appropriate set of parameters that are passed to productDetail.jsp
and used to render the page:
product
: the product being viewed (required)picker
: the appropriate picker for the product (required – see section “Pickers – JSP”)selectedSku
: the currently selected SKUselectedQty
: the currently selected quantityselectedColor
: the currently selected colorselectedSize
: the currently selected sizeavailableSizes
: all available sizes for the productavailableColors
: all available colors for the productoneSize
: true if the product has exactly one sizeoneColor
: true if the product has exactly one colorciId
: the commerce item being edited
The only required parameters are product and picker; the rest may be derived depending on what is appropriate for the given product. For example, productDetailColorSizePicker.jsp
derives all of the parameters listed above, whereas productDetailMultiSku.jsp
only derives product
, picker
, selectedSku
, selectedQty
, and ciId
, as those are the only parameters that pertain to multi-SKU products. Additional template pages and their required parameters could be easily added here to customize or modify CRS-M’s product details page to your specifications.
Once the correct parameters have been passed to productDetail.jsp
, it utilizes the mobilePageContainer tag
(see “Common Elements”) to include the SKU data (/mobile/browse/json/getSkuJSON.jsp
), page content (/mobile/browse/productDetailsContainer.jsp)
, out-of-stock notification form (/mobile/browse/gadgets/emailMeForm.jsp),
related items slider (/mobile/global/gadgets/productsHorizontalList.jsp),
and—depending on the context—either the add-to-cart form (/mobile/browse/gadgets/addToCartForm.jsp)
or update cart form (/mobile/browse/gadgets/updateCartForm.jsp)
.
The following illustration shows the product details page displaying a single SKU item:
A Single SKU Product
Pickers - JSP
The term “pickers” is used within CRS-M to refer to the SKU selectors, that is the pickers that are seen on the product details page. In terms of page code, the term “pickers” refers to a JSP that can display those SKU selectors.
The picker parameter passed to productDetail.jsp
(see above) is a string representing the relative path of the JSP that should be used to render the pickers for the given product. Although this path can point to any JSP on the site, there are two picker JSPs included with CRS-M: colorSizePickers.jsp
and multiSkuPicker.jsp
. It is worth noting that there is not a one-to-one correspondence from product details template JSP to picker JSP as two of the template pages—wood finish and color/size—can use the same picker, and single-SKU products do not require any pickers.
Similarly to the product details template JSPs, each picker JSP is also a template. They each derive the appropriate parameters to then pass to the generalized pickerList.jsp
, which renders a generic picker. Currently, pickerList.jsp
accepts the following parameters:
collection
: the collection of picker items to rendervalueProperty
: the name of the item property that should be used as the picker ‘value’type
: a string used to identify this picker, which must correspond to exactly one of the values passed to ‘pickerSelectFunction
inproduct.
callback
: the JavaScript function to call when the picker value has changedid
: the DOM id of the pickerselectedValue
: the currently selected valuedisabled
: disables the pickerdefaultLabel
: the default label to display when no value has been selectedlabelProperty
: the name of the item property that should be use as the picker ‘label’. If not specified, thevalueProperty
is used.
Again, you can extend this to add additional picker JSPs and render modified or additional pickers for your purposes.
Pickers – HTML and CSS
The generated markup for the pickers is intentionally simple. An individual picker is of the following form:
<label for="${id}" …> <select id="${id}" …> <!-- Default option --> <option value="" label="${defaultLabel}" disabled/> <option value="…" label="…"/> … </select> </label>
It is worth noting that the select control is nested inside its own label. This was included primarily for accessibility considerations, as every form control must have an associated label.
CSS styles are applied to the select control to customize its appearance while utilizing the browser’s native <select>
element functionality. This greatly reduced the amount of work that would have been necessary to create a completely custom select control without sacrificing the desired functionality.
Pickers – JavaScript
As noted above, all functions necessary for picker functionality are created and bound when the page loads. These functions are members of the skuFunctions
object, which follows the JavaScript “module” pattern. The signature of the skuFunctions
“module” is as follows:
cartLinkClick
: Called when the “Add To Cart” button is clicked. This function either updates the cart or adds a new item to the cart, depending on the current context.emailMe
: Called when a SKU is out of stock. This function displays a modal dialog that offers to notify the user when the item is back in stock.emailMeSubmit
: Called when the form in the aforementioned modal dialog is submitted. This function executes an AJAX request that submits the form and depending on the content that the user has entered, either flags invalid fields or shows a confirmation dialog.outOfStock
: Called when an out-of-stock SKU is selected. This function updates the displayed price, the text on the “Add To Cart” button, and the hidden SKU id field in the aforementioned email notification form.colorSizePickerSelect, multiSkuPickerSelect, woodFinishPickerSelect
: These functions are called when a picker value has been updated. They all use the same module-local function, pickerSelectFunction, which updates the displayed price, checks the availability of the selected SKU, changes the text displayed on the “Add To Cart” button (if necessary), and sets the hidden SKU id field in the add-to-cart form. The only difference between these functions is a string that fixes which type of SKU to look for – color/size, multi-sku, or wood finish.quantitySelect
: This function is called when the value of the quantity picker has been updated. It updates the quantity field of the add-to-cart form and, if necessary, changes the text on the “Add To Cart” button.available, preorder, backorder
: These functions are used to generate appropriate function closures, which are then associated with a given SKU during the data-loading step described in the section “Product Configuration Data.”
Again, these functions can be modified or additional functions added in order to meet your requirements.
Paired Sites
This feature supports two-way connections between sites. For example, if a shopper entered the CRS Store’s desktop URL on their mobile device, they would be correctly re-directed to the mobile CRS Store site. If the shopper shared an item with a friend using the Email A Friend feature while on their mobile device, then the URL that is sent in the email should be pointing to the product on the CRS Store Desktop site rather than the mobile site. The paired sites mapping helps the shopper view the correct version for their device by allowing the application to know which URL to display in which situation.
The paired sites concept is used in CRS mobile for the MobileDetectionInterceptor
component as a way to find a corresponding mobile site by a known non-mobile Commerce Reference Store site and vice versa.
A site is identified as “full CRS” when the “channel” property is “desktop”. All other values are considered not to be “full CRS” identifiers. For example, a “channel” value of “mobile” is used to identify a mobile site.
The “channel” property is defined in the sites.xml
file.
The MobileDetectionInterceptor
uses the “paired sites” information and the site “channel” property value for redirection between mobile and non-mobile sites when a mobile user agent performs a request with non-mobile site URL or non-mobile (desktop) user agent requests a resource from a mobile site.
Site pairs are defined in the sites.xml
files for each “CRS mobile” submodule using special site groups with the crs.MobileSitePairs
shareable type. Each site group with the crs.MobileSitePairs
shareable type joins together a “full CRS” and corresponding mobile site, thus “pairing” the mobile and non-mobile sites.
For example, the CRS mobile sites.xml
file defines the following sites group:
<add-item item-descriptor="siteGroup" id="sitesUS"> <set-property name="displayName"><![CDATA[Sites (US)]]></set-property> <set-property name="sites"><![CDATA[storeSiteUS,mobileStoreSiteUS]]></set-property> <set-property name="shareableTypes"><![CDATA[crs.MobileSitePairs]]></set-property> </add-item>
In this example, the MobileDetectionInterceptor
component redirects a mobile user agent that requests the storeSiteUS
site to the mobileStoreSiteUS
site.